@homeflare/alchemy 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/litellm/budget-errors.d.ts +36 -0
- package/dist/litellm/budget-errors.d.ts.map +1 -0
- package/dist/litellm/budget-form.d.ts +50 -0
- package/dist/litellm/budget-form.d.ts.map +1 -0
- package/dist/litellm/budget-operations.d.ts +20 -0
- package/dist/litellm/budget-operations.d.ts.map +1 -0
- package/dist/litellm/budget.d.ts +61 -0
- package/dist/litellm/budget.d.ts.map +1 -0
- package/dist/litellm/fake-litellm.d.ts +5 -0
- package/dist/litellm/fake-litellm.d.ts.map +1 -1
- package/dist/litellm/index.d.ts +2 -0
- package/dist/litellm/index.d.ts.map +1 -1
- package/dist/litellm/index.js +125 -2
- package/dist/litellm/index.js.map +9 -5
- package/dist/litellm/operations.d.ts +22 -0
- package/dist/litellm/operations.d.ts.map +1 -1
- package/dist/litellm/providers.d.ts +1 -1
- package/dist/litellm/providers.d.ts.map +1 -1
- package/dist/openbao/auth-role-form.d.ts +9 -0
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role-wire.d.ts.map +1 -1
- package/dist/openbao/fake-engines-roles.d.ts.map +1 -1
- package/dist/openbao/index.js +9 -6
- package/dist/openbao/index.js.map +4 -4
- package/dist/postgres/connection.d.ts +20 -2
- package/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/database-sql.d.ts +1 -1
- package/dist/postgres/database-sql.d.ts.map +1 -1
- package/dist/postgres/database.d.ts +1 -1
- package/dist/postgres/database.d.ts.map +1 -1
- package/dist/postgres/index.d.ts +5 -3
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +124 -38
- package/dist/postgres/index.js.map +8 -7
- package/dist/postgres/providers.d.ts +4 -2
- package/dist/postgres/providers.d.ts.map +1 -1
- package/dist/postgres/psql-executor.d.ts +21 -0
- package/dist/postgres/psql-executor.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag-types.d.ts +57 -0
- package/dist/proxmox/ceph-flag-types.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag-wire.d.ts +77 -0
- package/dist/proxmox/ceph-flag-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag.d.ts +15 -50
- package/dist/proxmox/ceph-flag.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +10 -13
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/index.js +772 -740
- package/dist/proxmox/index.js.map +8 -7
- package/docs/litellm-budget.md +55 -0
- package/docs/litellm.md +7 -6
- package/docs/postgres.md +22 -0
- package/docs/proxmox-sdk-migration.md +45 -0
- package/package.json +3 -3
- package/src/litellm/budget-errors.ts +38 -0
- package/src/litellm/budget-form.ts +94 -0
- package/src/litellm/budget-operations.ts +51 -0
- package/src/litellm/budget.test.ts +105 -0
- package/src/litellm/budget.ts +127 -0
- package/src/litellm/fake-litellm.ts +50 -1
- package/src/litellm/index.ts +13 -0
- package/src/litellm/operations.ts +1 -1
- package/src/litellm/providers.ts +4 -1
- package/src/openbao/auth-role-form.test.ts +37 -0
- package/src/openbao/auth-role-form.ts +12 -1
- package/src/openbao/auth-role-wire.test.ts +1 -0
- package/src/openbao/auth-role-wire.ts +13 -1
- package/src/openbao/distilled-retry.test.ts +1 -0
- package/src/openbao/fake-engines-roles.ts +7 -1
- package/src/postgres/connection.ts +37 -3
- package/src/postgres/database-sql.ts +4 -3
- package/src/postgres/database.ts +3 -2
- package/src/postgres/index.ts +10 -3
- package/src/postgres/providers.ts +15 -2
- package/src/postgres/psql-executor.test.ts +106 -0
- package/src/postgres/psql-executor.ts +130 -0
- package/src/proxmox/ceph-flag-types.ts +70 -0
- package/src/proxmox/ceph-flag-wire.test.ts +72 -0
- package/src/proxmox/ceph-flag-wire.ts +123 -0
- package/src/proxmox/ceph-flag.ts +77 -130
- package/src/proxmox/ceph-osd-write.ts +10 -13
package/dist/proxmox/index.js
CHANGED
|
@@ -1745,143 +1745,57 @@ var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect
|
|
|
1745
1745
|
})));
|
|
1746
1746
|
// src/proxmox/ceph-flag.ts
|
|
1747
1747
|
import { Resource as Resource5 } from "alchemy";
|
|
1748
|
-
import * as Provider5 from "alchemy/Provider";
|
|
1749
|
-
import * as Effect16 from "effect/Effect";
|
|
1750
|
-
|
|
1751
|
-
// src/proxmox/resource.ts
|
|
1752
1748
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1749
|
+
import * as Provider5 from "alchemy/Provider";
|
|
1753
1750
|
import * as Effect15 from "effect/Effect";
|
|
1754
1751
|
|
|
1755
|
-
// src/proxmox/
|
|
1752
|
+
// src/proxmox/ceph-flag-wire.ts
|
|
1753
|
+
import * as cluster3 from "@distilled.cloud/proxmox/cluster";
|
|
1756
1754
|
import * as Effect14 from "effect/Effect";
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
method;
|
|
1762
|
-
path;
|
|
1763
|
-
constructor(status, method, path, detail) {
|
|
1764
|
-
super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
|
|
1765
|
-
this.status = status;
|
|
1766
|
-
this.method = method;
|
|
1767
|
-
this.path = path;
|
|
1768
|
-
this.name = "PveError";
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
|
|
1772
|
-
var encode = (form) => {
|
|
1773
|
-
const params = new URLSearchParams;
|
|
1774
|
-
for (const [key, value] of Object.entries(form)) {
|
|
1775
|
-
if (typeof value === "string")
|
|
1776
|
-
params.append(key, value);
|
|
1777
|
-
else
|
|
1778
|
-
for (const item of value)
|
|
1779
|
-
params.append(key, item);
|
|
1780
|
-
}
|
|
1781
|
-
return params.toString();
|
|
1782
|
-
};
|
|
1783
|
-
var buildRequest = (method, apiBase, path, credential, target, form) => {
|
|
1784
|
-
const url = `${apiBase}/${path}`;
|
|
1785
|
-
return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
|
|
1786
|
-
};
|
|
1787
|
-
var executeOne = (target, credential, method, path, form, apiBase) => Effect14.gen(function* () {
|
|
1788
|
-
const client = yield* HttpClient5.HttpClient;
|
|
1789
|
-
const request = buildRequest(method, apiBase, path, credential, target, form);
|
|
1790
|
-
return yield* client.execute(request).pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1791
|
-
});
|
|
1792
|
-
var readResponse = (response, method, path) => Effect14.gen(function* () {
|
|
1793
|
-
if (response.status < 200 || response.status >= 300) {
|
|
1794
|
-
const detail = yield* response.text.pipe(Effect14.orElseSucceed(() => ""));
|
|
1795
|
-
return yield* Effect14.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
1796
|
-
}
|
|
1797
|
-
const body = yield* response.json.pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
1798
|
-
return body.data;
|
|
1799
|
-
});
|
|
1800
|
-
var pveWith = (target, credential, method, path, form) => Effect14.gen(function* () {
|
|
1801
|
-
const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect14.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure)))) : yield* executeOne(target, credential, method, path, form, target.api);
|
|
1802
|
-
return yield* readResponse(response, method, path);
|
|
1755
|
+
var CEPH_FLAG_UPDATE = "pve:PUT /cluster/ceph/flags/{flag}";
|
|
1756
|
+
var attributesOf3 = (live, props) => ({
|
|
1757
|
+
flag: props.flag,
|
|
1758
|
+
value: bool(live)
|
|
1803
1759
|
});
|
|
1804
|
-
var
|
|
1805
|
-
const
|
|
1806
|
-
return
|
|
1807
|
-
});
|
|
1808
|
-
|
|
1809
|
-
// src/proxmox/resource.ts
|
|
1810
|
-
var pveOperations = (spec) => {
|
|
1811
|
-
const { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(spec);
|
|
1812
|
-
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect15.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect15.orElseSucceed(() => {
|
|
1813
|
-
return;
|
|
1814
|
-
}));
|
|
1815
|
-
return {
|
|
1816
|
-
guardCreate: guardCreate2,
|
|
1817
|
-
guardUpdate: guardUpdate2,
|
|
1818
|
-
read,
|
|
1819
|
-
diff: (news, output) => Effect15.gen(function* () {
|
|
1820
|
-
if (!isResolved5(news))
|
|
1821
|
-
return;
|
|
1822
|
-
yield* guardCreate2(news, output === undefined);
|
|
1823
|
-
yield* guardUpdate2(news);
|
|
1824
|
-
if (output === undefined)
|
|
1825
|
-
return;
|
|
1826
|
-
const live = yield* read(news);
|
|
1827
|
-
if (live === undefined) {
|
|
1828
|
-
yield* guardCreate2(news, true);
|
|
1829
|
-
return { action: "update" };
|
|
1830
|
-
}
|
|
1831
|
-
if (spec.matches(live, news))
|
|
1832
|
-
return { action: "noop" };
|
|
1833
|
-
return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
|
|
1834
|
-
}),
|
|
1835
|
-
reconcile: (news) => Effect15.gen(function* () {
|
|
1836
|
-
const live = yield* read(news);
|
|
1837
|
-
yield* guardCreate2(news, live === undefined);
|
|
1838
|
-
yield* guardUpdate2(news);
|
|
1839
|
-
if (live === undefined) {
|
|
1840
|
-
yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
|
|
1841
|
-
} else if (spec.updateForm !== undefined) {
|
|
1842
|
-
const form = formToSend(spec.matches, live, news, spec.updateForm(news));
|
|
1843
|
-
if (form !== undefined) {
|
|
1844
|
-
yield* pve(news.target, "provision", "PUT", spec.path(news), form);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
const after = yield* read(news);
|
|
1848
|
-
if (after === undefined) {
|
|
1849
|
-
return yield* Effect15.die(new Error(`${spec.path(news)}: the write returned no error but the object is still absent. ` + 'PVE wraps every answer in {"data":...} and can report success on a call that did ' + "nothing -- read back rather than trusting the status code."));
|
|
1850
|
-
}
|
|
1851
|
-
return after;
|
|
1852
|
-
}),
|
|
1853
|
-
destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
|
|
1854
|
-
};
|
|
1855
|
-
};
|
|
1856
|
-
var pveHandlers = (spec) => {
|
|
1857
|
-
const ops = pveOperations(spec);
|
|
1858
|
-
return {
|
|
1859
|
-
list: () => Effect15.succeed([]),
|
|
1860
|
-
read: ({ olds }) => ops.read(olds),
|
|
1861
|
-
diff: ({ news, output }) => ops.diff(news, output),
|
|
1862
|
-
reconcile: ({ news }) => ops.reconcile(news),
|
|
1863
|
-
delete: ({ olds }) => ops.destroy(olds)
|
|
1864
|
-
};
|
|
1760
|
+
var scalarFlagOrDie = (live, props) => {
|
|
1761
|
+
const scalar = typeof live === "boolean" || live === 0 || live === 1 || live === "0" || live === "1";
|
|
1762
|
+
return scalar ? Effect14.succeed(live) : Effect14.die(new Error(`cluster/ceph/flags/${props.flag}: GET answered ${JSON.stringify(live)}, not a bare ` + "boolean. This endpoint's success is a scalar; an empty object is what the protocol " + 'substitutes for `{"data":null}`. Check `ceph osd dump | head -1` and the cluster ' + "log rather than trust a coerced `false`."));
|
|
1865
1763
|
};
|
|
1764
|
+
var readClusterCephFlag = (props) => runPve(props.target, "read", false, cluster3.getClusterCephFlag({ flag: props.flag })).pipe(Effect14.flatMap((live) => scalarFlagOrDie(live, props)), Effect14.map((live) => attributesOf3(live, props)));
|
|
1765
|
+
var readClusterCephFlagForDiff = (props) => readOrUnreadable(readClusterCephFlag(props));
|
|
1766
|
+
var updateForm = (props) => ({ value: flag(props.value) ?? "0" });
|
|
1767
|
+
var writeClusterCephFlag = (props) => runPve(props.target, "provision", true, cluster3.putClusterCephFlag({ flag: props.flag, value: updateForm(props).value }));
|
|
1866
1768
|
|
|
1867
1769
|
// src/proxmox/ceph-flag.ts
|
|
1868
1770
|
var ProxmoxCephFlag = Resource5("Proxmox.CephFlag");
|
|
1869
|
-
var
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1771
|
+
var matches3 = (attributes, props) => attributes.value === props.value;
|
|
1772
|
+
var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect15.succeed(ProxmoxCephFlag.Provider.of({
|
|
1773
|
+
list: () => Effect15.succeed([]),
|
|
1774
|
+
read: ({ olds }) => readClusterCephFlag(olds),
|
|
1775
|
+
diff: Effect15.fn(function* ({ news, output }) {
|
|
1776
|
+
if (!isResolved5(news))
|
|
1777
|
+
return;
|
|
1778
|
+
yield* guardWrite2(CEPH_FLAG_UPDATE, updateForm(news), false);
|
|
1779
|
+
if (output === undefined)
|
|
1780
|
+
return;
|
|
1781
|
+
const live = yield* readClusterCephFlagForDiff(news);
|
|
1782
|
+
if (live === UNREADABLE) {
|
|
1783
|
+
yield* unreadableWarning("Proxmox.CephFlag", news.flag, news.target.mount, mintTier(news.target, "read"));
|
|
1784
|
+
return { action: "noop" };
|
|
1785
|
+
}
|
|
1786
|
+
return { action: matches3(live, news) ? "noop" : "update" };
|
|
1787
|
+
}),
|
|
1788
|
+
delete: () => Effect15.void,
|
|
1789
|
+
reconcile: Effect15.fn(function* ({ news }) {
|
|
1790
|
+
const live = yield* readClusterCephFlag(news);
|
|
1791
|
+
const form = formToSend(matches3, live, news, updateForm(news));
|
|
1792
|
+
if (form !== undefined) {
|
|
1793
|
+
yield* guardWrite2(CEPH_FLAG_UPDATE, updateForm(news), false);
|
|
1794
|
+
yield* writeClusterCephFlag(news);
|
|
1795
|
+
}
|
|
1796
|
+
const after = yield* readClusterCephFlag(news);
|
|
1883
1797
|
if (after.value !== news.value) {
|
|
1884
|
-
return yield*
|
|
1798
|
+
return yield* Effect15.die(new Error(`cluster/ceph/flags/${news.flag}: the PUT returned no error but ceph still ` + `reports the flag ${after.value ? "set" : "clear"} rather than ` + `${news.value ? "set" : "clear"}. This endpoint's success is documented as a ` + "null body, so the status code proves nothing -- check `ceph osd dump | " + "head -1` and the cluster log. `pause` in particular is two ceph flags read " + "as one; see the header."));
|
|
1885
1799
|
}
|
|
1886
1800
|
return after;
|
|
1887
1801
|
})
|
|
@@ -1890,11 +1804,11 @@ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect16.s
|
|
|
1890
1804
|
import { Resource as Resource6 } from "alchemy";
|
|
1891
1805
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1892
1806
|
import * as Provider6 from "alchemy/Provider";
|
|
1893
|
-
import * as
|
|
1807
|
+
import * as Effect17 from "effect/Effect";
|
|
1894
1808
|
|
|
1895
1809
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1896
1810
|
import * as nodes2 from "@distilled.cloud/proxmox/nodes";
|
|
1897
|
-
import * as
|
|
1811
|
+
import * as Effect16 from "effect/Effect";
|
|
1898
1812
|
|
|
1899
1813
|
// src/proxmox/ceph-fs-wire.ts
|
|
1900
1814
|
var readRow = (live, props) => {
|
|
@@ -1922,40 +1836,40 @@ var notCreated2 = (props) => new Error(`${objectPath(props)}: the create task fi
|
|
|
1922
1836
|
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.");
|
|
1923
1837
|
|
|
1924
1838
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1925
|
-
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(
|
|
1839
|
+
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect16.map((rows) => readRow(rows, props)));
|
|
1926
1840
|
var toDistilledCreate = (props) => ({
|
|
1927
1841
|
...createForm2(props),
|
|
1928
1842
|
name: props.name,
|
|
1929
1843
|
node: props.node
|
|
1930
1844
|
});
|
|
1931
|
-
var settleTask = (props, upid) =>
|
|
1845
|
+
var settleTask = (props, upid) => Effect16.gen(function* () {
|
|
1932
1846
|
for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
|
|
1933
|
-
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(
|
|
1847
|
+
const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect16.orElseSucceed(() => {
|
|
1934
1848
|
return;
|
|
1935
1849
|
}));
|
|
1936
1850
|
if (status?.status === "stopped") {
|
|
1937
1851
|
if (status.exitstatus === "OK")
|
|
1938
1852
|
return;
|
|
1939
|
-
return yield*
|
|
1853
|
+
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\`.`));
|
|
1940
1854
|
}
|
|
1941
|
-
yield*
|
|
1855
|
+
yield* Effect16.sleep(POLL_SECONDS * 1000);
|
|
1942
1856
|
}
|
|
1943
|
-
return yield*
|
|
1857
|
+
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."));
|
|
1944
1858
|
});
|
|
1945
|
-
var createFs = (props) =>
|
|
1859
|
+
var createFs = (props) => Effect16.gen(function* () {
|
|
1946
1860
|
const upid = yield* runPve(props.target, "provision", true, nodes2.updateNodeCephFs(toDistilledCreate(props)));
|
|
1947
1861
|
if (upid === "") {
|
|
1948
|
-
return yield*
|
|
1862
|
+
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.'));
|
|
1949
1863
|
}
|
|
1950
1864
|
yield* settleTask(props, upid);
|
|
1951
1865
|
});
|
|
1952
|
-
var destroyFs = (props) =>
|
|
1866
|
+
var destroyFs = (props) => Effect16.gen(function* () {
|
|
1953
1867
|
const upid = yield* runPve(props.target, "provision", true, nodes2.deleteNodeCephFs({
|
|
1954
1868
|
node: props.node,
|
|
1955
1869
|
name: props.name,
|
|
1956
1870
|
...props["remove-pools"] === true ? { remove_pools: "1" } : {},
|
|
1957
1871
|
...props["remove-storages"] === true ? { remove_storages: "1" } : {}
|
|
1958
|
-
})).pipe(
|
|
1872
|
+
})).pipe(Effect16.catchTag("CephFsNotFound", () => Effect16.succeed("")));
|
|
1959
1873
|
if (upid !== "")
|
|
1960
1874
|
yield* settleTask(props, upid);
|
|
1961
1875
|
});
|
|
@@ -1964,12 +1878,12 @@ var destroyFs = (props) => Effect17.gen(function* () {
|
|
|
1964
1878
|
var ProxmoxCephFs = Resource6("Proxmox.CephFs", {
|
|
1965
1879
|
defaultRemovalPolicy: "retain"
|
|
1966
1880
|
});
|
|
1967
|
-
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs,
|
|
1968
|
-
list: () =>
|
|
1969
|
-
read:
|
|
1881
|
+
var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect17.succeed(ProxmoxCephFs.Provider.of({
|
|
1882
|
+
list: () => Effect17.succeed([]),
|
|
1883
|
+
read: Effect17.fn(function* ({ olds }) {
|
|
1970
1884
|
return yield* readFs(olds);
|
|
1971
1885
|
}),
|
|
1972
|
-
diff:
|
|
1886
|
+
diff: Effect17.fn(function* ({ news, output }) {
|
|
1973
1887
|
if (!isResolved6(news))
|
|
1974
1888
|
return;
|
|
1975
1889
|
yield* guardWrite2(CEPH_FS_CREATE, createForm2(news), output === undefined);
|
|
@@ -1985,34 +1899,34 @@ var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect18.succe
|
|
|
1985
1899
|
}
|
|
1986
1900
|
return { action: "noop" };
|
|
1987
1901
|
}),
|
|
1988
|
-
reconcile:
|
|
1902
|
+
reconcile: Effect17.fn(function* ({ news }) {
|
|
1989
1903
|
const live = yield* readFs(news);
|
|
1990
1904
|
if (live !== undefined)
|
|
1991
1905
|
return live;
|
|
1992
1906
|
yield* createFs(news);
|
|
1993
1907
|
const after = yield* readFs(news);
|
|
1994
1908
|
if (after === undefined)
|
|
1995
|
-
return yield*
|
|
1909
|
+
return yield* Effect17.die(notCreated2(news));
|
|
1996
1910
|
return after;
|
|
1997
1911
|
}),
|
|
1998
|
-
delete:
|
|
1912
|
+
delete: Effect17.fn(function* ({ olds }) {
|
|
1999
1913
|
if ((yield* readFs(olds)) === undefined)
|
|
2000
1914
|
return;
|
|
2001
1915
|
yield* destroyFs(olds);
|
|
2002
1916
|
const after = yield* readFs(olds);
|
|
2003
1917
|
if (after !== undefined)
|
|
2004
|
-
return yield*
|
|
1918
|
+
return yield* Effect17.die(notDestroyed(olds));
|
|
2005
1919
|
})
|
|
2006
1920
|
})));
|
|
2007
1921
|
// src/proxmox/ceph-osd.ts
|
|
2008
1922
|
import { Resource as Resource7 } from "alchemy";
|
|
2009
1923
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2010
1924
|
import * as Provider7 from "alchemy/Provider";
|
|
2011
|
-
import * as
|
|
1925
|
+
import * as Effect20 from "effect/Effect";
|
|
2012
1926
|
|
|
2013
1927
|
// src/proxmox/ceph-osd-tree.ts
|
|
2014
1928
|
import * as nodes3 from "@distilled.cloud/proxmox/nodes";
|
|
2015
|
-
import * as
|
|
1929
|
+
import * as Effect18 from "effect/Effect";
|
|
2016
1930
|
var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
|
|
2017
1931
|
var osdLeaves = (tree) => {
|
|
2018
1932
|
const root = tree["root"];
|
|
@@ -2038,23 +1952,23 @@ var osdAttributes = (leaf, props) => ({
|
|
|
2038
1952
|
status: text(leaf["status"]),
|
|
2039
1953
|
total_space: num(leaf["total_space"], 0)
|
|
2040
1954
|
});
|
|
2041
|
-
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(
|
|
1955
|
+
var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(Effect18.map((t) => {
|
|
2042
1956
|
const leaf = findOsd(t, props.osdid);
|
|
2043
1957
|
return leaf === undefined ? undefined : osdAttributes(leaf, props);
|
|
2044
1958
|
}));
|
|
2045
1959
|
|
|
2046
1960
|
// src/proxmox/ceph-osd-write.ts
|
|
2047
1961
|
import * as nodes4 from "@distilled.cloud/proxmox/nodes";
|
|
2048
|
-
import * as
|
|
1962
|
+
import * as Effect19 from "effect/Effect";
|
|
2049
1963
|
var OSD_CREATE_ENDPOINT = "pve:POST /nodes/{node}/ceph/osd";
|
|
2050
1964
|
var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
|
|
2051
1965
|
var createOsdForm = (props, dev) => ({
|
|
2052
1966
|
dev,
|
|
2053
1967
|
...props.device_class === undefined ? {} : { "crush-device-class": props.device_class }
|
|
2054
1968
|
});
|
|
2055
|
-
var createOsd =
|
|
1969
|
+
var createOsd = Effect19.fn(function* (news) {
|
|
2056
1970
|
if (news.dev === undefined) {
|
|
2057
|
-
return yield*
|
|
1971
|
+
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."));
|
|
2058
1972
|
}
|
|
2059
1973
|
const form = createOsdForm(news, news.dev);
|
|
2060
1974
|
yield* guardForm(OSD_CREATE_ENDPOINT, form, true);
|
|
@@ -2065,7 +1979,7 @@ var createOsd = Effect20.fn(function* (news) {
|
|
|
2065
1979
|
}));
|
|
2066
1980
|
const created = yield* readOsd(news);
|
|
2067
1981
|
if (created === undefined) {
|
|
2068
|
-
return yield*
|
|
1982
|
+
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."));
|
|
2069
1983
|
}
|
|
2070
1984
|
return created;
|
|
2071
1985
|
});
|
|
@@ -2081,12 +1995,12 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
|
|
|
2081
1995
|
});
|
|
2082
1996
|
var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
|
|
2083
1997
|
var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
|
|
2084
|
-
var
|
|
2085
|
-
list: () =>
|
|
2086
|
-
read:
|
|
1998
|
+
var handlers = {
|
|
1999
|
+
list: () => Effect20.succeed([]),
|
|
2000
|
+
read: Effect20.fn(function* ({ olds }) {
|
|
2087
2001
|
return yield* readOsd(olds);
|
|
2088
2002
|
}),
|
|
2089
|
-
diff:
|
|
2003
|
+
diff: Effect20.fn(function* ({
|
|
2090
2004
|
news,
|
|
2091
2005
|
output
|
|
2092
2006
|
}) {
|
|
@@ -2099,27 +2013,27 @@ var handlers2 = {
|
|
|
2099
2013
|
return { action: "update" };
|
|
2100
2014
|
return settled(live, news) ? { action: "noop" } : { action: "update" };
|
|
2101
2015
|
}),
|
|
2102
|
-
reconcile:
|
|
2016
|
+
reconcile: Effect20.fn(function* ({ news }) {
|
|
2103
2017
|
const live = yield* readOsd(news);
|
|
2104
2018
|
if (live === undefined) {
|
|
2105
2019
|
return yield* createOsd(news);
|
|
2106
2020
|
}
|
|
2107
2021
|
if (!settled(live, news)) {
|
|
2108
|
-
return yield*
|
|
2022
|
+
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."));
|
|
2109
2023
|
}
|
|
2110
2024
|
return live;
|
|
2111
2025
|
}),
|
|
2112
|
-
delete:
|
|
2026
|
+
delete: Effect20.fn(function* ({ olds }) {
|
|
2113
2027
|
yield* destroyOsd(olds);
|
|
2114
2028
|
})
|
|
2115
2029
|
};
|
|
2116
|
-
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd,
|
|
2030
|
+
var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect20.succeed(ProxmoxCephOsd.Provider.of(handlers)));
|
|
2117
2031
|
// src/proxmox/ceph-pool.ts
|
|
2118
2032
|
import { Resource as Resource8 } from "alchemy";
|
|
2119
2033
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2120
2034
|
import * as Provider8 from "alchemy/Provider";
|
|
2121
2035
|
import * as nodes7 from "@distilled.cloud/proxmox/nodes";
|
|
2122
|
-
import * as
|
|
2036
|
+
import * as Effect23 from "effect/Effect";
|
|
2123
2037
|
|
|
2124
2038
|
// src/proxmox/ceph-pool-form.ts
|
|
2125
2039
|
var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
|
|
@@ -2148,22 +2062,22 @@ var createBody = (props) => ({
|
|
|
2148
2062
|
|
|
2149
2063
|
// src/proxmox/ceph-pool-settle.ts
|
|
2150
2064
|
import * as nodes5 from "@distilled.cloud/proxmox/nodes";
|
|
2151
|
-
import * as
|
|
2152
|
-
var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(
|
|
2153
|
-
var settle = (props, read, done) =>
|
|
2065
|
+
import * as Effect21 from "effect/Effect";
|
|
2066
|
+
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));
|
|
2067
|
+
var settle = (props, read, done) => Effect21.gen(function* () {
|
|
2154
2068
|
for (let attempt = 0;attempt < 30; attempt += 1) {
|
|
2155
2069
|
const live = yield* read(props);
|
|
2156
2070
|
if (done(live))
|
|
2157
2071
|
return live;
|
|
2158
|
-
yield*
|
|
2072
|
+
yield* Effect21.sleep("2 seconds");
|
|
2159
2073
|
}
|
|
2160
2074
|
return yield* read(props);
|
|
2161
2075
|
});
|
|
2162
2076
|
|
|
2163
2077
|
// src/proxmox/ceph-pool-wire.ts
|
|
2164
2078
|
import * as nodes6 from "@distilled.cloud/proxmox/nodes";
|
|
2165
|
-
import * as
|
|
2166
|
-
var
|
|
2079
|
+
import * as Effect22 from "effect/Effect";
|
|
2080
|
+
var attributesOf4 = (live, props) => {
|
|
2167
2081
|
const row = live;
|
|
2168
2082
|
if (typeof row["name"] !== "string")
|
|
2169
2083
|
return;
|
|
@@ -2185,7 +2099,7 @@ var attributesOf3 = (live, props) => {
|
|
|
2185
2099
|
target_size_ratio: num(row["target_size_ratio"], UNSET)
|
|
2186
2100
|
};
|
|
2187
2101
|
};
|
|
2188
|
-
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(
|
|
2102
|
+
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(Effect22.map((live) => attributesOf4(live, props)), Effect22.catchTag("CephPoolNotFound", () => Effect22.succeed(undefined)));
|
|
2189
2103
|
var CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
|
|
2190
2104
|
var CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
|
|
2191
2105
|
var toDistilledCreate2 = (props) => ({
|
|
@@ -2202,11 +2116,11 @@ var toDistilledUpdate = (props) => ({
|
|
|
2202
2116
|
var ProxmoxCephPool = Resource8("Proxmox.CephPool", {
|
|
2203
2117
|
defaultRemovalPolicy: "retain"
|
|
2204
2118
|
});
|
|
2205
|
-
var
|
|
2206
|
-
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool,
|
|
2207
|
-
list: () =>
|
|
2119
|
+
var matches4 = (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);
|
|
2120
|
+
var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect23.succeed(ProxmoxCephPool.Provider.of({
|
|
2121
|
+
list: () => Effect23.succeed([]),
|
|
2208
2122
|
read: ({ olds }) => readPoolStatus(olds),
|
|
2209
|
-
diff:
|
|
2123
|
+
diff: Effect23.fn(function* ({ news, output }) {
|
|
2210
2124
|
if (!isResolved8(news))
|
|
2211
2125
|
return;
|
|
2212
2126
|
yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), output === undefined);
|
|
@@ -2218,9 +2132,9 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2218
2132
|
yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), true);
|
|
2219
2133
|
return { action: "update" };
|
|
2220
2134
|
}
|
|
2221
|
-
return
|
|
2135
|
+
return matches4(live, news) ? { action: "noop" } : { action: "update" };
|
|
2222
2136
|
}),
|
|
2223
|
-
reconcile:
|
|
2137
|
+
reconcile: Effect23.fn(function* ({ news }) {
|
|
2224
2138
|
const live = yield* readPoolStatus(news);
|
|
2225
2139
|
let upid;
|
|
2226
2140
|
if (live === undefined) {
|
|
@@ -2228,36 +2142,36 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
|
|
|
2228
2142
|
yield* confirmAbsent(news, object(news));
|
|
2229
2143
|
upid = yield* runPve(news.target, "provision", true, nodes7.createNodeCephPool(toDistilledCreate2(news)));
|
|
2230
2144
|
} else {
|
|
2231
|
-
const form = formToSend(
|
|
2145
|
+
const form = formToSend(matches4, live, news, updateBody(news));
|
|
2232
2146
|
if (form !== undefined) {
|
|
2233
2147
|
yield* guardWrite2(CEPH_POOL_UPDATE, updateBody(news), false);
|
|
2234
2148
|
upid = yield* runPve(news.target, "provision", true, nodes7.putNodeCephPool(toDistilledUpdate(news)));
|
|
2235
2149
|
}
|
|
2236
2150
|
}
|
|
2237
|
-
const after = yield* settle(news, readPoolStatus, (row) => row !== undefined &&
|
|
2238
|
-
if (after === undefined || !
|
|
2239
|
-
return yield*
|
|
2151
|
+
const after = yield* settle(news, readPoolStatus, (row) => row !== undefined && matches4(row, news));
|
|
2152
|
+
if (after === undefined || !matches4(after, news)) {
|
|
2153
|
+
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."));
|
|
2240
2154
|
}
|
|
2241
2155
|
return after;
|
|
2242
2156
|
}),
|
|
2243
|
-
delete:
|
|
2157
|
+
delete: Effect23.fn(function* ({ olds }) {
|
|
2244
2158
|
yield* runPve(olds.target, "provision", true, nodes7.deleteNodeCephPool({ name: olds.name, node: olds.node }));
|
|
2245
2159
|
const left = yield* settle(olds, readPoolStatus, (row) => row === undefined);
|
|
2246
2160
|
if (left !== undefined) {
|
|
2247
|
-
return yield*
|
|
2161
|
+
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."));
|
|
2248
2162
|
}
|
|
2249
2163
|
})
|
|
2250
2164
|
})));
|
|
2251
2165
|
// src/proxmox/firewall-alias.ts
|
|
2252
2166
|
import { Resource as Resource9 } from "alchemy";
|
|
2253
2167
|
import * as Provider9 from "alchemy/Provider";
|
|
2254
|
-
import * as
|
|
2168
|
+
import * as Effect25 from "effect/Effect";
|
|
2255
2169
|
|
|
2256
2170
|
// src/proxmox/firewall-alias-lifecycle.ts
|
|
2257
2171
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2258
|
-
import * as
|
|
2172
|
+
import * as cluster4 from "@distilled.cloud/proxmox/cluster";
|
|
2259
2173
|
import { ProxmoxParseError as ProxmoxParseError2 } from "@distilled.cloud/proxmox/Errors";
|
|
2260
|
-
import * as
|
|
2174
|
+
import * as Effect24 from "effect/Effect";
|
|
2261
2175
|
|
|
2262
2176
|
// src/proxmox/firewall-alias-form.ts
|
|
2263
2177
|
var fold = (name) => name.trim().toLowerCase();
|
|
@@ -2299,20 +2213,20 @@ var firewallAliasSpec = {
|
|
|
2299
2213
|
|
|
2300
2214
|
// src/proxmox/firewall-alias-lifecycle.ts
|
|
2301
2215
|
var { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(firewallAliasSpec);
|
|
2302
|
-
var readFirewallAlias = (props) => runPve(props.target, "read", false,
|
|
2216
|
+
var readFirewallAlias = (props) => runPve(props.target, "read", false, cluster4.getClusterFirewallAlias({ name: props.name })).pipe(Effect24.flatMap((live) => {
|
|
2303
2217
|
if (live === null || typeof live !== "object" || Array.isArray(live) || !("name" in live) || typeof live.name !== "string" || fold(live.name) !== fold(props.name) || !("cidr" in live) || typeof live.cidr !== "string" || cidr(live.cidr) === "") {
|
|
2304
|
-
return
|
|
2218
|
+
return Effect24.fail(new ProxmoxParseError2({
|
|
2305
2219
|
body: undefined,
|
|
2306
2220
|
cause: "Firewall alias response does not match the requested vendor identity"
|
|
2307
2221
|
}));
|
|
2308
2222
|
}
|
|
2309
|
-
return
|
|
2310
|
-
}),
|
|
2311
|
-
var deleteFirewallAlias = (props) => runPve(props.target, "provision", true,
|
|
2223
|
+
return Effect24.succeed(firewallAliasSpec.attributes({ ...live }, props));
|
|
2224
|
+
}), Effect24.catchTag("FirewallAliasNotFound", () => Effect24.succeed(undefined)));
|
|
2225
|
+
var deleteFirewallAlias = (props) => runPve(props.target, "provision", true, cluster4.deleteClusterFirewallAlias({ name: props.name }));
|
|
2312
2226
|
var firewallAliasHandlers = {
|
|
2313
|
-
list: () =>
|
|
2227
|
+
list: () => Effect24.succeed([]),
|
|
2314
2228
|
read: ({ olds }) => readFirewallAlias(olds),
|
|
2315
|
-
diff:
|
|
2229
|
+
diff: Effect24.fn(function* ({
|
|
2316
2230
|
news,
|
|
2317
2231
|
output
|
|
2318
2232
|
}) {
|
|
@@ -2331,20 +2245,20 @@ var firewallAliasHandlers = {
|
|
|
2331
2245
|
}
|
|
2332
2246
|
return { action: firewallAliasSpec.matches(live, news) ? "noop" : "update" };
|
|
2333
2247
|
}),
|
|
2334
|
-
reconcile:
|
|
2248
|
+
reconcile: Effect24.fn(function* ({ news }) {
|
|
2335
2249
|
const live = yield* readFirewallAlias(news);
|
|
2336
2250
|
yield* guardCreate2(news, live === undefined);
|
|
2337
2251
|
yield* guardUpdate2(news);
|
|
2338
2252
|
if (live === undefined) {
|
|
2339
|
-
yield* runPve(news.target, "provision", true,
|
|
2253
|
+
yield* runPve(news.target, "provision", true, cluster4.createClusterFirewallAlias(firewallAliasSpec.createForm(news)));
|
|
2340
2254
|
} else {
|
|
2341
2255
|
const form = formToSend(firewallAliasSpec.matches, live, news, firewallAliasSpec.updateForm(news));
|
|
2342
2256
|
if (form !== undefined)
|
|
2343
|
-
yield* runPve(news.target, "provision", true,
|
|
2257
|
+
yield* runPve(news.target, "provision", true, cluster4.putClusterFirewallAlias({ ...form, name: news.name }));
|
|
2344
2258
|
}
|
|
2345
2259
|
const after = yield* readFirewallAlias(news);
|
|
2346
2260
|
if (after === undefined)
|
|
2347
|
-
return yield*
|
|
2261
|
+
return yield* Effect24.fail(new Error(`${firewallAliasSpec.path(news)}: write returned success but the resource is still absent`));
|
|
2348
2262
|
return after;
|
|
2349
2263
|
}),
|
|
2350
2264
|
delete: ({ olds }) => deleteFirewallAlias(olds)
|
|
@@ -2352,17 +2266,17 @@ var firewallAliasHandlers = {
|
|
|
2352
2266
|
|
|
2353
2267
|
// src/proxmox/firewall-alias.ts
|
|
2354
2268
|
var ProxmoxFirewallAlias = Resource9("Proxmox.FirewallAlias");
|
|
2355
|
-
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
2269
|
+
var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect25.succeed(ProxmoxFirewallAlias.Provider.of(firewallAliasHandlers)));
|
|
2356
2270
|
// src/proxmox/group.ts
|
|
2357
2271
|
import { Resource as Resource10 } from "alchemy";
|
|
2358
2272
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2359
2273
|
import * as Provider10 from "alchemy/Provider";
|
|
2360
2274
|
import * as access4 from "@distilled.cloud/proxmox/access";
|
|
2361
|
-
import * as
|
|
2275
|
+
import * as Effect27 from "effect/Effect";
|
|
2362
2276
|
|
|
2363
2277
|
// src/proxmox/group-wire.ts
|
|
2364
2278
|
import * as access3 from "@distilled.cloud/proxmox/access";
|
|
2365
|
-
import * as
|
|
2279
|
+
import * as Effect26 from "effect/Effect";
|
|
2366
2280
|
var GROUP_CREATE = "pve:POST /access/groups";
|
|
2367
2281
|
var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
|
|
2368
2282
|
var storedComment = (comment2) => {
|
|
@@ -2377,34 +2291,34 @@ var createForm3 = (props) => ({
|
|
|
2377
2291
|
comment: storedComment(props.comment),
|
|
2378
2292
|
groupid: props.groupid
|
|
2379
2293
|
});
|
|
2380
|
-
var
|
|
2294
|
+
var updateForm2 = (props) => ({
|
|
2381
2295
|
comment: storedComment(props.comment),
|
|
2382
2296
|
groupid: props.groupid
|
|
2383
2297
|
});
|
|
2384
|
-
var
|
|
2298
|
+
var attributesOf5 = (live, props) => ({
|
|
2385
2299
|
comment: text(live.comment),
|
|
2386
2300
|
groupid: props.groupid,
|
|
2387
2301
|
members: memberList(live.members)
|
|
2388
2302
|
});
|
|
2389
|
-
var
|
|
2390
|
-
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(
|
|
2391
|
-
var readGroup = (props) => readGroupOrFail(props).pipe(
|
|
2303
|
+
var matches5 = (attributes, props) => attributes.comment === storedComment(props.comment);
|
|
2304
|
+
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect26.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf5(live, props)));
|
|
2305
|
+
var readGroup = (props) => readGroupOrFail(props).pipe(Effect26.catchTag("GroupNotFound", () => Effect26.succeed(undefined)));
|
|
2392
2306
|
var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
|
|
2393
2307
|
|
|
2394
2308
|
// src/proxmox/group.ts
|
|
2395
2309
|
var ProxmoxGroup = Resource10("Proxmox.Group", {
|
|
2396
2310
|
defaultRemovalPolicy: "retain"
|
|
2397
2311
|
});
|
|
2398
|
-
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup,
|
|
2399
|
-
list: () =>
|
|
2400
|
-
read:
|
|
2312
|
+
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succeed(ProxmoxGroup.Provider.of({
|
|
2313
|
+
list: () => Effect27.succeed([]),
|
|
2314
|
+
read: Effect27.fn(function* ({ olds, output }) {
|
|
2401
2315
|
return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
|
|
2402
2316
|
}),
|
|
2403
|
-
diff:
|
|
2317
|
+
diff: Effect27.fn(function* ({ news, output }) {
|
|
2404
2318
|
if (!isResolved10(news))
|
|
2405
2319
|
return;
|
|
2406
2320
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
|
|
2407
|
-
yield* guardWrite2(GROUP_UPDATE,
|
|
2321
|
+
yield* guardWrite2(GROUP_UPDATE, updateForm2(news), false);
|
|
2408
2322
|
if (output === undefined)
|
|
2409
2323
|
return;
|
|
2410
2324
|
const live = yield* readGroupOrFail(news);
|
|
@@ -2416,31 +2330,149 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect28.succee
|
|
|
2416
2330
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), true);
|
|
2417
2331
|
return { action: "update" };
|
|
2418
2332
|
}
|
|
2419
|
-
return
|
|
2333
|
+
return matches5(live, news) ? { action: "noop" } : { action: "update" };
|
|
2420
2334
|
}),
|
|
2421
|
-
reconcile:
|
|
2335
|
+
reconcile: Effect27.fn(function* ({ news }) {
|
|
2422
2336
|
const before = dropUnreadable3(yield* readGroup(news));
|
|
2423
2337
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
|
|
2424
|
-
yield* guardWrite2(GROUP_UPDATE,
|
|
2338
|
+
yield* guardWrite2(GROUP_UPDATE, updateForm2(news), false);
|
|
2425
2339
|
if (before === undefined) {
|
|
2426
2340
|
yield* runPve(news.target, "provision", true, access4.createAccessGroup(createForm3(news)));
|
|
2427
|
-
} else if (!
|
|
2428
|
-
yield* runPve(news.target, "provision", true, access4.putAccessGroup(
|
|
2341
|
+
} else if (!matches5(before, news)) {
|
|
2342
|
+
yield* runPve(news.target, "provision", true, access4.putAccessGroup(updateForm2(news)));
|
|
2429
2343
|
}
|
|
2430
2344
|
const after = dropUnreadable3(yield* readGroup(news));
|
|
2431
2345
|
if (after === undefined) {
|
|
2432
|
-
return yield*
|
|
2346
|
+
return yield* Effect27.die(new Error(`access/groups/${news.groupid}: the write returned no error but the group is ` + 'still absent. PVE wraps every answer in {"data":...} and can report success ' + "on a call that did nothing -- read back rather than trusting the status code."));
|
|
2433
2347
|
}
|
|
2434
2348
|
return after;
|
|
2435
2349
|
}),
|
|
2436
|
-
delete:
|
|
2350
|
+
delete: Effect27.fn(function* ({ olds }) {
|
|
2437
2351
|
yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
|
|
2438
2352
|
})
|
|
2439
2353
|
})));
|
|
2440
2354
|
// src/proxmox/ha-resource.ts
|
|
2441
2355
|
import { Resource as Resource11 } from "alchemy";
|
|
2442
2356
|
import * as Provider11 from "alchemy/Provider";
|
|
2357
|
+
import * as Effect30 from "effect/Effect";
|
|
2358
|
+
|
|
2359
|
+
// src/proxmox/resource.ts
|
|
2360
|
+
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2443
2361
|
import * as Effect29 from "effect/Effect";
|
|
2362
|
+
|
|
2363
|
+
// src/proxmox/client.ts
|
|
2364
|
+
import * as Effect28 from "effect/Effect";
|
|
2365
|
+
import * as HttpClient5 from "effect/unstable/http/HttpClient";
|
|
2366
|
+
import * as HttpClientRequest2 from "effect/unstable/http/HttpClientRequest";
|
|
2367
|
+
class PveError extends Error {
|
|
2368
|
+
status;
|
|
2369
|
+
method;
|
|
2370
|
+
path;
|
|
2371
|
+
constructor(status, method, path, detail) {
|
|
2372
|
+
super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
|
|
2373
|
+
this.status = status;
|
|
2374
|
+
this.method = method;
|
|
2375
|
+
this.path = path;
|
|
2376
|
+
this.name = "PveError";
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
|
|
2380
|
+
var encode = (form) => {
|
|
2381
|
+
const params = new URLSearchParams;
|
|
2382
|
+
for (const [key, value] of Object.entries(form)) {
|
|
2383
|
+
if (typeof value === "string")
|
|
2384
|
+
params.append(key, value);
|
|
2385
|
+
else
|
|
2386
|
+
for (const item of value)
|
|
2387
|
+
params.append(key, item);
|
|
2388
|
+
}
|
|
2389
|
+
return params.toString();
|
|
2390
|
+
};
|
|
2391
|
+
var buildRequest = (method, apiBase, path, credential, target, form) => {
|
|
2392
|
+
const url = `${apiBase}/${path}`;
|
|
2393
|
+
return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
|
|
2394
|
+
};
|
|
2395
|
+
var executeOne = (target, credential, method, path, form, apiBase) => Effect28.gen(function* () {
|
|
2396
|
+
const client = yield* HttpClient5.HttpClient;
|
|
2397
|
+
const request = buildRequest(method, apiBase, path, credential, target, form);
|
|
2398
|
+
return yield* client.execute(request).pipe(Effect28.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
2399
|
+
});
|
|
2400
|
+
var readResponse = (response, method, path) => Effect28.gen(function* () {
|
|
2401
|
+
if (response.status < 200 || response.status >= 300) {
|
|
2402
|
+
const detail = yield* response.text.pipe(Effect28.orElseSucceed(() => ""));
|
|
2403
|
+
return yield* Effect28.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
|
|
2404
|
+
}
|
|
2405
|
+
const body2 = yield* response.json.pipe(Effect28.mapError((cause) => new PveError(0, method, path, String(cause))));
|
|
2406
|
+
return body2.data;
|
|
2407
|
+
});
|
|
2408
|
+
var pveWith = (target, credential, method, path, form) => Effect28.gen(function* () {
|
|
2409
|
+
const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect28.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure)))) : yield* executeOne(target, credential, method, path, form, target.api);
|
|
2410
|
+
return yield* readResponse(response, method, path);
|
|
2411
|
+
});
|
|
2412
|
+
var pve = (target, role, method, path, form) => Effect28.gen(function* () {
|
|
2413
|
+
const credential = yield* leased(target, role);
|
|
2414
|
+
return yield* pveWith(target, credential, method, path, form);
|
|
2415
|
+
});
|
|
2416
|
+
|
|
2417
|
+
// src/proxmox/resource.ts
|
|
2418
|
+
var pveOperations = (spec) => {
|
|
2419
|
+
const { guardCreate: guardCreate3, guardUpdate: guardUpdate3 } = specGuards(spec);
|
|
2420
|
+
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect29.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect29.orElseSucceed(() => {
|
|
2421
|
+
return;
|
|
2422
|
+
}));
|
|
2423
|
+
return {
|
|
2424
|
+
guardCreate: guardCreate3,
|
|
2425
|
+
guardUpdate: guardUpdate3,
|
|
2426
|
+
read,
|
|
2427
|
+
diff: (news, output) => Effect29.gen(function* () {
|
|
2428
|
+
if (!isResolved11(news))
|
|
2429
|
+
return;
|
|
2430
|
+
yield* guardCreate3(news, output === undefined);
|
|
2431
|
+
yield* guardUpdate3(news);
|
|
2432
|
+
if (output === undefined)
|
|
2433
|
+
return;
|
|
2434
|
+
const live = yield* read(news);
|
|
2435
|
+
if (live === undefined) {
|
|
2436
|
+
yield* guardCreate3(news, true);
|
|
2437
|
+
return { action: "update" };
|
|
2438
|
+
}
|
|
2439
|
+
if (spec.matches(live, news))
|
|
2440
|
+
return { action: "noop" };
|
|
2441
|
+
return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
|
|
2442
|
+
}),
|
|
2443
|
+
reconcile: (news) => Effect29.gen(function* () {
|
|
2444
|
+
const live = yield* read(news);
|
|
2445
|
+
yield* guardCreate3(news, live === undefined);
|
|
2446
|
+
yield* guardUpdate3(news);
|
|
2447
|
+
if (live === undefined) {
|
|
2448
|
+
yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
|
|
2449
|
+
} else if (spec.updateForm !== undefined) {
|
|
2450
|
+
const form = formToSend(spec.matches, live, news, spec.updateForm(news));
|
|
2451
|
+
if (form !== undefined) {
|
|
2452
|
+
yield* pve(news.target, "provision", "PUT", spec.path(news), form);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
const after = yield* read(news);
|
|
2456
|
+
if (after === undefined) {
|
|
2457
|
+
return yield* Effect29.die(new Error(`${spec.path(news)}: the write returned no error but the object is still absent. ` + 'PVE wraps every answer in {"data":...} and can report success on a call that did ' + "nothing -- read back rather than trusting the status code."));
|
|
2458
|
+
}
|
|
2459
|
+
return after;
|
|
2460
|
+
}),
|
|
2461
|
+
destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
|
|
2462
|
+
};
|
|
2463
|
+
};
|
|
2464
|
+
var pveHandlers = (spec) => {
|
|
2465
|
+
const ops = pveOperations(spec);
|
|
2466
|
+
return {
|
|
2467
|
+
list: () => Effect29.succeed([]),
|
|
2468
|
+
read: ({ olds }) => ops.read(olds),
|
|
2469
|
+
diff: ({ news, output }) => ops.diff(news, output),
|
|
2470
|
+
reconcile: ({ news }) => ops.reconcile(news),
|
|
2471
|
+
delete: ({ olds }) => ops.destroy(olds)
|
|
2472
|
+
};
|
|
2473
|
+
};
|
|
2474
|
+
|
|
2475
|
+
// src/proxmox/ha-resource.ts
|
|
2444
2476
|
var ProxmoxHaResource = Resource11("Proxmox.HaResource");
|
|
2445
2477
|
var kind = (sid) => sid.split(":")[0] ?? "";
|
|
2446
2478
|
var shape3 = (props) => ({
|
|
@@ -2449,7 +2481,7 @@ var shape3 = (props) => ({
|
|
|
2449
2481
|
max_restart: String(props.max_restart ?? 1),
|
|
2450
2482
|
state: props.state ?? "started"
|
|
2451
2483
|
});
|
|
2452
|
-
var
|
|
2484
|
+
var handlers2 = pveHandlers({
|
|
2453
2485
|
attributes: (live, props) => ({
|
|
2454
2486
|
comment: typeof live["comment"] === "string" ? live["comment"] : "",
|
|
2455
2487
|
max_relocate: num(live["max_relocate"], 1),
|
|
@@ -2468,11 +2500,11 @@ var handlers3 = pveHandlers({
|
|
|
2468
2500
|
path: (props) => `cluster/ha/resources/${props.sid}`,
|
|
2469
2501
|
updateForm: shape3
|
|
2470
2502
|
});
|
|
2471
|
-
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource,
|
|
2503
|
+
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect30.succeed(ProxmoxHaResource.Provider.of(handlers2)));
|
|
2472
2504
|
// src/proxmox/ha-rule.ts
|
|
2473
2505
|
import { Resource as Resource12 } from "alchemy";
|
|
2474
2506
|
import * as Provider12 from "alchemy/Provider";
|
|
2475
|
-
import * as
|
|
2507
|
+
import * as Effect31 from "effect/Effect";
|
|
2476
2508
|
|
|
2477
2509
|
// src/proxmox/ha-rule-form.ts
|
|
2478
2510
|
var nodeList = (value) => {
|
|
@@ -2520,7 +2552,7 @@ var clearList = (props) => Object.entries(optional(props)).filter(([, value]) =>
|
|
|
2520
2552
|
|
|
2521
2553
|
// src/proxmox/ha-rule.ts
|
|
2522
2554
|
var ProxmoxHaRule = Resource12("Proxmox.HaRule");
|
|
2523
|
-
var
|
|
2555
|
+
var handlers3 = pveHandlers({
|
|
2524
2556
|
attributes: (live, props) => {
|
|
2525
2557
|
const liveType = text(live["type"]);
|
|
2526
2558
|
if (liveType !== "" && liveType !== props.type)
|
|
@@ -2549,43 +2581,43 @@ var handlers4 = pveHandlers({
|
|
|
2549
2581
|
return withClears(fields, clear);
|
|
2550
2582
|
}
|
|
2551
2583
|
});
|
|
2552
|
-
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule,
|
|
2584
|
+
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect31.succeed(ProxmoxHaRule.Provider.of(handlers3)));
|
|
2553
2585
|
// src/proxmox/lxc.ts
|
|
2554
2586
|
import { Resource as Resource13 } from "alchemy";
|
|
2555
|
-
import { isResolved as
|
|
2587
|
+
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
2556
2588
|
import * as Provider13 from "alchemy/Provider";
|
|
2557
|
-
import * as
|
|
2589
|
+
import * as Effect42 from "effect/Effect";
|
|
2558
2590
|
|
|
2559
2591
|
// src/ownership/adopt.ts
|
|
2560
2592
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
2561
2593
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
2562
2594
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
2563
|
-
import * as
|
|
2595
|
+
import * as Effect35 from "effect/Effect";
|
|
2564
2596
|
import * as Option5 from "effect/Option";
|
|
2565
2597
|
|
|
2566
2598
|
// src/ownership/resume.ts
|
|
2567
2599
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
2568
2600
|
import { Artifacts } from "alchemy/Artifacts";
|
|
2569
|
-
import * as
|
|
2601
|
+
import * as Effect32 from "effect/Effect";
|
|
2570
2602
|
import * as Option2 from "effect/Option";
|
|
2571
2603
|
var PROVEN = "homeflare/ownership/resumes";
|
|
2572
2604
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
2573
|
-
var note = (key, instanceId) =>
|
|
2574
|
-
const bag = yield*
|
|
2605
|
+
var note = (key, instanceId) => Effect32.gen(function* () {
|
|
2606
|
+
const bag = yield* Effect32.serviceOption(Artifacts);
|
|
2575
2607
|
if (Option2.isSome(bag))
|
|
2576
2608
|
yield* bag.value.set(key, instanceId);
|
|
2577
2609
|
});
|
|
2578
|
-
var noted = (key, instanceId) =>
|
|
2579
|
-
const bag = yield*
|
|
2610
|
+
var noted = (key, instanceId) => Effect32.gen(function* () {
|
|
2611
|
+
const bag = yield* Effect32.serviceOption(Artifacts);
|
|
2580
2612
|
if (Option2.isNone(bag))
|
|
2581
2613
|
return false;
|
|
2582
2614
|
return (yield* bag.value.get(key)) === instanceId;
|
|
2583
2615
|
});
|
|
2584
|
-
var noteUnfinished = (instanceId) =>
|
|
2585
|
-
var noteResume = (instanceId, recovered) =>
|
|
2616
|
+
var noteUnfinished = (instanceId) => Effect32.as(note(UNFINISHED, instanceId), undefined);
|
|
2617
|
+
var noteResume = (instanceId, recovered) => Effect32.gen(function* () {
|
|
2586
2618
|
yield* noteUnfinished(instanceId);
|
|
2587
|
-
const unproven = () =>
|
|
2588
|
-
const found = yield* recovered.pipe(
|
|
2619
|
+
const unproven = () => Effect32.succeed(undefined);
|
|
2620
|
+
const found = yield* recovered.pipe(Effect32.catch(unproven), Effect32.catchDefect(unproven));
|
|
2589
2621
|
if (found === undefined || found === null || Unowned.is(found))
|
|
2590
2622
|
return;
|
|
2591
2623
|
yield* note(PROVEN, instanceId);
|
|
@@ -2596,7 +2628,7 @@ var provingResumes = (service) => {
|
|
|
2596
2628
|
const { diff, read } = service;
|
|
2597
2629
|
if (diff === undefined || read === undefined)
|
|
2598
2630
|
return service;
|
|
2599
|
-
const proving = (input) =>
|
|
2631
|
+
const proving = (input) => Effect32.gen(function* () {
|
|
2600
2632
|
if (input.output === undefined) {
|
|
2601
2633
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
2602
2634
|
}
|
|
@@ -2608,12 +2640,12 @@ var provingResumes = (service) => {
|
|
|
2608
2640
|
// src/ownership/rows.ts
|
|
2609
2641
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
2610
2642
|
import { State, isActionState } from "alchemy/State/State";
|
|
2611
|
-
import * as
|
|
2643
|
+
import * as Effect34 from "effect/Effect";
|
|
2612
2644
|
import * as Option4 from "effect/Option";
|
|
2613
2645
|
|
|
2614
2646
|
// src/ownership/whole.ts
|
|
2615
2647
|
import { Stack } from "alchemy/Stack";
|
|
2616
|
-
import * as
|
|
2648
|
+
import * as Effect33 from "effect/Effect";
|
|
2617
2649
|
import * as Option3 from "effect/Option";
|
|
2618
2650
|
var absent = (value) => value === undefined || value === null;
|
|
2619
2651
|
var isPlainObject = (value) => {
|
|
@@ -2639,22 +2671,22 @@ var carries = (declared, recorded) => {
|
|
|
2639
2671
|
}
|
|
2640
2672
|
return true;
|
|
2641
2673
|
};
|
|
2642
|
-
var wholeDeclaration = (fqn, props) =>
|
|
2674
|
+
var wholeDeclaration = (fqn, props) => Effect33.map(Effect33.serviceOption(Stack), (stack) => {
|
|
2643
2675
|
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
2644
2676
|
return declared !== undefined && carries(declared.Props, props);
|
|
2645
2677
|
});
|
|
2646
2678
|
|
|
2647
2679
|
// src/ownership/rows.ts
|
|
2648
|
-
var storeOf =
|
|
2649
|
-
const stack = yield*
|
|
2650
|
-
const state = yield*
|
|
2680
|
+
var storeOf = Effect34.gen(function* () {
|
|
2681
|
+
const stack = yield* Effect34.serviceOption(Stack2);
|
|
2682
|
+
const state = yield* Effect34.serviceOption(State);
|
|
2651
2683
|
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
2652
2684
|
return;
|
|
2653
2685
|
const store = yield* state.value;
|
|
2654
2686
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
2655
2687
|
return { resources: stack.value.resources, store, where };
|
|
2656
2688
|
});
|
|
2657
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
2689
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect34.orElseSucceed(() => {
|
|
2658
2690
|
return;
|
|
2659
2691
|
}));
|
|
2660
2692
|
var generationOf = (row, instanceId) => {
|
|
@@ -2667,7 +2699,7 @@ var generationOf = (row, instanceId) => {
|
|
|
2667
2699
|
}
|
|
2668
2700
|
return;
|
|
2669
2701
|
};
|
|
2670
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
2702
|
+
var recordedGeneration = (fqn, instanceId) => Effect34.gen(function* () {
|
|
2671
2703
|
const found = yield* storeOf;
|
|
2672
2704
|
if (found === undefined)
|
|
2673
2705
|
return;
|
|
@@ -2678,14 +2710,14 @@ var recordedGeneration = (fqn, instanceId) => Effect33.gen(function* () {
|
|
|
2678
2710
|
}
|
|
2679
2711
|
return;
|
|
2680
2712
|
});
|
|
2681
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
2713
|
+
var recordedInstance = (fqn, instanceId) => Effect34.gen(function* () {
|
|
2682
2714
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
2683
2715
|
if (generation === undefined)
|
|
2684
2716
|
return "absent";
|
|
2685
2717
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
2686
2718
|
});
|
|
2687
|
-
var isCreate = (fqn, instanceId) =>
|
|
2688
|
-
var forgetRefusedCreate = (fqn, instanceId) =>
|
|
2719
|
+
var isCreate = (fqn, instanceId) => Effect34.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
2720
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect34.gen(function* () {
|
|
2689
2721
|
const found = yield* storeOf;
|
|
2690
2722
|
if (found === undefined)
|
|
2691
2723
|
return;
|
|
@@ -2694,32 +2726,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect33.gen(function* () {
|
|
|
2694
2726
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
2695
2727
|
return;
|
|
2696
2728
|
}
|
|
2697
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
2729
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect34.ignore);
|
|
2698
2730
|
});
|
|
2699
2731
|
|
|
2700
2732
|
// src/ownership/adopt.ts
|
|
2701
|
-
var adoptEnabled = (fqn) =>
|
|
2702
|
-
const stack = yield*
|
|
2733
|
+
var adoptEnabled = (fqn) => Effect35.gen(function* () {
|
|
2734
|
+
const stack = yield* Effect35.serviceOption(Stack3);
|
|
2703
2735
|
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
2704
2736
|
if (scoped !== undefined)
|
|
2705
2737
|
return scoped;
|
|
2706
|
-
const policy = yield*
|
|
2738
|
+
const policy = yield* Effect35.serviceOption(AdoptPolicy);
|
|
2707
2739
|
if (Option5.isSome(policy))
|
|
2708
2740
|
return policy.value;
|
|
2709
|
-
const context = yield*
|
|
2741
|
+
const context = yield* Effect35.serviceOption(AlchemyContext);
|
|
2710
2742
|
return Option5.isSome(context) ? context.value.adopt : false;
|
|
2711
2743
|
});
|
|
2712
|
-
var adoptable = (owner) =>
|
|
2744
|
+
var adoptable = (owner) => Effect35.gen(function* () {
|
|
2713
2745
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
2714
2746
|
return true;
|
|
2715
2747
|
return yield* unfinished(owner.instanceId);
|
|
2716
2748
|
});
|
|
2717
|
-
var adoptsAtApply = (owner) =>
|
|
2749
|
+
var adoptsAtApply = (owner) => Effect35.gen(function* () {
|
|
2718
2750
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
2719
2751
|
return false;
|
|
2720
2752
|
return yield* adoptable(owner);
|
|
2721
2753
|
});
|
|
2722
|
-
var refuseTakeover = (owner, what) =>
|
|
2754
|
+
var refuseTakeover = (owner, what) => Effect35.gen(function* () {
|
|
2723
2755
|
if (owner.output !== undefined)
|
|
2724
2756
|
return;
|
|
2725
2757
|
if (yield* resumes(owner.instanceId))
|
|
@@ -2729,25 +2761,25 @@ var refuseTakeover = (owner, what) => Effect34.gen(function* () {
|
|
|
2729
2761
|
return;
|
|
2730
2762
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
2731
2763
|
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.";
|
|
2732
|
-
return yield*
|
|
2764
|
+
return yield* Effect35.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}`));
|
|
2733
2765
|
});
|
|
2734
2766
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
2735
2767
|
|
|
2736
2768
|
// src/ownership/probe.ts
|
|
2737
2769
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
2738
|
-
import * as
|
|
2739
|
-
var provenOurs = (ask, settled2) =>
|
|
2770
|
+
import * as Effect36 from "effect/Effect";
|
|
2771
|
+
var provenOurs = (ask, settled2) => Effect36.gen(function* () {
|
|
2740
2772
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
2741
2773
|
if (recorded === "absent")
|
|
2742
2774
|
return false;
|
|
2743
2775
|
if (recorded === "partial") {
|
|
2744
|
-
yield*
|
|
2776
|
+
yield* Effect36.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");
|
|
2745
2777
|
return false;
|
|
2746
2778
|
}
|
|
2747
|
-
const unproven = (reason) =>
|
|
2748
|
-
return yield* settled2.pipe(
|
|
2779
|
+
const unproven = (reason) => Effect36.as(Effect36.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);
|
|
2780
|
+
return yield* settled2.pipe(Effect36.catch(unproven), Effect36.catchDefect(unproven));
|
|
2749
2781
|
});
|
|
2750
|
-
var ownedRead = (ask, found, settled2) =>
|
|
2782
|
+
var ownedRead = (ask, found, settled2) => Effect36.gen(function* () {
|
|
2751
2783
|
if (found === undefined || ask.output !== undefined)
|
|
2752
2784
|
return found;
|
|
2753
2785
|
return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
|
|
@@ -2805,8 +2837,8 @@ var optionMap = (value, family, defaultKey) => {
|
|
|
2805
2837
|
return out;
|
|
2806
2838
|
};
|
|
2807
2839
|
var sameMap = (left, right) => left.size === right.size && [...left].every(([key, value]) => right.get(key) === value);
|
|
2808
|
-
var sortedForm = (
|
|
2809
|
-
var printMap = (
|
|
2840
|
+
var sortedForm = (map14) => [...map14].map(([key, value]) => `${key}=${value}`).sort().join(",");
|
|
2841
|
+
var printMap = (map14, lead = []) => [...lead.filter((key) => map14.has(key)), ...[...map14.keys()].filter((k) => !lead.includes(k))].map((key) => `${key}=${map14.get(key) ?? ""}`).join(",");
|
|
2810
2842
|
var netMaps = (declared, live) => {
|
|
2811
2843
|
const want = optionMap(declared, "net");
|
|
2812
2844
|
const have = optionMap(live, "net");
|
|
@@ -3202,11 +3234,11 @@ var identityRefusals = (news, olds, output) => {
|
|
|
3202
3234
|
};
|
|
3203
3235
|
|
|
3204
3236
|
// src/proxmox/lxc-adoption.ts
|
|
3205
|
-
import * as
|
|
3237
|
+
import * as Effect41 from "effect/Effect";
|
|
3206
3238
|
|
|
3207
3239
|
// src/ownership/adopting.ts
|
|
3208
|
-
import * as
|
|
3209
|
-
var adopting = (owner, settled2) =>
|
|
3240
|
+
import * as Effect37 from "effect/Effect";
|
|
3241
|
+
var adopting = (owner, settled2) => Effect37.gen(function* () {
|
|
3210
3242
|
if (owner.output === undefined)
|
|
3211
3243
|
return false;
|
|
3212
3244
|
const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
|
|
@@ -3218,7 +3250,7 @@ var adopting = (owner, settled2) => Effect36.gen(function* () {
|
|
|
3218
3250
|
});
|
|
3219
3251
|
|
|
3220
3252
|
// src/proxmox/lxc-lifecycle.ts
|
|
3221
|
-
import * as
|
|
3253
|
+
import * as Effect40 from "effect/Effect";
|
|
3222
3254
|
import * as nodes10 from "@distilled.cloud/proxmox/nodes";
|
|
3223
3255
|
|
|
3224
3256
|
// src/proxmox/lxc-errors.ts
|
|
@@ -3227,44 +3259,44 @@ class LxcRefusedError extends Error {
|
|
|
3227
3259
|
}
|
|
3228
3260
|
|
|
3229
3261
|
// src/proxmox/lxc-read.ts
|
|
3230
|
-
import * as
|
|
3262
|
+
import * as cluster5 from "@distilled.cloud/proxmox/cluster";
|
|
3231
3263
|
import * as nodes8 from "@distilled.cloud/proxmox/nodes";
|
|
3232
|
-
import * as
|
|
3233
|
-
var readLive = (where) =>
|
|
3264
|
+
import * as Effect38 from "effect/Effect";
|
|
3265
|
+
var readLive = (where) => Effect38.gen(function* () {
|
|
3234
3266
|
const credential = yield* leased(where.target, "read");
|
|
3235
|
-
const answer = yield* runPveWith(where.target, credential, false, nodes8.getNodeLxcConfig({ node: where.node, vmid: String(where.vmid) })).pipe(
|
|
3267
|
+
const answer = yield* runPveWith(where.target, credential, false, nodes8.getNodeLxcConfig({ node: where.node, vmid: String(where.vmid) })).pipe(Effect38.map((data) => ({ data, error: undefined })), Effect38.catchTag("LxcConfigNotFound", (error) => Effect38.succeed({ data: undefined, error })));
|
|
3236
3268
|
if (answer.error === undefined) {
|
|
3237
3269
|
const live = answer.data;
|
|
3238
3270
|
if (live === null || typeof live !== "object" || Array.isArray(live) || !("digest" in live) || typeof live.digest !== "string" || live.digest === "") {
|
|
3239
|
-
return yield*
|
|
3271
|
+
return yield* Effect38.fail(new LxcRefusedError(`CT ${String(where.vmid)}: config read did not return a valid digest-bearing config.`));
|
|
3240
3272
|
}
|
|
3241
3273
|
return live;
|
|
3242
3274
|
}
|
|
3243
|
-
const rows = yield* runPveWith(where.target, credential, false,
|
|
3275
|
+
const rows = yield* runPveWith(where.target, credential, false, cluster5.listClusterResources({ type: "vm" }));
|
|
3244
3276
|
if (!Array.isArray(rows) || rows.some((row) => !Number.isSafeInteger(Number(row?.vmid)) || Number(row?.vmid) <= 0 || typeof row?.node !== "string" || row.node === "" || !["lxc", "qemu"].includes(row.type))) {
|
|
3245
|
-
return yield*
|
|
3277
|
+
return yield* Effect38.fail(new LxcRefusedError("The cluster guest index did not identify its rows."));
|
|
3246
3278
|
}
|
|
3247
3279
|
const found = rows.find((row) => Number(row.vmid) === where.vmid);
|
|
3248
3280
|
if (found !== undefined && found.node === where.node && found.type === "lxc") {
|
|
3249
|
-
return yield*
|
|
3281
|
+
return yield* Effect38.fail(answer.error);
|
|
3250
3282
|
}
|
|
3251
3283
|
if (found !== undefined) {
|
|
3252
|
-
return yield*
|
|
3284
|
+
return yield* Effect38.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."));
|
|
3253
3285
|
}
|
|
3254
3286
|
return;
|
|
3255
3287
|
});
|
|
3256
3288
|
|
|
3257
3289
|
// src/proxmox/lxc-task.ts
|
|
3258
3290
|
import * as nodes9 from "@distilled.cloud/proxmox/nodes";
|
|
3259
|
-
import * as
|
|
3260
|
-
var lxcTask = (where, operation, what, polls) =>
|
|
3291
|
+
import * as Effect39 from "effect/Effect";
|
|
3292
|
+
var lxcTask = (where, operation, what, polls) => Effect39.gen(function* () {
|
|
3261
3293
|
const credential = yield* mint(where.target, "provision");
|
|
3262
3294
|
const upid = text(yield* runPveWith(where.target, credential, true, operation));
|
|
3263
3295
|
if (upid === "")
|
|
3264
|
-
return yield*
|
|
3296
|
+
return yield* Effect39.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
3265
3297
|
let exit = "still running when this provider stopped waiting";
|
|
3266
3298
|
for (let attempt = 0;attempt < polls; attempt++) {
|
|
3267
|
-
const status = yield* runPveWith(where.target, credential, false, nodes9.getNodeTaskStatus({ node: where.node, upid })).pipe(
|
|
3299
|
+
const status = yield* runPveWith(where.target, credential, false, nodes9.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect39.orElseSucceed(() => {
|
|
3268
3300
|
return;
|
|
3269
3301
|
}));
|
|
3270
3302
|
if (status === undefined || status.status === undefined) {
|
|
@@ -3275,10 +3307,10 @@ var lxcTask = (where, operation, what, polls) => Effect38.gen(function* () {
|
|
|
3275
3307
|
exit = text(status.exitstatus, "stopped with no exitstatus");
|
|
3276
3308
|
break;
|
|
3277
3309
|
}
|
|
3278
|
-
yield*
|
|
3310
|
+
yield* Effect39.sleep("1 second");
|
|
3279
3311
|
}
|
|
3280
3312
|
if (exit !== "OK")
|
|
3281
|
-
return yield*
|
|
3313
|
+
return yield* Effect39.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
|
|
3282
3314
|
});
|
|
3283
3315
|
|
|
3284
3316
|
// src/proxmox/lxc-lifecycle.ts
|
|
@@ -3289,13 +3321,13 @@ var LXC_ENDPOINTS = {
|
|
|
3289
3321
|
};
|
|
3290
3322
|
var CREATE_POLLS = 180;
|
|
3291
3323
|
var TASK_POLLS = 60;
|
|
3292
|
-
var
|
|
3324
|
+
var attributesOf6 = (where, live) => ({
|
|
3293
3325
|
config: storedConfig(live),
|
|
3294
3326
|
node: where.node,
|
|
3295
3327
|
rawKeys: rawKeysOf(live),
|
|
3296
3328
|
vmid: where.vmid
|
|
3297
3329
|
});
|
|
3298
|
-
var createGuest = (props) =>
|
|
3330
|
+
var createGuest = (props) => Effect40.gen(function* () {
|
|
3299
3331
|
const form = createForm4(props);
|
|
3300
3332
|
yield* guardForm(LXC_ENDPOINTS.create, form, true);
|
|
3301
3333
|
return yield* lxcTask(props, nodes10.createNodeLxc({
|
|
@@ -3305,7 +3337,7 @@ var createGuest = (props) => Effect39.gen(function* () {
|
|
|
3305
3337
|
ostemplate: text(form["ostemplate"])
|
|
3306
3338
|
}), `create CT ${String(props.vmid)}`, CREATE_POLLS);
|
|
3307
3339
|
});
|
|
3308
|
-
var updateGuest = (props, change, digest) =>
|
|
3340
|
+
var updateGuest = (props, change, digest) => Effect40.gen(function* () {
|
|
3309
3341
|
if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
|
|
3310
3342
|
const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
|
|
3311
3343
|
yield* guardForm(LXC_ENDPOINTS.update, form, false);
|
|
@@ -3317,47 +3349,47 @@ var updateGuest = (props, change, digest) => Effect39.gen(function* () {
|
|
|
3317
3349
|
yield* lxcTask(props, nodes10.putNodeLxcResize({ ...grown, node: props.node, vmid: String(props.vmid) }), `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS);
|
|
3318
3350
|
}
|
|
3319
3351
|
});
|
|
3320
|
-
var destroyGuest = (where, declared) =>
|
|
3352
|
+
var destroyGuest = (where, declared) => Effect40.gen(function* () {
|
|
3321
3353
|
const live = yield* readLive(where);
|
|
3322
3354
|
if (live === undefined)
|
|
3323
3355
|
return;
|
|
3324
3356
|
const drift = judge(declared, live).drift;
|
|
3325
3357
|
if (drift.length > 0) {
|
|
3326
|
-
return yield*
|
|
3358
|
+
return yield* Effect40.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."));
|
|
3327
3359
|
}
|
|
3328
3360
|
yield* lxcTask(where, nodes10.deleteNodeLxc({ node: where.node, vmid: String(where.vmid) }), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
|
|
3329
3361
|
});
|
|
3330
3362
|
|
|
3331
3363
|
// src/proxmox/lxc-adoption.ts
|
|
3332
3364
|
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.";
|
|
3333
|
-
var refuseAdoptedDrift = (owner, props, live, change) =>
|
|
3365
|
+
var refuseAdoptedDrift = (owner, props, live, change) => Effect41.gen(function* () {
|
|
3334
3366
|
if (change.drift.length === 0)
|
|
3335
3367
|
return;
|
|
3336
|
-
const settled2 = (recorded) =>
|
|
3368
|
+
const settled2 = (recorded) => Effect41.sync(() => judge(recorded, live).drift.length === 0);
|
|
3337
3369
|
if (!(yield* adopting(owner, settled2)))
|
|
3338
3370
|
return;
|
|
3339
|
-
return yield*
|
|
3371
|
+
return yield* Effect41.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
|
|
3340
3372
|
});
|
|
3341
3373
|
|
|
3342
3374
|
// src/proxmox/lxc.ts
|
|
3343
3375
|
var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
|
|
3344
|
-
var refused = (reasons) =>
|
|
3376
|
+
var refused = (reasons) => Effect42.fail(new LxcRefusedError(reasons.join(`
|
|
3345
3377
|
`)));
|
|
3346
|
-
var diff = (owner, news, olds) =>
|
|
3378
|
+
var diff = (owner, news, olds) => Effect42.gen(function* () {
|
|
3347
3379
|
const { output } = owner;
|
|
3348
3380
|
const identity2 = identityRefusals(news, olds, output);
|
|
3349
3381
|
if (identity2.length > 0)
|
|
3350
3382
|
return yield* refused(identity2);
|
|
3351
3383
|
if (output === undefined)
|
|
3352
3384
|
return;
|
|
3353
|
-
if (!
|
|
3385
|
+
if (!isResolved12(news))
|
|
3354
3386
|
return;
|
|
3355
3387
|
const live = yield* readLive(news);
|
|
3356
3388
|
if (live === undefined) {
|
|
3357
3389
|
const refusals = createRefusals(news);
|
|
3358
3390
|
if (refusals.length > 0)
|
|
3359
3391
|
return yield* refused(refusals);
|
|
3360
|
-
yield*
|
|
3392
|
+
yield* Effect42.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.");
|
|
3361
3393
|
return { action: "update" };
|
|
3362
3394
|
}
|
|
3363
3395
|
const change = judge(news, live);
|
|
@@ -3368,10 +3400,10 @@ var diff = (owner, news, olds) => Effect41.gen(function* () {
|
|
|
3368
3400
|
if (change.drift.length === 0 && !moved)
|
|
3369
3401
|
return { action: "noop" };
|
|
3370
3402
|
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.";
|
|
3371
|
-
yield*
|
|
3403
|
+
yield* Effect42.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
|
|
3372
3404
|
return { action: "update" };
|
|
3373
3405
|
});
|
|
3374
|
-
var reconcile = (owner, news) =>
|
|
3406
|
+
var reconcile = (owner, news) => Effect42.gen(function* () {
|
|
3375
3407
|
const { output } = owner;
|
|
3376
3408
|
const identity2 = identityRefusals(news, news, output);
|
|
3377
3409
|
if (identity2.length > 0)
|
|
@@ -3410,22 +3442,22 @@ var reconcile = (owner, news) => Effect41.gen(function* () {
|
|
|
3410
3442
|
`CT ${String(news.vmid)}: after the write, ${left.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value (tags are lower-cased by default) -- " + "declare what it stores."
|
|
3411
3443
|
]);
|
|
3412
3444
|
}
|
|
3413
|
-
return
|
|
3445
|
+
return attributesOf6(news, after);
|
|
3414
3446
|
});
|
|
3415
3447
|
var whereOf = (olds, output) => ({
|
|
3416
3448
|
node: output?.node ?? olds.node,
|
|
3417
3449
|
target: olds.target,
|
|
3418
3450
|
vmid: output?.vmid ?? olds.vmid
|
|
3419
3451
|
});
|
|
3420
|
-
var read = (owner, olds) =>
|
|
3452
|
+
var read = (owner, olds) => Effect42.gen(function* () {
|
|
3421
3453
|
const where = whereOf(olds, owner.output);
|
|
3422
3454
|
const live = yield* readLive(where);
|
|
3423
3455
|
if (live === undefined)
|
|
3424
3456
|
return;
|
|
3425
|
-
const settled2 =
|
|
3426
|
-
return yield* ownedRead(owner,
|
|
3457
|
+
const settled2 = Effect42.sync(() => judge(olds, live).drift.length === 0);
|
|
3458
|
+
return yield* ownedRead(owner, attributesOf6(where, live), settled2);
|
|
3427
3459
|
});
|
|
3428
|
-
var
|
|
3460
|
+
var handlers4 = {
|
|
3429
3461
|
delete: ({ olds, output }) => destroyGuest(whereOf(olds, output), olds),
|
|
3430
3462
|
diff: ({
|
|
3431
3463
|
fqn,
|
|
@@ -3434,7 +3466,7 @@ var handlers5 = {
|
|
|
3434
3466
|
olds,
|
|
3435
3467
|
output
|
|
3436
3468
|
}) => diff({ fqn, instanceId, output }, news, olds),
|
|
3437
|
-
list: () =>
|
|
3469
|
+
list: () => Effect42.succeed([]),
|
|
3438
3470
|
read: ({
|
|
3439
3471
|
fqn,
|
|
3440
3472
|
instanceId,
|
|
@@ -3448,11 +3480,11 @@ var handlers5 = {
|
|
|
3448
3480
|
output
|
|
3449
3481
|
}) => reconcile({ fqn, instanceId, output }, news)
|
|
3450
3482
|
};
|
|
3451
|
-
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc,
|
|
3483
|
+
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect42.succeed(ProxmoxLxc.Provider.of(handlers4)).pipe(Effect42.map(provingResumes)));
|
|
3452
3484
|
// src/proxmox/metric-server.ts
|
|
3453
3485
|
import { Resource as Resource14 } from "alchemy";
|
|
3454
|
-
import { isResolved as
|
|
3455
|
-
import * as
|
|
3486
|
+
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
3487
|
+
import * as cluster7 from "@distilled.cloud/proxmox/cluster";
|
|
3456
3488
|
|
|
3457
3489
|
// src/proxmox/metric-server-form.ts
|
|
3458
3490
|
var UNSET2 = -1;
|
|
@@ -3566,15 +3598,15 @@ var metricServerSpec = {
|
|
|
3566
3598
|
};
|
|
3567
3599
|
|
|
3568
3600
|
// src/proxmox/metric-server-distilled.ts
|
|
3569
|
-
import * as
|
|
3601
|
+
import * as cluster6 from "@distilled.cloud/proxmox/cluster";
|
|
3570
3602
|
import { ProxmoxParseError as ProxmoxParseError3 } from "@distilled.cloud/proxmox/Errors";
|
|
3571
|
-
import * as
|
|
3603
|
+
import * as Effect43 from "effect/Effect";
|
|
3572
3604
|
import * as Schema2 from "effect/Schema";
|
|
3573
|
-
var readMetricServerRow = (props) => runPve(props.target, "read", false,
|
|
3605
|
+
var readMetricServerRow = (props) => runPve(props.target, "read", false, cluster6.getClusterMetricsServer({ id: props.id })).pipe(Effect43.flatMap((body4) => Schema2.decodeUnknownEffect(Schema2.Record(Schema2.String, Schema2.Unknown))(body4).pipe(Effect43.mapError(() => new ProxmoxParseError3({
|
|
3574
3606
|
body: undefined,
|
|
3575
3607
|
cause: "Metric server response must be an object"
|
|
3576
|
-
})))),
|
|
3577
|
-
var readMetricServer = (props) => readMetricServerRow(props).pipe(
|
|
3608
|
+
})))), Effect43.catchTag("MetricServerNotFound", () => Effect43.succeed(undefined)), Effect43.catchTag("NotFound", () => Effect43.succeed(undefined)));
|
|
3609
|
+
var readMetricServer = (props) => readMetricServerRow(props).pipe(Effect43.map((row) => row === undefined ? undefined : metricServerSpec.attributes(row, props)));
|
|
3578
3610
|
var metricServerRequest = (props, form) => ({
|
|
3579
3611
|
...asForm2({
|
|
3580
3612
|
api_path_prefix: form["api-path-prefix"],
|
|
@@ -3599,22 +3631,22 @@ var metricServerRequest = (props, form) => ({
|
|
|
3599
3631
|
port: String(props.port),
|
|
3600
3632
|
server: props.server
|
|
3601
3633
|
});
|
|
3602
|
-
var deleteMetricServer = (props) =>
|
|
3634
|
+
var deleteMetricServer = (props) => Effect43.gen(function* () {
|
|
3603
3635
|
if ((yield* readMetricServerRow(props)) === undefined)
|
|
3604
3636
|
return;
|
|
3605
|
-
yield* runPve(props.target, "provision", true,
|
|
3637
|
+
yield* runPve(props.target, "provision", true, cluster6.deleteClusterMetricsServer({ id: props.id }));
|
|
3606
3638
|
});
|
|
3607
3639
|
|
|
3608
3640
|
// src/proxmox/metric-server.ts
|
|
3609
3641
|
import * as Provider14 from "alchemy/Provider";
|
|
3610
|
-
import * as
|
|
3642
|
+
import * as Effect44 from "effect/Effect";
|
|
3611
3643
|
var ProxmoxMetricServer = Resource14("Proxmox.MetricServer");
|
|
3612
3644
|
var { guardCreate: guardCreate3, guardUpdate: guardUpdate3 } = specGuards(metricServerSpec);
|
|
3613
|
-
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer,
|
|
3614
|
-
list: () =>
|
|
3645
|
+
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect44.succeed(ProxmoxMetricServer.Provider.of({
|
|
3646
|
+
list: () => Effect44.succeed([]),
|
|
3615
3647
|
read: ({ olds }) => readMetricServer(olds),
|
|
3616
|
-
diff:
|
|
3617
|
-
if (!
|
|
3648
|
+
diff: Effect44.fn(function* ({ news, output }) {
|
|
3649
|
+
if (!isResolved13(news))
|
|
3618
3650
|
return;
|
|
3619
3651
|
yield* guardCreate3(news, output === undefined);
|
|
3620
3652
|
yield* guardUpdate3(news);
|
|
@@ -3627,36 +3659,36 @@ var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, E
|
|
|
3627
3659
|
}
|
|
3628
3660
|
return { action: metricServerSpec.matches(live, news) ? "noop" : "update" };
|
|
3629
3661
|
}),
|
|
3630
|
-
reconcile:
|
|
3662
|
+
reconcile: Effect44.fn(function* ({ news }) {
|
|
3631
3663
|
const live = yield* readMetricServer(news);
|
|
3632
3664
|
yield* guardCreate3(news, live === undefined);
|
|
3633
3665
|
yield* guardUpdate3(news);
|
|
3634
3666
|
if (live === undefined) {
|
|
3635
|
-
yield* runPve(news.target, "provision", true,
|
|
3667
|
+
yield* runPve(news.target, "provision", true, cluster7.updateClusterMetricsServer({
|
|
3636
3668
|
...metricServerRequest(news, metricServerSpec.createForm(news)),
|
|
3637
3669
|
type: news.type
|
|
3638
3670
|
}));
|
|
3639
3671
|
} else {
|
|
3640
3672
|
const form = formToSend(metricServerSpec.matches, live, news, metricServerSpec.updateForm(news));
|
|
3641
3673
|
if (form !== undefined)
|
|
3642
|
-
yield* runPve(news.target, "provision", true,
|
|
3674
|
+
yield* runPve(news.target, "provision", true, cluster7.putClusterMetricsServer(metricServerRequest(news, form)));
|
|
3643
3675
|
}
|
|
3644
3676
|
const after = yield* readMetricServer(news);
|
|
3645
3677
|
if (after === undefined)
|
|
3646
|
-
return yield*
|
|
3678
|
+
return yield* Effect44.fail(new Error(`${metricServerSpec.path(news)}: write returned success but the resource is still absent`));
|
|
3647
3679
|
return after;
|
|
3648
3680
|
}),
|
|
3649
3681
|
delete: ({ olds }) => deleteMetricServer(olds)
|
|
3650
3682
|
})));
|
|
3651
3683
|
// src/proxmox/network-apply.ts
|
|
3652
3684
|
import { Resource as Resource15 } from "alchemy";
|
|
3653
|
-
import { isResolved as
|
|
3685
|
+
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
3654
3686
|
import * as Provider15 from "alchemy/Provider";
|
|
3655
|
-
import * as
|
|
3687
|
+
import * as Effect47 from "effect/Effect";
|
|
3656
3688
|
|
|
3657
3689
|
// src/proxmox/network-apply-run.ts
|
|
3658
3690
|
import * as nodes12 from "@distilled.cloud/proxmox/nodes";
|
|
3659
|
-
import * as
|
|
3691
|
+
import * as Effect46 from "effect/Effect";
|
|
3660
3692
|
|
|
3661
3693
|
// src/proxmox/apply-endpoints.ts
|
|
3662
3694
|
var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
|
|
@@ -3665,10 +3697,10 @@ var guardNetworkApply = guardForm(NETWORK_APPLY_ENDPOINT, {}, true);
|
|
|
3665
3697
|
var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
|
|
3666
3698
|
|
|
3667
3699
|
// src/proxmox/network-apply-read.ts
|
|
3668
|
-
import * as
|
|
3700
|
+
import * as cluster8 from "@distilled.cloud/proxmox/cluster";
|
|
3669
3701
|
import * as nodes11 from "@distilled.cloud/proxmox/nodes";
|
|
3670
|
-
import * as
|
|
3671
|
-
var stagedDiff = (target, node) =>
|
|
3702
|
+
import * as Effect45 from "effect/Effect";
|
|
3703
|
+
var stagedDiff = (target, node) => Effect45.gen(function* () {
|
|
3672
3704
|
const credential = yield* leased(target, "read");
|
|
3673
3705
|
const live = yield* runPveWith(target, credential, false, nodes11.listNodeNetwork({ node }));
|
|
3674
3706
|
return Array.isArray(live) ? "" : live.changes;
|
|
@@ -3680,36 +3712,36 @@ var pendingLines = (diff2) => {
|
|
|
3680
3712
|
`).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
|
|
3681
3713
|
return Math.max(changed, 1);
|
|
3682
3714
|
};
|
|
3683
|
-
var pendingCount = (target, node) => stagedDiff(target, node).pipe(
|
|
3684
|
-
var clusterHealth = (target) => runPve(target, "read", false,
|
|
3715
|
+
var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect45.map(pendingLines));
|
|
3716
|
+
var clusterHealth = (target) => runPve(target, "read", false, cluster8.listClusterStatus({})).pipe(Effect45.map((rows) => {
|
|
3685
3717
|
const all = rows ?? [];
|
|
3686
|
-
const
|
|
3718
|
+
const cluster9 = all.find((row) => row.type === "cluster");
|
|
3687
3719
|
return {
|
|
3688
3720
|
offline: all.filter((row) => row.type === "node" && !bool(row.online)).map((row) => text(row.name, "<unnamed>")),
|
|
3689
|
-
quorate:
|
|
3721
|
+
quorate: cluster9 === undefined ? true : bool(cluster9.quorate)
|
|
3690
3722
|
};
|
|
3691
3723
|
}));
|
|
3692
|
-
var degradedReason = (target) => clusterHealth(target).pipe(
|
|
3724
|
+
var degradedReason = (target) => clusterHealth(target).pipe(Effect45.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
|
|
3693
3725
|
var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
3694
3726
|
var STILL_RUNNING = "still running when this provider stopped waiting";
|
|
3695
3727
|
var ATTEMPTS = 30;
|
|
3696
|
-
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) =>
|
|
3728
|
+
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect45.gen(function* () {
|
|
3697
3729
|
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
3698
|
-
const status = yield* runPveWith(target, credential, false, nodes11.getNodeTaskStatus({ node, upid })).pipe(
|
|
3730
|
+
const status = yield* runPveWith(target, credential, false, nodes11.getNodeTaskStatus({ node, upid })).pipe(Effect45.orElseSucceed(() => {
|
|
3699
3731
|
return;
|
|
3700
3732
|
}));
|
|
3701
3733
|
if (status === undefined)
|
|
3702
3734
|
return UNREACHABLE;
|
|
3703
3735
|
if (status.status === "stopped")
|
|
3704
3736
|
return text(status.exitstatus, "stopped with no exitstatus");
|
|
3705
|
-
yield*
|
|
3737
|
+
yield* Effect45.sleep("1 second");
|
|
3706
3738
|
}
|
|
3707
3739
|
return STILL_RUNNING;
|
|
3708
3740
|
});
|
|
3709
3741
|
|
|
3710
3742
|
// src/proxmox/network-apply-run.ts
|
|
3711
|
-
var refuse = (node, why) =>
|
|
3712
|
-
var applyNetwork = (props) =>
|
|
3743
|
+
var refuse = (node, why) => Effect46.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
|
|
3744
|
+
var applyNetwork = (props) => Effect46.gen(function* () {
|
|
3713
3745
|
const node = props.node;
|
|
3714
3746
|
const staged = yield* pendingCount(props.target, node);
|
|
3715
3747
|
if (staged === 0)
|
|
@@ -3741,27 +3773,27 @@ var applyNetwork = (props) => Effect45.gen(function* () {
|
|
|
3741
3773
|
|
|
3742
3774
|
// src/proxmox/network-apply.ts
|
|
3743
3775
|
var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
|
|
3744
|
-
var read2 = (props) => pendingCount(props.target, props.node).pipe(
|
|
3745
|
-
var diff2 = (news) =>
|
|
3746
|
-
if (!
|
|
3776
|
+
var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect47.map((pending) => ({ node: props.node, pending })));
|
|
3777
|
+
var diff2 = (news) => Effect47.gen(function* () {
|
|
3778
|
+
if (!isResolved14(news))
|
|
3747
3779
|
return;
|
|
3748
3780
|
const { pending } = yield* read2(news);
|
|
3749
3781
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3750
3782
|
});
|
|
3751
|
-
var
|
|
3752
|
-
delete: () =>
|
|
3783
|
+
var handlers5 = {
|
|
3784
|
+
delete: () => Effect47.void,
|
|
3753
3785
|
diff: ({ news }) => diff2(news),
|
|
3754
|
-
list: () =>
|
|
3786
|
+
list: () => Effect47.succeed([]),
|
|
3755
3787
|
read: ({ olds }) => read2(olds),
|
|
3756
3788
|
reconcile: ({ news }) => applyNetwork(news)
|
|
3757
3789
|
};
|
|
3758
|
-
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply,
|
|
3790
|
+
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect47.succeed(ProxmoxNetworkApply.Provider.of(handlers5)));
|
|
3759
3791
|
// src/proxmox/node-network.ts
|
|
3760
3792
|
import { Resource as Resource16 } from "alchemy";
|
|
3761
|
-
import { isResolved as
|
|
3793
|
+
import { isResolved as isResolved15 } from "alchemy/Diff";
|
|
3762
3794
|
import * as Provider16 from "alchemy/Provider";
|
|
3763
3795
|
import * as nodes14 from "@distilled.cloud/proxmox/nodes";
|
|
3764
|
-
import * as
|
|
3796
|
+
import * as Effect49 from "effect/Effect";
|
|
3765
3797
|
|
|
3766
3798
|
// src/proxmox/node-network-form.ts
|
|
3767
3799
|
var NODE_NETWORK_CREATE = "pve:POST /nodes/{node}/network";
|
|
@@ -3794,7 +3826,7 @@ var createForm5 = (props) => ({
|
|
|
3794
3826
|
...body4(props),
|
|
3795
3827
|
iface: props.iface
|
|
3796
3828
|
});
|
|
3797
|
-
var
|
|
3829
|
+
var updateForm3 = (props) => {
|
|
3798
3830
|
const clear = [
|
|
3799
3831
|
...props.cidr === undefined ? ["cidr"] : [],
|
|
3800
3832
|
...props.bridge_vlan_aware === false ? ["bridge_vlan_aware"] : []
|
|
@@ -3804,8 +3836,8 @@ var updateForm2 = (props) => {
|
|
|
3804
3836
|
|
|
3805
3837
|
// src/proxmox/node-network-wire.ts
|
|
3806
3838
|
import * as nodes13 from "@distilled.cloud/proxmox/nodes";
|
|
3807
|
-
import * as
|
|
3808
|
-
var
|
|
3839
|
+
import * as Effect48 from "effect/Effect";
|
|
3840
|
+
var attributesOf7 = (live, props) => {
|
|
3809
3841
|
const data = live;
|
|
3810
3842
|
const liveType = text(data["type"]);
|
|
3811
3843
|
if (liveType !== "" && liveType !== props.type)
|
|
@@ -3838,16 +3870,16 @@ var attributesOf6 = (live, props) => {
|
|
|
3838
3870
|
"vlan-raw-device": text(data["vlan-raw-device"])
|
|
3839
3871
|
};
|
|
3840
3872
|
};
|
|
3841
|
-
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes13.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(
|
|
3873
|
+
var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes13.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect48.catchTag("NetworkInterfaceNotFound", () => Effect48.succeed(undefined)))).pipe(Effect48.map((live) => {
|
|
3842
3874
|
if (live === UNREADABLE)
|
|
3843
3875
|
return UNREADABLE;
|
|
3844
|
-
return live === undefined ? undefined :
|
|
3876
|
+
return live === undefined ? undefined : attributesOf7(live, props);
|
|
3845
3877
|
}));
|
|
3846
|
-
var readInterface = (props) => readInterfaceOrFail(props).pipe(
|
|
3878
|
+
var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect48.orElseSucceed(() => {
|
|
3847
3879
|
return;
|
|
3848
3880
|
}));
|
|
3849
3881
|
var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
|
|
3850
|
-
var
|
|
3882
|
+
var matches6 = (attributes, props) => attributes.cidr === (props.cidr ?? "") && same2(props.gateway, attributes.gateway) && same2(props.autostart, attributes.autostart) && same2(props.mtu, attributes.mtu) && sameComment(props.comments, attributes.comments) && sameList(props.bridge_ports, attributes.bridge_ports) && sameList(props.bridge_vids, attributes.bridge_vids) && same2(props.bridge_vlan_aware, attributes.bridge_vlan_aware) && sameList(props.slaves, attributes.slaves) && same2(props.bond_mode, attributes.bond_mode) && same2(props.bond_xmit_hash_policy, attributes.bond_xmit_hash_policy) && same2(props["bond-primary"], attributes["bond-primary"]) && same2(props["vlan-id"], attributes["vlan-id"]) && same2(props["vlan-raw-device"], attributes["vlan-raw-device"]);
|
|
3851
3883
|
|
|
3852
3884
|
// src/proxmox/node-network.ts
|
|
3853
3885
|
var ProxmoxNodeNetwork = Resource16("Proxmox.NodeNetwork", {
|
|
@@ -3864,20 +3896,20 @@ var toDistilledCreate3 = (props) => ({
|
|
|
3864
3896
|
node: props.node
|
|
3865
3897
|
});
|
|
3866
3898
|
var toDistilledUpdate2 = (props) => ({
|
|
3867
|
-
...toDistilled(
|
|
3899
|
+
...toDistilled(updateForm3(props)),
|
|
3868
3900
|
iface: props.iface,
|
|
3869
3901
|
node: props.node
|
|
3870
3902
|
});
|
|
3871
|
-
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork,
|
|
3872
|
-
list: () =>
|
|
3873
|
-
read:
|
|
3903
|
+
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect49.succeed(ProxmoxNodeNetwork.Provider.of({
|
|
3904
|
+
list: () => Effect49.succeed([]),
|
|
3905
|
+
read: Effect49.fn(function* ({ olds, output }) {
|
|
3874
3906
|
return dropUnreadable4(yield* output === undefined ? readInterface(olds) : readInterfaceOrFail(olds));
|
|
3875
3907
|
}),
|
|
3876
|
-
diff:
|
|
3877
|
-
if (!
|
|
3908
|
+
diff: Effect49.fn(function* ({ news, output }) {
|
|
3909
|
+
if (!isResolved15(news))
|
|
3878
3910
|
return;
|
|
3879
3911
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), output === undefined);
|
|
3880
|
-
yield* guardWrite2(NODE_NETWORK_UPDATE,
|
|
3912
|
+
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm3(news), false);
|
|
3881
3913
|
if (output === undefined)
|
|
3882
3914
|
return;
|
|
3883
3915
|
const live = yield* readInterfaceOrFail(news);
|
|
@@ -3889,35 +3921,35 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
|
|
|
3889
3921
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), true);
|
|
3890
3922
|
return { action: "update" };
|
|
3891
3923
|
}
|
|
3892
|
-
return
|
|
3924
|
+
return matches6(live, news) ? { action: "noop" } : { action: "update" };
|
|
3893
3925
|
}),
|
|
3894
|
-
reconcile:
|
|
3926
|
+
reconcile: Effect49.fn(function* ({ news }) {
|
|
3895
3927
|
const before = dropUnreadable4(yield* readInterface(news));
|
|
3896
3928
|
yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), before === undefined);
|
|
3897
|
-
yield* guardWrite2(NODE_NETWORK_UPDATE,
|
|
3929
|
+
yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm3(news), false);
|
|
3898
3930
|
if (before === undefined) {
|
|
3899
3931
|
yield* runPve(news.target, "provision", true, nodes14.createNodeNetwork(toDistilledCreate3(news)));
|
|
3900
|
-
} else if (!
|
|
3932
|
+
} else if (!matches6(before, news)) {
|
|
3901
3933
|
yield* runPve(news.target, "provision", true, nodes14.putNodeNetwork2(toDistilledUpdate2(news)));
|
|
3902
3934
|
}
|
|
3903
3935
|
const after = dropUnreadable4(yield* readInterface(news));
|
|
3904
3936
|
if (after === undefined) {
|
|
3905
|
-
return yield*
|
|
3937
|
+
return yield* Effect49.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."));
|
|
3906
3938
|
}
|
|
3907
3939
|
return after;
|
|
3908
3940
|
}),
|
|
3909
|
-
delete:
|
|
3941
|
+
delete: Effect49.fn(function* ({ olds }) {
|
|
3910
3942
|
yield* runPve(olds.target, "provision", true, nodes14.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
|
|
3911
3943
|
})
|
|
3912
3944
|
})));
|
|
3913
3945
|
// src/proxmox/notification-matcher.ts
|
|
3914
3946
|
import { Resource as Resource17 } from "alchemy";
|
|
3915
3947
|
import * as Provider17 from "alchemy/Provider";
|
|
3916
|
-
import * as
|
|
3948
|
+
import * as Effect53 from "effect/Effect";
|
|
3917
3949
|
|
|
3918
3950
|
// src/proxmox/notification-matcher-lifecycle.ts
|
|
3919
|
-
import { isResolved as
|
|
3920
|
-
import * as
|
|
3951
|
+
import { isResolved as isResolved16 } from "alchemy/Diff";
|
|
3952
|
+
import * as Effect52 from "effect/Effect";
|
|
3921
3953
|
|
|
3922
3954
|
// src/proxmox/notification-matcher-form.ts
|
|
3923
3955
|
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
@@ -3994,49 +4026,49 @@ var matcherUpdateForm = (fields) => {
|
|
|
3994
4026
|
};
|
|
3995
4027
|
|
|
3996
4028
|
// src/proxmox/notification-matcher-distilled.ts
|
|
3997
|
-
import * as
|
|
3998
|
-
import * as
|
|
4029
|
+
import * as cluster9 from "@distilled.cloud/proxmox/cluster";
|
|
4030
|
+
import * as Effect51 from "effect/Effect";
|
|
3999
4031
|
|
|
4000
4032
|
// src/proxmox/notification-sdk-input.ts
|
|
4001
4033
|
import { ProxmoxParseError as ProxmoxParseError4 } from "@distilled.cloud/proxmox/Errors";
|
|
4002
4034
|
import * as Data2 from "effect/Data";
|
|
4003
|
-
import * as
|
|
4035
|
+
import * as Effect50 from "effect/Effect";
|
|
4004
4036
|
import * as Schema3 from "effect/Schema";
|
|
4005
4037
|
|
|
4006
4038
|
class NotificationRequestInvalid extends Data2.TaggedError("NotificationRequestInvalid") {
|
|
4007
4039
|
}
|
|
4008
|
-
var notificationRequest = (schema, fields) => Schema3.decodeUnknownEffect(Schema3.toType(schema), { onExcessProperty: "error" })(Object.fromEntries(Object.entries(fields).map(([key, value]) => [key.replaceAll("-", "_"), value]))).pipe(
|
|
4009
|
-
var notificationResponse = (schema) => (body5) => Schema3.decodeUnknownEffect(Schema3.toType(schema))(body5).pipe(
|
|
4040
|
+
var notificationRequest = (schema, fields) => Schema3.decodeUnknownEffect(Schema3.toType(schema), { onExcessProperty: "error" })(Object.fromEntries(Object.entries(fields).map(([key, value]) => [key.replaceAll("-", "_"), value]))).pipe(Effect50.mapError(() => new NotificationRequestInvalid({ operation: "PVE notification write" })));
|
|
4041
|
+
var notificationResponse = (schema) => (body5) => Schema3.decodeUnknownEffect(Schema3.toType(schema))(body5).pipe(Effect50.as(body5), Effect50.mapError(() => new ProxmoxParseError4({
|
|
4010
4042
|
body: undefined,
|
|
4011
4043
|
cause: "PVE notification response does not match its SDK schema"
|
|
4012
4044
|
})));
|
|
4013
4045
|
|
|
4014
4046
|
// src/proxmox/notification-matcher-distilled.ts
|
|
4015
|
-
var readMatcher = (props) => runPve(props.target, "read", false,
|
|
4047
|
+
var readMatcher = (props) => runPve(props.target, "read", false, cluster9.getClusterNotificationMatcher({ name: props.name })).pipe(Effect51.flatMap(notificationResponse(cluster9.GetClusterNotificationMatcherResponse)), Effect51.map((live) => matcherAttributes({
|
|
4016
4048
|
...live,
|
|
4017
4049
|
"invert-match": live.invert_match,
|
|
4018
4050
|
"match-calendar": live.match_calendar,
|
|
4019
4051
|
"match-field": live.match_field,
|
|
4020
4052
|
"match-severity": live.match_severity
|
|
4021
|
-
}, props.name)),
|
|
4022
|
-
var createMatcher = (props) =>
|
|
4023
|
-
const input = yield* notificationRequest(
|
|
4024
|
-
yield* runPve(props.target, "provision", true,
|
|
4053
|
+
}, props.name)), Effect51.catchTag("NotFound", () => Effect51.succeed(undefined)));
|
|
4054
|
+
var createMatcher = (props) => Effect51.gen(function* () {
|
|
4055
|
+
const input = yield* notificationRequest(cluster9.CreateClusterNotificationMatcherRequest, matcherCreateForm(props));
|
|
4056
|
+
yield* runPve(props.target, "provision", true, cluster9.createClusterNotificationMatcher(input));
|
|
4025
4057
|
});
|
|
4026
|
-
var updateMatcher = (props) =>
|
|
4027
|
-
const input = yield* notificationRequest(
|
|
4058
|
+
var updateMatcher = (props) => Effect51.gen(function* () {
|
|
4059
|
+
const input = yield* notificationRequest(cluster9.PutClusterNotificationMatcherRequest, {
|
|
4028
4060
|
...matcherUpdateForm(props),
|
|
4029
4061
|
name: props.name
|
|
4030
4062
|
});
|
|
4031
|
-
yield* runPve(props.target, "provision", true,
|
|
4063
|
+
yield* runPve(props.target, "provision", true, cluster9.putClusterNotificationMatcher(input));
|
|
4032
4064
|
});
|
|
4033
|
-
var deleteMatcher = (props) => runPve(props.target, "provision", true,
|
|
4065
|
+
var deleteMatcher = (props) => runPve(props.target, "provision", true, cluster9.deleteClusterNotificationMatcher({ name: props.name })).pipe(Effect51.catchTag("NotFound", () => Effect51.void));
|
|
4034
4066
|
|
|
4035
4067
|
// src/proxmox/notification-matcher-lifecycle.ts
|
|
4036
|
-
var guard = (props, create) => guardForm("pve:POST /cluster/notifications/matchers", matcherCreateForm(props), create).pipe(
|
|
4068
|
+
var guard = (props, create) => guardForm("pve:POST /cluster/notifications/matchers", matcherCreateForm(props), create).pipe(Effect52.andThen(guardForm("pve:PUT /cluster/notifications/matchers/{name}", matcherUpdateForm(props), false)));
|
|
4037
4069
|
var matcherHandlers = {
|
|
4038
|
-
list: () =>
|
|
4039
|
-
read: ({ olds }) =>
|
|
4070
|
+
list: () => Effect52.succeed([]),
|
|
4071
|
+
read: ({ olds }) => Effect52.gen(function* () {
|
|
4040
4072
|
const live = yield* readMatcher(olds);
|
|
4041
4073
|
yield* guard(olds, live === undefined);
|
|
4042
4074
|
return live;
|
|
@@ -4045,8 +4077,8 @@ var matcherHandlers = {
|
|
|
4045
4077
|
news,
|
|
4046
4078
|
olds,
|
|
4047
4079
|
output
|
|
4048
|
-
}) =>
|
|
4049
|
-
if (!
|
|
4080
|
+
}) => Effect52.gen(function* () {
|
|
4081
|
+
if (!isResolved16(news))
|
|
4050
4082
|
return;
|
|
4051
4083
|
if (olds.name !== news.name)
|
|
4052
4084
|
return { action: "replace" };
|
|
@@ -4060,7 +4092,7 @@ var matcherHandlers = {
|
|
|
4060
4092
|
}
|
|
4061
4093
|
return { action: matcherMatches(live, news) ? "noop" : "update" };
|
|
4062
4094
|
}),
|
|
4063
|
-
reconcile: ({ news }) =>
|
|
4095
|
+
reconcile: ({ news }) => Effect52.gen(function* () {
|
|
4064
4096
|
const live = yield* readMatcher(news);
|
|
4065
4097
|
yield* guard(news, live === undefined);
|
|
4066
4098
|
if (live === undefined)
|
|
@@ -4069,7 +4101,7 @@ var matcherHandlers = {
|
|
|
4069
4101
|
yield* updateMatcher(news);
|
|
4070
4102
|
const after = yield* readMatcher(news);
|
|
4071
4103
|
if (after === undefined)
|
|
4072
|
-
return yield*
|
|
4104
|
+
return yield* Effect52.die(new Error(`Notification matcher ${news.name}: write returned but read-back is absent.`));
|
|
4073
4105
|
return after;
|
|
4074
4106
|
}),
|
|
4075
4107
|
delete: ({ olds }) => deleteMatcher(olds)
|
|
@@ -4077,15 +4109,15 @@ var matcherHandlers = {
|
|
|
4077
4109
|
|
|
4078
4110
|
// src/proxmox/notification-matcher.ts
|
|
4079
4111
|
var ProxmoxNotificationMatcher = Resource17("Proxmox.NotificationMatcher");
|
|
4080
|
-
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher,
|
|
4112
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect53.succeed(ProxmoxNotificationMatcher.Provider.of(matcherHandlers)));
|
|
4081
4113
|
// src/proxmox/notification-target.ts
|
|
4082
4114
|
import { Resource as Resource18 } from "alchemy";
|
|
4083
4115
|
import * as Provider18 from "alchemy/Provider";
|
|
4084
|
-
import * as
|
|
4116
|
+
import * as Effect56 from "effect/Effect";
|
|
4085
4117
|
|
|
4086
4118
|
// src/proxmox/notification-target-lifecycle.ts
|
|
4087
|
-
import { isResolved as
|
|
4088
|
-
import * as
|
|
4119
|
+
import { isResolved as isResolved17 } from "alchemy/Diff";
|
|
4120
|
+
import * as Effect55 from "effect/Effect";
|
|
4089
4121
|
|
|
4090
4122
|
// src/proxmox/notification-target-endpoint.ts
|
|
4091
4123
|
var ENDPOINTS = {
|
|
@@ -4168,30 +4200,30 @@ var targetSpec = {
|
|
|
4168
4200
|
};
|
|
4169
4201
|
|
|
4170
4202
|
// src/proxmox/notification-target-distilled.ts
|
|
4171
|
-
import * as
|
|
4172
|
-
import * as
|
|
4203
|
+
import * as cluster10 from "@distilled.cloud/proxmox/cluster";
|
|
4204
|
+
import * as Effect54 from "effect/Effect";
|
|
4173
4205
|
var read3 = (props) => {
|
|
4174
4206
|
const request = { name: props.name };
|
|
4175
4207
|
switch (props.type) {
|
|
4176
4208
|
case "gotify":
|
|
4177
|
-
return
|
|
4209
|
+
return cluster10.getClusterNotificationEndpointGotify(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointGotifyResponse)), Effect54.map((row) => ({ ...row })));
|
|
4178
4210
|
case "sendmail":
|
|
4179
|
-
return
|
|
4211
|
+
return cluster10.getClusterNotificationEndpointSendmail(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointSendmailResponse)), Effect54.map((row) => ({
|
|
4180
4212
|
...row,
|
|
4181
4213
|
"from-address": row.from_address,
|
|
4182
4214
|
"mailto-user": row.mailto_user
|
|
4183
4215
|
})));
|
|
4184
4216
|
case "smtp":
|
|
4185
|
-
return
|
|
4217
|
+
return cluster10.getClusterNotificationEndpointSmtp(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointSmtpResponse)), Effect54.map((row) => ({
|
|
4186
4218
|
...row,
|
|
4187
4219
|
"from-address": row.from_address,
|
|
4188
4220
|
"mailto-user": row.mailto_user
|
|
4189
4221
|
})));
|
|
4190
4222
|
case "webhook":
|
|
4191
|
-
return
|
|
4223
|
+
return cluster10.getClusterNotificationEndpointWebhook(request).pipe(Effect54.flatMap(notificationResponse(cluster10.GetClusterNotificationEndpointWebhookResponse)), Effect54.map((row) => ({ ...row })));
|
|
4192
4224
|
}
|
|
4193
4225
|
};
|
|
4194
|
-
var readTarget = (props) => runPve(props.target, "read", false, read3(props)).pipe(
|
|
4226
|
+
var readTarget = (props) => runPve(props.target, "read", false, read3(props)).pipe(Effect54.map((row) => targetSpec.attributes(row, props)), Effect54.catchTag("NotFound", () => Effect54.succeed(undefined)));
|
|
4195
4227
|
var fields = (props, create) => {
|
|
4196
4228
|
const form = {
|
|
4197
4229
|
...create ? createShape(props) : shape4(props),
|
|
@@ -4225,40 +4257,40 @@ var fields = (props, create) => {
|
|
|
4225
4257
|
};
|
|
4226
4258
|
var validateTargetWrite = (props, create) => {
|
|
4227
4259
|
const schema = create ? {
|
|
4228
|
-
sendmail:
|
|
4229
|
-
smtp:
|
|
4230
|
-
gotify:
|
|
4231
|
-
webhook:
|
|
4260
|
+
sendmail: cluster10.CreateClusterNotificationEndpointSendmailRequest,
|
|
4261
|
+
smtp: cluster10.CreateClusterNotificationEndpointSmtpRequest,
|
|
4262
|
+
gotify: cluster10.CreateClusterNotificationEndpointGotifyRequest,
|
|
4263
|
+
webhook: cluster10.CreateClusterNotificationEndpointWebhookRequest
|
|
4232
4264
|
}[props.type] : {
|
|
4233
|
-
sendmail:
|
|
4234
|
-
smtp:
|
|
4235
|
-
gotify:
|
|
4236
|
-
webhook:
|
|
4265
|
+
sendmail: cluster10.PutClusterNotificationEndpointSendmailRequest,
|
|
4266
|
+
smtp: cluster10.PutClusterNotificationEndpointSmtpRequest,
|
|
4267
|
+
gotify: cluster10.PutClusterNotificationEndpointGotifyRequest,
|
|
4268
|
+
webhook: cluster10.PutClusterNotificationEndpointWebhookRequest
|
|
4237
4269
|
}[props.type];
|
|
4238
|
-
return notificationRequest(schema, fields(props, create)).pipe(
|
|
4270
|
+
return notificationRequest(schema, fields(props, create)).pipe(Effect54.asVoid);
|
|
4239
4271
|
};
|
|
4240
4272
|
var createTarget = (props) => {
|
|
4241
4273
|
const form = fields(props, true);
|
|
4242
|
-
const operation = props.type === "sendmail" ? notificationRequest(
|
|
4274
|
+
const operation = props.type === "sendmail" ? notificationRequest(cluster10.CreateClusterNotificationEndpointSendmailRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster10.CreateClusterNotificationEndpointSmtpRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster10.CreateClusterNotificationEndpointGotifyRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointGotify)) : notificationRequest(cluster10.CreateClusterNotificationEndpointWebhookRequest, form).pipe(Effect54.flatMap(cluster10.createClusterNotificationEndpointWebhook));
|
|
4243
4275
|
return runPve(props.target, "provision", true, operation);
|
|
4244
4276
|
};
|
|
4245
4277
|
var updateTarget = (props) => {
|
|
4246
4278
|
const form = fields(props, false);
|
|
4247
|
-
const operation = props.type === "sendmail" ? notificationRequest(
|
|
4279
|
+
const operation = props.type === "sendmail" ? notificationRequest(cluster10.PutClusterNotificationEndpointSendmailRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster10.PutClusterNotificationEndpointSmtpRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster10.PutClusterNotificationEndpointGotifyRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointGotify)) : notificationRequest(cluster10.PutClusterNotificationEndpointWebhookRequest, form).pipe(Effect54.flatMap(cluster10.putClusterNotificationEndpointWebhook));
|
|
4248
4280
|
return runPve(props.target, "provision", true, operation);
|
|
4249
4281
|
};
|
|
4250
4282
|
var deleteTarget = (props) => {
|
|
4251
4283
|
const request = { name: props.name };
|
|
4252
|
-
const operation = props.type === "sendmail" ?
|
|
4253
|
-
return runPve(props.target, "provision", true, operation).pipe(
|
|
4284
|
+
const operation = props.type === "sendmail" ? cluster10.deleteClusterNotificationEndpointSendmail(request) : props.type === "smtp" ? cluster10.deleteClusterNotificationEndpointSmtp(request) : props.type === "gotify" ? cluster10.deleteClusterNotificationEndpointGotify(request) : cluster10.deleteClusterNotificationEndpointWebhook(request);
|
|
4285
|
+
return runPve(props.target, "provision", true, operation).pipe(Effect54.catchTag("NotFound", () => Effect54.void));
|
|
4254
4286
|
};
|
|
4255
4287
|
|
|
4256
4288
|
// src/proxmox/notification-target-lifecycle.ts
|
|
4257
4289
|
var { guardCreate: guardCreate4, guardUpdate: guardUpdate4 } = specGuards(targetSpec);
|
|
4258
|
-
var guard2 = (props, create) => guardCreate4(props, create).pipe(
|
|
4290
|
+
var guard2 = (props, create) => guardCreate4(props, create).pipe(Effect55.andThen(guardUpdate4(props)));
|
|
4259
4291
|
var targetHandlers = {
|
|
4260
|
-
list: () =>
|
|
4261
|
-
read: ({ olds }) =>
|
|
4292
|
+
list: () => Effect55.succeed([]),
|
|
4293
|
+
read: ({ olds }) => Effect55.gen(function* () {
|
|
4262
4294
|
const live = yield* readTarget(olds);
|
|
4263
4295
|
yield* guard2(olds, live === undefined);
|
|
4264
4296
|
return live;
|
|
@@ -4267,8 +4299,8 @@ var targetHandlers = {
|
|
|
4267
4299
|
news,
|
|
4268
4300
|
olds,
|
|
4269
4301
|
output
|
|
4270
|
-
}) =>
|
|
4271
|
-
if (!
|
|
4302
|
+
}) => Effect55.gen(function* () {
|
|
4303
|
+
if (!isResolved17(news))
|
|
4272
4304
|
return;
|
|
4273
4305
|
if (olds.name !== news.name || olds.type !== news.type) {
|
|
4274
4306
|
const destination = yield* readTarget(news);
|
|
@@ -4286,7 +4318,7 @@ var targetHandlers = {
|
|
|
4286
4318
|
}
|
|
4287
4319
|
return { action: targetSpec.matches(live, news) ? "noop" : "update" };
|
|
4288
4320
|
}),
|
|
4289
|
-
reconcile: ({ news }) =>
|
|
4321
|
+
reconcile: ({ news }) => Effect55.gen(function* () {
|
|
4290
4322
|
const live = yield* readTarget(news);
|
|
4291
4323
|
yield* guard2(news, live === undefined);
|
|
4292
4324
|
if (live === undefined)
|
|
@@ -4295,7 +4327,7 @@ var targetHandlers = {
|
|
|
4295
4327
|
yield* updateTarget(news);
|
|
4296
4328
|
const after = yield* readTarget(news);
|
|
4297
4329
|
if (after === undefined)
|
|
4298
|
-
return yield*
|
|
4330
|
+
return yield* Effect55.die(new Error(`Notification target ${news.name}: write returned but read-back is absent.`));
|
|
4299
4331
|
return after;
|
|
4300
4332
|
}),
|
|
4301
4333
|
delete: ({ olds }) => deleteTarget(olds)
|
|
@@ -4303,15 +4335,15 @@ var targetHandlers = {
|
|
|
4303
4335
|
|
|
4304
4336
|
// src/proxmox/notification-target.ts
|
|
4305
4337
|
var ProxmoxNotificationTarget = Resource18("Proxmox.NotificationTarget");
|
|
4306
|
-
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget,
|
|
4338
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect56.succeed(ProxmoxNotificationTarget.Provider.of(targetHandlers)));
|
|
4307
4339
|
// src/proxmox/pbs-datastore.ts
|
|
4308
4340
|
import { Resource as Resource19 } from "alchemy";
|
|
4309
4341
|
import * as Provider19 from "alchemy/Provider";
|
|
4310
|
-
import * as
|
|
4342
|
+
import * as Effect62 from "effect/Effect";
|
|
4311
4343
|
|
|
4312
4344
|
// src/proxmox/pbs-datastore-lifecycle.ts
|
|
4313
|
-
import { isResolved as
|
|
4314
|
-
import * as
|
|
4345
|
+
import { isResolved as isResolved18 } from "alchemy/Diff";
|
|
4346
|
+
import * as Effect61 from "effect/Effect";
|
|
4315
4347
|
|
|
4316
4348
|
// src/proxmox/pbs-datastore-form.ts
|
|
4317
4349
|
var attributes = (live, props) => ({
|
|
@@ -4336,7 +4368,7 @@ var attributes = (live, props) => ({
|
|
|
4336
4368
|
"verify-new": bool(live["verify-new"])
|
|
4337
4369
|
});
|
|
4338
4370
|
var same4 = (declared, live) => declared === undefined || declared === live;
|
|
4339
|
-
var
|
|
4371
|
+
var matches7 = (live, props) => same4(props.comment, live.comment) && same4(props["gc-schedule"]?.trim(), live["gc-schedule"]) && same4(props["prune-schedule"]?.trim(), live["prune-schedule"]) && same4(props["keep-last"], live["keep-last"]) && same4(props["keep-hourly"], live["keep-hourly"]) && same4(props["keep-daily"], live["keep-daily"]) && same4(props["keep-weekly"], live["keep-weekly"]) && same4(props["keep-monthly"], live["keep-monthly"]) && same4(props["keep-yearly"], live["keep-yearly"]) && same4(props["notify-user"], live["notify-user"]) && same4(props["counter-reset-schedule"]?.trim(), live["counter-reset-schedule"]) && (props["notification-thresholds"] === undefined || propertyString(props["notification-thresholds"]) === live["notification-thresholds"]) && same4(props["verify-new"], live["verify-new"]) && (props.notify === undefined || propertyString(props.notify) === live.notify) && (props.tuning === undefined || propertyString(props.tuning) === live.tuning) && (props["maintenance-mode"] === undefined || propertyString(props["maintenance-mode"], "type") === live["maintenance-mode"]);
|
|
4340
4372
|
var set2 = (key, value) => value === undefined ? {} : { [key]: value };
|
|
4341
4373
|
var count = (value) => value === undefined ? undefined : String(value);
|
|
4342
4374
|
var mutable = (props) => ({
|
|
@@ -4363,23 +4395,23 @@ var createForm6 = (props) => ({
|
|
|
4363
4395
|
path: props.path,
|
|
4364
4396
|
...props.backend === undefined ? {} : { backend: props.backend }
|
|
4365
4397
|
});
|
|
4366
|
-
var
|
|
4398
|
+
var updateForm4 = (props) => mutable(props);
|
|
4367
4399
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
4368
4400
|
|
|
4369
4401
|
// src/proxmox/pbs-datastore-wire.ts
|
|
4370
4402
|
import * as config from "@distilled.cloud/proxmox-backup/config";
|
|
4371
|
-
import * as
|
|
4403
|
+
import * as Effect58 from "effect/Effect";
|
|
4372
4404
|
|
|
4373
4405
|
// src/proxmox/distilled-pbs.ts
|
|
4374
4406
|
import { credentials } from "@distilled.cloud/proxmox-backup/Credentials";
|
|
4375
4407
|
import * as Retry from "@distilled.cloud/proxmox-backup/Retry";
|
|
4376
|
-
import * as
|
|
4377
|
-
var runPbsWith = (target, credential, op, timeout5 = MEMBER_TIMEOUT) => op.pipe(Retry.none,
|
|
4408
|
+
import * as Effect57 from "effect/Effect";
|
|
4409
|
+
var runPbsWith = (target, credential, op, timeout5 = MEMBER_TIMEOUT) => op.pipe(Retry.none, Effect57.provide(credentials({
|
|
4378
4410
|
baseUrl: target.api,
|
|
4379
4411
|
secret: credential.secret,
|
|
4380
4412
|
tokenId: credential.tokenId
|
|
4381
|
-
})),
|
|
4382
|
-
var runPbs = (target, role, op) =>
|
|
4413
|
+
})), Effect57.timeout(timeout5));
|
|
4414
|
+
var runPbs = (target, role, op) => Effect57.gen(function* () {
|
|
4383
4415
|
const credential = yield* leased(target, role);
|
|
4384
4416
|
return yield* runPbsWith(target, credential, op);
|
|
4385
4417
|
});
|
|
@@ -4410,7 +4442,7 @@ var createRequest = (props) => ({
|
|
|
4410
4442
|
...props.backend === undefined ? {} : { backend: props.backend }
|
|
4411
4443
|
});
|
|
4412
4444
|
var updateRequest = (props) => ({
|
|
4413
|
-
...members(
|
|
4445
|
+
...members(updateForm4(props)),
|
|
4414
4446
|
name: props.name
|
|
4415
4447
|
});
|
|
4416
4448
|
var wire = (row) => ({
|
|
@@ -4429,53 +4461,53 @@ var wire = (row) => ({
|
|
|
4429
4461
|
"prune-schedule": row.prune_schedule,
|
|
4430
4462
|
"verify-new": row.verify_new
|
|
4431
4463
|
});
|
|
4432
|
-
var readOne = (props) => runPbs(props.target, "read", config.getConfigDatastore({ name: props.name })).pipe(
|
|
4464
|
+
var readOne = (props) => runPbs(props.target, "read", config.getConfigDatastore({ name: props.name })).pipe(Effect58.map((live) => attributes(wire(live), props)), Effect58.catchTag("DatastoreNotFound", () => Effect58.succeed(undefined)));
|
|
4433
4465
|
var createOne = (props) => runPbs(props.target, "provision", config.createConfigDatastore(createRequest(props)));
|
|
4434
4466
|
var updateOne = (props) => runPbs(props.target, "provision", config.putConfigDatastore(updateRequest(props)));
|
|
4435
|
-
var deleteOne = (props) =>
|
|
4467
|
+
var deleteOne = (props) => Effect58.gen(function* () {
|
|
4436
4468
|
if ((yield* readOne(props)) === undefined)
|
|
4437
4469
|
return;
|
|
4438
4470
|
return yield* runPbs(props.target, "provision", config.deleteConfigDatastore({ name: props.name }));
|
|
4439
4471
|
});
|
|
4440
4472
|
|
|
4441
4473
|
// src/proxmox/pbs-datastore-guard.ts
|
|
4442
|
-
import * as
|
|
4474
|
+
import * as Effect59 from "effect/Effect";
|
|
4443
4475
|
var samePath = (left, right) => {
|
|
4444
4476
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
4445
4477
|
return trim(left) === trim(right);
|
|
4446
4478
|
};
|
|
4447
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
4448
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
4449
|
-
var settle2 = (read4, done) =>
|
|
4479
|
+
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect59.void : Effect59.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."));
|
|
4480
|
+
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect59.void : Effect59.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."));
|
|
4481
|
+
var settle2 = (read4, done) => Effect59.gen(function* () {
|
|
4450
4482
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
4451
4483
|
const live = yield* read4;
|
|
4452
4484
|
if (done(live))
|
|
4453
4485
|
return live;
|
|
4454
|
-
yield*
|
|
4486
|
+
yield* Effect59.sleep("2 seconds");
|
|
4455
4487
|
}
|
|
4456
4488
|
return yield* read4;
|
|
4457
4489
|
});
|
|
4458
4490
|
|
|
4459
4491
|
// src/proxmox/pbs-datastore-endpoint.ts
|
|
4460
|
-
import * as
|
|
4492
|
+
import * as Effect60 from "effect/Effect";
|
|
4461
4493
|
var DATASTORE_ENDPOINT = {
|
|
4462
4494
|
create: "pbs:POST /config/datastore",
|
|
4463
4495
|
update: "pbs:PUT /config/datastore/{name}"
|
|
4464
4496
|
};
|
|
4465
|
-
var guardDatastoreForms = (props) =>
|
|
4497
|
+
var guardDatastoreForms = (props) => Effect60.gen(function* () {
|
|
4466
4498
|
yield* guardForm(DATASTORE_ENDPOINT.create, createForm6(props), true);
|
|
4467
|
-
yield* guardForm(DATASTORE_ENDPOINT.update,
|
|
4499
|
+
yield* guardForm(DATASTORE_ENDPOINT.update, updateForm4(props), false);
|
|
4468
4500
|
});
|
|
4469
4501
|
|
|
4470
4502
|
// src/proxmox/pbs-datastore-lifecycle.ts
|
|
4471
|
-
var
|
|
4472
|
-
list: () =>
|
|
4503
|
+
var handlers6 = {
|
|
4504
|
+
list: () => Effect61.succeed([]),
|
|
4473
4505
|
read: ({ olds }) => readOne(olds),
|
|
4474
4506
|
diff: ({
|
|
4475
4507
|
news,
|
|
4476
4508
|
output
|
|
4477
|
-
}) =>
|
|
4478
|
-
if (!
|
|
4509
|
+
}) => Effect61.gen(function* () {
|
|
4510
|
+
if (!isResolved18(news))
|
|
4479
4511
|
return;
|
|
4480
4512
|
yield* guardDatastoreForms(news);
|
|
4481
4513
|
if (output === undefined)
|
|
@@ -4485,9 +4517,9 @@ var handlers7 = {
|
|
|
4485
4517
|
return { action: "update" };
|
|
4486
4518
|
yield* guardPath(live, news);
|
|
4487
4519
|
yield* guardBackend(live, news);
|
|
4488
|
-
return
|
|
4520
|
+
return matches7(live, news) ? { action: "noop" } : { action: "update" };
|
|
4489
4521
|
}),
|
|
4490
|
-
reconcile:
|
|
4522
|
+
reconcile: Effect61.fn(function* ({ news }) {
|
|
4491
4523
|
yield* guardDatastoreForms(news);
|
|
4492
4524
|
const live = yield* readOne(news);
|
|
4493
4525
|
if (live === undefined) {
|
|
@@ -4495,22 +4527,22 @@ var handlers7 = {
|
|
|
4495
4527
|
} else {
|
|
4496
4528
|
yield* guardPath(live, news);
|
|
4497
4529
|
yield* guardBackend(live, news);
|
|
4498
|
-
const form = formToSend(
|
|
4530
|
+
const form = formToSend(matches7, live, news, updateForm4(news));
|
|
4499
4531
|
if (form !== undefined) {
|
|
4500
4532
|
yield* updateOne(news);
|
|
4501
4533
|
}
|
|
4502
4534
|
}
|
|
4503
|
-
const after = yield* settle2(readOne(news), (row) => row !== undefined &&
|
|
4504
|
-
if (after === undefined || !
|
|
4505
|
-
return yield*
|
|
4535
|
+
const after = yield* settle2(readOne(news), (row) => row !== undefined && matches7(row, news));
|
|
4536
|
+
if (after === undefined || !matches7(after, news)) {
|
|
4537
|
+
return yield* Effect61.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + "match the declaration after 120s. Check the PBS task list " + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
|
|
4506
4538
|
}
|
|
4507
4539
|
return after;
|
|
4508
4540
|
}),
|
|
4509
|
-
delete:
|
|
4541
|
+
delete: Effect61.fn(function* ({ olds }) {
|
|
4510
4542
|
yield* deleteOne(olds);
|
|
4511
4543
|
const left = yield* settle2(readOne(olds), (row) => row === undefined);
|
|
4512
4544
|
if (left !== undefined) {
|
|
4513
|
-
return yield*
|
|
4545
|
+
return yield* Effect61.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>\`.`));
|
|
4514
4546
|
}
|
|
4515
4547
|
})
|
|
4516
4548
|
};
|
|
@@ -4519,36 +4551,36 @@ var handlers7 = {
|
|
|
4519
4551
|
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
4520
4552
|
defaultRemovalPolicy: "retain"
|
|
4521
4553
|
});
|
|
4522
|
-
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore,
|
|
4554
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect62.succeed(PbsDatastore.Provider.of(handlers6)));
|
|
4523
4555
|
// src/proxmox/pbs-notification-matcher.ts
|
|
4524
4556
|
import { Resource as Resource20 } from "alchemy";
|
|
4525
4557
|
import * as Provider20 from "alchemy/Provider";
|
|
4526
|
-
import { isResolved as
|
|
4527
|
-
import * as
|
|
4558
|
+
import { isResolved as isResolved19 } from "alchemy/Diff";
|
|
4559
|
+
import * as Effect65 from "effect/Effect";
|
|
4528
4560
|
|
|
4529
4561
|
// src/proxmox/pbs-notification-matcher-distilled.ts
|
|
4530
4562
|
import * as config2 from "@distilled.cloud/proxmox-backup/config";
|
|
4531
|
-
import * as
|
|
4563
|
+
import * as Effect64 from "effect/Effect";
|
|
4532
4564
|
|
|
4533
4565
|
// src/proxmox/pbs-notification-input.ts
|
|
4534
4566
|
import * as Data3 from "effect/Data";
|
|
4535
|
-
import * as
|
|
4567
|
+
import * as Effect63 from "effect/Effect";
|
|
4536
4568
|
import * as Schema4 from "effect/Schema";
|
|
4537
4569
|
|
|
4538
4570
|
class PbsNotificationInputRefusal extends Data3.TaggedError("PbsNotificationInputRefusal") {
|
|
4539
4571
|
}
|
|
4540
|
-
var notificationInput = (schema, fields2) => Schema4.decodeUnknownEffect(Schema4.toType(schema))(fields2).pipe(
|
|
4572
|
+
var notificationInput = (schema, fields2) => Schema4.decodeUnknownEffect(Schema4.toType(schema))(fields2).pipe(Effect63.mapError(() => new PbsNotificationInputRefusal({
|
|
4541
4573
|
message: "PBS notification fields do not match the SDK request schema; no PBS request was sent."
|
|
4542
4574
|
})));
|
|
4543
4575
|
|
|
4544
4576
|
// src/proxmox/pbs-notification-matcher-distilled.ts
|
|
4545
|
-
var readMatcher2 = (props) => runPbs(props.target, "read", config2.getConfigNotificationMatcher({ name: props.name })).pipe(
|
|
4577
|
+
var readMatcher2 = (props) => runPbs(props.target, "read", config2.getConfigNotificationMatcher({ name: props.name })).pipe(Effect64.map((row) => matcherAttributes({
|
|
4546
4578
|
...row,
|
|
4547
4579
|
"invert-match": row.invert_match,
|
|
4548
4580
|
"match-calendar": row.match_calendar,
|
|
4549
4581
|
"match-field": row.match_field,
|
|
4550
4582
|
"match-severity": row.match_severity
|
|
4551
|
-
}, props.name)),
|
|
4583
|
+
}, props.name)), Effect64.catchTag("NotFound", () => Effect64.succeed(undefined)));
|
|
4552
4584
|
var requestFields = (props, form) => ({
|
|
4553
4585
|
...form,
|
|
4554
4586
|
invert_match: form["invert-match"],
|
|
@@ -4557,23 +4589,23 @@ var requestFields = (props, form) => ({
|
|
|
4557
4589
|
match_severity: form["match-severity"],
|
|
4558
4590
|
name: props.name
|
|
4559
4591
|
});
|
|
4560
|
-
var createMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.CreateConfigNotificationMatcherRequest, requestFields(props, form)).pipe(
|
|
4561
|
-
var updateMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.PutConfigNotificationMatcherRequest, requestFields(props, form)).pipe(
|
|
4562
|
-
var deleteMatcher2 = (props) => runPbs(props.target, "provision", config2.deleteConfigNotificationMatcher({ name: props.name })).pipe(
|
|
4592
|
+
var createMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.CreateConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect64.flatMap(config2.createConfigNotificationMatcher)));
|
|
4593
|
+
var updateMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.PutConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect64.flatMap(config2.putConfigNotificationMatcher)));
|
|
4594
|
+
var deleteMatcher2 = (props) => runPbs(props.target, "provision", config2.deleteConfigNotificationMatcher({ name: props.name })).pipe(Effect64.catchTag("NotFound", () => Effect64.void));
|
|
4563
4595
|
|
|
4564
4596
|
// src/proxmox/pbs-notification-matcher.ts
|
|
4565
4597
|
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
4566
4598
|
var guardCreate5 = (props, requirePresence) => guardForm("pbs:POST /config/notifications/matchers", matcherCreateForm(props), requirePresence);
|
|
4567
4599
|
var guardUpdate5 = (props) => guardForm("pbs:PUT /config/notifications/matchers/{name}", matcherUpdateForm(props), false);
|
|
4568
|
-
var
|
|
4569
|
-
list: () =>
|
|
4600
|
+
var handlers7 = {
|
|
4601
|
+
list: () => Effect65.succeed([]),
|
|
4570
4602
|
read: ({ olds }) => readMatcher2(olds),
|
|
4571
4603
|
diff: ({
|
|
4572
4604
|
news,
|
|
4573
4605
|
olds,
|
|
4574
4606
|
output
|
|
4575
|
-
}) =>
|
|
4576
|
-
if (!
|
|
4607
|
+
}) => Effect65.gen(function* () {
|
|
4608
|
+
if (!isResolved19(news))
|
|
4577
4609
|
return;
|
|
4578
4610
|
yield* guardCreate5(news, output === undefined);
|
|
4579
4611
|
yield* guardUpdate5(news);
|
|
@@ -4588,7 +4620,7 @@ var handlers8 = {
|
|
|
4588
4620
|
}
|
|
4589
4621
|
return { action: matcherMatches(live, news) ? "noop" : "update" };
|
|
4590
4622
|
}),
|
|
4591
|
-
reconcile: ({ news }) =>
|
|
4623
|
+
reconcile: ({ news }) => Effect65.gen(function* () {
|
|
4592
4624
|
const live = yield* readMatcher2(news);
|
|
4593
4625
|
yield* guardCreate5(news, live === undefined);
|
|
4594
4626
|
yield* guardUpdate5(news);
|
|
@@ -4598,24 +4630,24 @@ var handlers8 = {
|
|
|
4598
4630
|
yield* updateMatcher2(news, matcherUpdateForm(news));
|
|
4599
4631
|
const after = yield* readMatcher2(news);
|
|
4600
4632
|
if (after === undefined)
|
|
4601
|
-
return yield*
|
|
4633
|
+
return yield* Effect65.fail(new Error(`config/notifications/matchers/${news.name}: the write returned no error but the matcher is still absent.`));
|
|
4602
4634
|
return after;
|
|
4603
4635
|
}),
|
|
4604
4636
|
delete: ({ olds }) => deleteMatcher2(olds)
|
|
4605
4637
|
};
|
|
4606
|
-
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher,
|
|
4638
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect65.succeed(PbsNotificationMatcher.Provider.of(handlers7)));
|
|
4607
4639
|
// src/proxmox/pbs-notification-target.ts
|
|
4608
4640
|
import { Resource as Resource21 } from "alchemy";
|
|
4609
4641
|
import * as Provider21 from "alchemy/Provider";
|
|
4610
|
-
import * as
|
|
4642
|
+
import * as Effect68 from "effect/Effect";
|
|
4611
4643
|
|
|
4612
4644
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4613
|
-
import { isResolved as
|
|
4614
|
-
import * as
|
|
4645
|
+
import { isResolved as isResolved20 } from "alchemy/Diff";
|
|
4646
|
+
import * as Effect67 from "effect/Effect";
|
|
4615
4647
|
|
|
4616
4648
|
// src/proxmox/pbs-notification-target-distilled.ts
|
|
4617
4649
|
import * as config3 from "@distilled.cloud/proxmox-backup/config";
|
|
4618
|
-
import * as
|
|
4650
|
+
import * as Effect66 from "effect/Effect";
|
|
4619
4651
|
|
|
4620
4652
|
// src/proxmox/pbs-notification-target-wire.ts
|
|
4621
4653
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
@@ -4716,22 +4748,22 @@ var requestFields2 = (props, form) => ({
|
|
|
4716
4748
|
var read4 = (props) => {
|
|
4717
4749
|
switch (props.type) {
|
|
4718
4750
|
case "sendmail":
|
|
4719
|
-
return config3.getConfigNotificationEndpointSendmail({ name: props.name }).pipe(
|
|
4751
|
+
return config3.getConfigNotificationEndpointSendmail({ name: props.name }).pipe(Effect66.map((row) => ({
|
|
4720
4752
|
...row,
|
|
4721
4753
|
"from-address": row.from_address,
|
|
4722
4754
|
"mailto-user": row.mailto_user
|
|
4723
4755
|
})));
|
|
4724
4756
|
case "smtp":
|
|
4725
|
-
return config3.getConfigNotificationEndpointSmtp({ name: props.name }).pipe(
|
|
4757
|
+
return config3.getConfigNotificationEndpointSmtp({ name: props.name }).pipe(Effect66.map((row) => ({
|
|
4726
4758
|
...row,
|
|
4727
4759
|
"from-address": row.from_address,
|
|
4728
4760
|
"mailto-user": row.mailto_user
|
|
4729
4761
|
})));
|
|
4730
4762
|
case "webhook":
|
|
4731
|
-
return config3.getConfigNotificationEndpointWebhook({ name: props.name }).pipe(
|
|
4763
|
+
return config3.getConfigNotificationEndpointWebhook({ name: props.name }).pipe(Effect66.map((row) => ({ ...row })));
|
|
4732
4764
|
}
|
|
4733
4765
|
};
|
|
4734
|
-
var readTarget2 = (props) => runPbs(props.target, "read", read4(props)).pipe(
|
|
4766
|
+
var readTarget2 = (props) => runPbs(props.target, "read", read4(props)).pipe(Effect66.map((row) => targetAttributes(row, props)), Effect66.catchTag("NotFound", () => Effect66.succeed(undefined)));
|
|
4735
4767
|
var validateTargetWrite2 = (props, form, mode) => {
|
|
4736
4768
|
const schema = mode === "create" ? {
|
|
4737
4769
|
sendmail: config3.CreateConfigNotificationEndpointSendmailRequest,
|
|
@@ -4742,22 +4774,22 @@ var validateTargetWrite2 = (props, form, mode) => {
|
|
|
4742
4774
|
smtp: config3.PutConfigNotificationEndpointSmtpRequest,
|
|
4743
4775
|
webhook: config3.PutConfigNotificationEndpointWebhookRequest
|
|
4744
4776
|
}[props.type];
|
|
4745
|
-
return notificationInput(schema, requestFields2(props, form)).pipe(
|
|
4777
|
+
return notificationInput(schema, requestFields2(props, form)).pipe(Effect66.asVoid);
|
|
4746
4778
|
};
|
|
4747
4779
|
var createTarget2 = (props, form) => {
|
|
4748
4780
|
const fields2 = requestFields2(props, form);
|
|
4749
|
-
const operation = props.type === "sendmail" ? notificationInput(config3.CreateConfigNotificationEndpointSendmailRequest, fields2).pipe(
|
|
4781
|
+
const operation = props.type === "sendmail" ? notificationInput(config3.CreateConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect66.flatMap(config3.createConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.CreateConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect66.flatMap(config3.createConfigNotificationEndpointSmtp)) : notificationInput(config3.CreateConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect66.flatMap(config3.createConfigNotificationEndpointWebhook));
|
|
4750
4782
|
return runPbs(props.target, "provision", operation);
|
|
4751
4783
|
};
|
|
4752
4784
|
var updateTarget2 = (props, form) => {
|
|
4753
4785
|
const fields2 = requestFields2(props, form);
|
|
4754
|
-
const operation = props.type === "sendmail" ? notificationInput(config3.PutConfigNotificationEndpointSendmailRequest, fields2).pipe(
|
|
4786
|
+
const operation = props.type === "sendmail" ? notificationInput(config3.PutConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect66.flatMap(config3.putConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.PutConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect66.flatMap(config3.putConfigNotificationEndpointSmtp)) : notificationInput(config3.PutConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect66.flatMap(config3.putConfigNotificationEndpointWebhook));
|
|
4755
4787
|
return runPbs(props.target, "provision", operation);
|
|
4756
4788
|
};
|
|
4757
4789
|
var deleteTarget2 = (props) => {
|
|
4758
4790
|
const request = { name: props.name };
|
|
4759
4791
|
const operation = props.type === "sendmail" ? config3.deleteConfigNotificationEndpointSendmail(request) : props.type === "smtp" ? config3.deleteConfigNotificationEndpointSmtp(request) : config3.deleteConfigNotificationEndpointWebhook(request);
|
|
4760
|
-
return runPbs(props.target, "provision", operation).pipe(
|
|
4792
|
+
return runPbs(props.target, "provision", operation).pipe(Effect66.catchTag("NotFound", () => Effect66.void));
|
|
4761
4793
|
};
|
|
4762
4794
|
|
|
4763
4795
|
// src/proxmox/pbs-notification-target-endpoint.ts
|
|
@@ -4948,7 +4980,7 @@ var targetForm = (props, groups, carry, mode) => {
|
|
|
4948
4980
|
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
4949
4981
|
var refuse2 = (props) => {
|
|
4950
4982
|
const reasons = refusals(props);
|
|
4951
|
-
return reasons.length === 0 ?
|
|
4983
|
+
return reasons.length === 0 ? Effect67.void : Effect67.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
4952
4984
|
};
|
|
4953
4985
|
var toCarry = (live, props, groups, sealed) => {
|
|
4954
4986
|
const header = headerState(live, props, groups) === "stale";
|
|
@@ -4960,17 +4992,17 @@ var requireValues = (props, groups, carry) => {
|
|
|
4960
4992
|
...carry.header ? groups.header.missing : [],
|
|
4961
4993
|
...carry.sealed ? groups.sealed.missing : []
|
|
4962
4994
|
];
|
|
4963
|
-
return missing.length === 0 ?
|
|
4995
|
+
return missing.length === 0 ? Effect67.void : Effect67.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."));
|
|
4964
4996
|
};
|
|
4965
|
-
var
|
|
4966
|
-
list: () =>
|
|
4967
|
-
read: ({ olds, output }) => (output === undefined ? refuse2(olds) :
|
|
4997
|
+
var handlers8 = {
|
|
4998
|
+
list: () => Effect67.succeed([]),
|
|
4999
|
+
read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect67.void).pipe(Effect67.andThen(readTarget2(olds)), Effect67.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
|
|
4968
5000
|
diff: ({
|
|
4969
5001
|
news,
|
|
4970
5002
|
olds,
|
|
4971
5003
|
output
|
|
4972
|
-
}) =>
|
|
4973
|
-
if (output === undefined || !
|
|
5004
|
+
}) => Effect67.gen(function* () {
|
|
5005
|
+
if (output === undefined || !isResolved20(news))
|
|
4974
5006
|
return;
|
|
4975
5007
|
yield* refuse2(news);
|
|
4976
5008
|
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
@@ -4991,7 +5023,7 @@ var handlers9 = {
|
|
|
4991
5023
|
return { action: "update" };
|
|
4992
5024
|
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
4993
5025
|
}),
|
|
4994
|
-
reconcile: ({ news, output }) =>
|
|
5026
|
+
reconcile: ({ news, output }) => Effect67.gen(function* () {
|
|
4995
5027
|
yield* refuse2(news);
|
|
4996
5028
|
const groups = resolveGroups(news);
|
|
4997
5029
|
const live = yield* readTarget2(news);
|
|
@@ -5016,7 +5048,7 @@ var handlers9 = {
|
|
|
5016
5048
|
}
|
|
5017
5049
|
const after = yield* readTarget2(news);
|
|
5018
5050
|
if (after === undefined) {
|
|
5019
|
-
return yield*
|
|
5051
|
+
return yield* Effect67.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
5020
5052
|
}
|
|
5021
5053
|
return { ...after, sealed };
|
|
5022
5054
|
}),
|
|
@@ -5025,15 +5057,15 @@ var handlers9 = {
|
|
|
5025
5057
|
|
|
5026
5058
|
// src/proxmox/pbs-notification-target.ts
|
|
5027
5059
|
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
5028
|
-
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget,
|
|
5060
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect68.succeed(PbsNotificationTarget.Provider.of(handlers8)));
|
|
5029
5061
|
// src/proxmox/pbs-prune-job.ts
|
|
5030
5062
|
import { Resource as Resource22 } from "alchemy";
|
|
5031
5063
|
import * as Provider22 from "alchemy/Provider";
|
|
5032
|
-
import * as
|
|
5064
|
+
import * as Effect71 from "effect/Effect";
|
|
5033
5065
|
|
|
5034
5066
|
// src/proxmox/pbs-prune-job-lifecycle.ts
|
|
5035
|
-
import { isResolved as
|
|
5036
|
-
import * as
|
|
5067
|
+
import { isResolved as isResolved21 } from "alchemy/Diff";
|
|
5068
|
+
import * as Effect70 from "effect/Effect";
|
|
5037
5069
|
|
|
5038
5070
|
// src/proxmox/pbs-prune-job-form.ts
|
|
5039
5071
|
var KEEP_KEYS = [
|
|
@@ -5111,7 +5143,7 @@ var spec = {
|
|
|
5111
5143
|
|
|
5112
5144
|
// src/proxmox/pbs-prune-job-wire.ts
|
|
5113
5145
|
import * as config4 from "@distilled.cloud/proxmox-backup/config";
|
|
5114
|
-
import * as
|
|
5146
|
+
import * as Effect69 from "effect/Effect";
|
|
5115
5147
|
var members2 = (form) => ({
|
|
5116
5148
|
...form["comment"] === undefined ? {} : { comment: form["comment"] },
|
|
5117
5149
|
...form["disable"] === undefined ? {} : { disable: form["disable"] },
|
|
@@ -5146,10 +5178,10 @@ var wire2 = (row) => ({
|
|
|
5146
5178
|
"keep-yearly": row.keep_yearly,
|
|
5147
5179
|
"max-depth": row.max_depth
|
|
5148
5180
|
});
|
|
5149
|
-
var readOne2 = (props) => runPbs(props.target, "read", config4.getConfigPrune({ id: props.id })).pipe(
|
|
5181
|
+
var readOne2 = (props) => runPbs(props.target, "read", config4.getConfigPrune({ id: props.id })).pipe(Effect69.map((row) => spec.attributes(wire2(row), props)), Effect69.catchTag("PruneJobNotFound", () => Effect69.succeed(undefined)));
|
|
5150
5182
|
var createOne2 = (props) => runPbs(props.target, "provision", config4.createConfigPrune(createRequest2(props)));
|
|
5151
5183
|
var updateOne2 = (props) => runPbs(props.target, "provision", config4.putConfigPrune(updateRequest2(props)));
|
|
5152
|
-
var deleteOne2 = (props) =>
|
|
5184
|
+
var deleteOne2 = (props) => Effect69.gen(function* () {
|
|
5153
5185
|
if ((yield* readOne2(props)) === undefined)
|
|
5154
5186
|
return;
|
|
5155
5187
|
return yield* runPbs(props.target, "provision", config4.deleteConfigPrune({ id: props.id }));
|
|
@@ -5157,14 +5189,14 @@ var deleteOne2 = (props) => Effect68.gen(function* () {
|
|
|
5157
5189
|
|
|
5158
5190
|
// src/proxmox/pbs-prune-job-lifecycle.ts
|
|
5159
5191
|
var { guardCreate: guardCreate6, guardUpdate: guardUpdate6 } = specGuards(spec);
|
|
5160
|
-
var
|
|
5161
|
-
list: () =>
|
|
5192
|
+
var handlers9 = {
|
|
5193
|
+
list: () => Effect70.succeed([]),
|
|
5162
5194
|
read: ({ olds }) => readOne2(olds),
|
|
5163
5195
|
diff: ({
|
|
5164
5196
|
news,
|
|
5165
5197
|
output
|
|
5166
|
-
}) =>
|
|
5167
|
-
if (!
|
|
5198
|
+
}) => Effect70.gen(function* () {
|
|
5199
|
+
if (!isResolved21(news))
|
|
5168
5200
|
return;
|
|
5169
5201
|
yield* guardCreate6(news, output === undefined);
|
|
5170
5202
|
yield* guardUpdate6(news);
|
|
@@ -5177,7 +5209,7 @@ var handlers10 = {
|
|
|
5177
5209
|
}
|
|
5178
5210
|
return { action: spec.matches(live, news) ? "noop" : "update" };
|
|
5179
5211
|
}),
|
|
5180
|
-
reconcile: ({ news }) =>
|
|
5212
|
+
reconcile: ({ news }) => Effect70.gen(function* () {
|
|
5181
5213
|
const live = yield* readOne2(news);
|
|
5182
5214
|
yield* guardCreate6(news, live === undefined);
|
|
5183
5215
|
yield* guardUpdate6(news);
|
|
@@ -5187,7 +5219,7 @@ var handlers10 = {
|
|
|
5187
5219
|
yield* updateOne2(news);
|
|
5188
5220
|
const after = yield* readOne2(news);
|
|
5189
5221
|
if (after === undefined) {
|
|
5190
|
-
return yield*
|
|
5222
|
+
return yield* Effect70.fail(new Error(`${spec.path(news)}: write succeeded but job is absent.`));
|
|
5191
5223
|
}
|
|
5192
5224
|
return after;
|
|
5193
5225
|
}),
|
|
@@ -5196,15 +5228,15 @@ var handlers10 = {
|
|
|
5196
5228
|
|
|
5197
5229
|
// src/proxmox/pbs-prune-job.ts
|
|
5198
5230
|
var PbsPruneJob = Resource22("Pbs.PruneJob");
|
|
5199
|
-
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob,
|
|
5231
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect71.succeed(PbsPruneJob.Provider.of(handlers9)));
|
|
5200
5232
|
// src/proxmox/pbs-sync-job.ts
|
|
5201
5233
|
import { Resource as Resource23 } from "alchemy";
|
|
5202
5234
|
import * as Provider23 from "alchemy/Provider";
|
|
5203
|
-
import * as
|
|
5235
|
+
import * as Effect74 from "effect/Effect";
|
|
5204
5236
|
|
|
5205
5237
|
// src/proxmox/pbs-sync-job-lifecycle.ts
|
|
5206
|
-
import { isResolved as
|
|
5207
|
-
import * as
|
|
5238
|
+
import { isResolved as isResolved22 } from "alchemy/Diff";
|
|
5239
|
+
import * as Effect73 from "effect/Effect";
|
|
5208
5240
|
|
|
5209
5241
|
// src/proxmox/pbs-sync-job-form.ts
|
|
5210
5242
|
var UNSET4 = -1;
|
|
@@ -5281,7 +5313,7 @@ var spec2 = {
|
|
|
5281
5313
|
|
|
5282
5314
|
// src/proxmox/pbs-sync-job-wire.ts
|
|
5283
5315
|
import * as config5 from "@distilled.cloud/proxmox-backup/config";
|
|
5284
|
-
import * as
|
|
5316
|
+
import * as Effect72 from "effect/Effect";
|
|
5285
5317
|
var members3 = (form) => ({
|
|
5286
5318
|
...form["remote-store"] === undefined ? {} : { remote_store: form["remote-store"] },
|
|
5287
5319
|
...form["remove-vanished"] === undefined ? {} : { remove_vanished: form["remove-vanished"] },
|
|
@@ -5320,10 +5352,10 @@ var wire3 = (row) => ({
|
|
|
5320
5352
|
"sync-direction": row.sync_direction,
|
|
5321
5353
|
"group-filter": row.group_filter
|
|
5322
5354
|
});
|
|
5323
|
-
var readOne3 = (props) => runPbs(props.target, "read", config5.getConfigSync({ id: props.id })).pipe(
|
|
5355
|
+
var readOne3 = (props) => runPbs(props.target, "read", config5.getConfigSync({ id: props.id })).pipe(Effect72.map((row) => spec2.attributes(wire3(row), props)), Effect72.catchTag("SyncJobNotFound", () => Effect72.succeed(undefined)));
|
|
5324
5356
|
var createOne3 = (props) => runPbs(props.target, "provision", config5.syncConfig(createRequest3(props)));
|
|
5325
5357
|
var updateOne3 = (props) => runPbs(props.target, "provision", config5.putConfigSync(updateRequest3(props)));
|
|
5326
|
-
var deleteOne3 = (props) =>
|
|
5358
|
+
var deleteOne3 = (props) => Effect72.gen(function* () {
|
|
5327
5359
|
if ((yield* readOne3(props)) === undefined)
|
|
5328
5360
|
return;
|
|
5329
5361
|
return yield* runPbs(props.target, "provision", config5.deleteConfigSync({ id: props.id }));
|
|
@@ -5331,11 +5363,11 @@ var deleteOne3 = (props) => Effect71.gen(function* () {
|
|
|
5331
5363
|
|
|
5332
5364
|
// src/proxmox/pbs-sync-job-lifecycle.ts
|
|
5333
5365
|
var { guardCreate: guardCreate7, guardUpdate: guardUpdate7 } = specGuards(spec2);
|
|
5334
|
-
var
|
|
5335
|
-
list: () =>
|
|
5366
|
+
var handlers10 = {
|
|
5367
|
+
list: () => Effect73.succeed([]),
|
|
5336
5368
|
read: ({ olds }) => readOne3(olds),
|
|
5337
|
-
diff: ({ news, output }) =>
|
|
5338
|
-
if (!
|
|
5369
|
+
diff: ({ news, output }) => Effect73.gen(function* () {
|
|
5370
|
+
if (!isResolved22(news))
|
|
5339
5371
|
return;
|
|
5340
5372
|
yield* guardCreate7(news, output === undefined);
|
|
5341
5373
|
yield* guardUpdate7(news);
|
|
@@ -5348,7 +5380,7 @@ var handlers11 = {
|
|
|
5348
5380
|
}
|
|
5349
5381
|
return { action: spec2.matches(live, news) ? "noop" : "update" };
|
|
5350
5382
|
}),
|
|
5351
|
-
reconcile: ({ news }) =>
|
|
5383
|
+
reconcile: ({ news }) => Effect73.gen(function* () {
|
|
5352
5384
|
const live = yield* readOne3(news);
|
|
5353
5385
|
yield* guardCreate7(news, live === undefined);
|
|
5354
5386
|
yield* guardUpdate7(news);
|
|
@@ -5358,7 +5390,7 @@ var handlers11 = {
|
|
|
5358
5390
|
yield* updateOne3(news);
|
|
5359
5391
|
const after = yield* readOne3(news);
|
|
5360
5392
|
if (after === undefined) {
|
|
5361
|
-
return yield*
|
|
5393
|
+
return yield* Effect73.fail(new Error(`${spec2.path(news)}: write succeeded but job is absent.`));
|
|
5362
5394
|
}
|
|
5363
5395
|
return after;
|
|
5364
5396
|
}),
|
|
@@ -5367,15 +5399,15 @@ var handlers11 = {
|
|
|
5367
5399
|
|
|
5368
5400
|
// src/proxmox/pbs-sync-job.ts
|
|
5369
5401
|
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
5370
|
-
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob,
|
|
5402
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect74.succeed(PbsSyncJob.Provider.of(handlers10)));
|
|
5371
5403
|
// src/proxmox/pbs-verify-job.ts
|
|
5372
5404
|
import { Resource as Resource24 } from "alchemy";
|
|
5373
5405
|
import * as Provider24 from "alchemy/Provider";
|
|
5374
|
-
import * as
|
|
5406
|
+
import * as Effect77 from "effect/Effect";
|
|
5375
5407
|
|
|
5376
5408
|
// src/proxmox/pbs-verify-job-lifecycle.ts
|
|
5377
|
-
import { isResolved as
|
|
5378
|
-
import * as
|
|
5409
|
+
import { isResolved as isResolved23 } from "alchemy/Diff";
|
|
5410
|
+
import * as Effect76 from "effect/Effect";
|
|
5379
5411
|
|
|
5380
5412
|
// src/proxmox/pbs-verify-job-form.ts
|
|
5381
5413
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -5422,7 +5454,7 @@ var spec3 = {
|
|
|
5422
5454
|
|
|
5423
5455
|
// src/proxmox/pbs-verify-job-wire.ts
|
|
5424
5456
|
import * as config6 from "@distilled.cloud/proxmox-backup/config";
|
|
5425
|
-
import * as
|
|
5457
|
+
import * as Effect75 from "effect/Effect";
|
|
5426
5458
|
var members4 = (form) => ({
|
|
5427
5459
|
...form["ignore-verified"] === undefined ? {} : { ignore_verified: form["ignore-verified"] },
|
|
5428
5460
|
...form["store"] === undefined ? {} : { store: form["store"] },
|
|
@@ -5447,10 +5479,10 @@ var wire4 = (row) => ({
|
|
|
5447
5479
|
"max-depth": row.max_depth,
|
|
5448
5480
|
"outdated-after": row.outdated_after
|
|
5449
5481
|
});
|
|
5450
|
-
var readOne4 = (props) => runPbs(props.target, "read", config6.getConfigVerify({ id: props.id })).pipe(
|
|
5482
|
+
var readOne4 = (props) => runPbs(props.target, "read", config6.getConfigVerify({ id: props.id })).pipe(Effect75.map((row) => spec3.attributes(wire4(row), props)), Effect75.catchTag("VerifyJobNotFound", () => Effect75.succeed(undefined)));
|
|
5451
5483
|
var createOne4 = (props) => runPbs(props.target, "provision", config6.verifyConfig(createRequest4(props)));
|
|
5452
5484
|
var updateOne4 = (props) => runPbs(props.target, "provision", config6.putConfigVerify(updateRequest4(props)));
|
|
5453
|
-
var deleteOne4 = (props) =>
|
|
5485
|
+
var deleteOne4 = (props) => Effect75.gen(function* () {
|
|
5454
5486
|
if ((yield* readOne4(props)) === undefined)
|
|
5455
5487
|
return;
|
|
5456
5488
|
return yield* runPbs(props.target, "provision", config6.deleteConfigVerify({ id: props.id }));
|
|
@@ -5458,14 +5490,14 @@ var deleteOne4 = (props) => Effect74.gen(function* () {
|
|
|
5458
5490
|
|
|
5459
5491
|
// src/proxmox/pbs-verify-job-lifecycle.ts
|
|
5460
5492
|
var { guardCreate: guardCreate8, guardUpdate: guardUpdate8 } = specGuards(spec3);
|
|
5461
|
-
var
|
|
5462
|
-
list: () =>
|
|
5493
|
+
var handlers11 = {
|
|
5494
|
+
list: () => Effect76.succeed([]),
|
|
5463
5495
|
read: ({ olds }) => readOne4(olds),
|
|
5464
5496
|
diff: ({
|
|
5465
5497
|
news,
|
|
5466
5498
|
output
|
|
5467
|
-
}) =>
|
|
5468
|
-
if (!
|
|
5499
|
+
}) => Effect76.gen(function* () {
|
|
5500
|
+
if (!isResolved23(news))
|
|
5469
5501
|
return;
|
|
5470
5502
|
yield* guardCreate8(news, output === undefined);
|
|
5471
5503
|
yield* guardUpdate8(news);
|
|
@@ -5478,7 +5510,7 @@ var handlers12 = {
|
|
|
5478
5510
|
}
|
|
5479
5511
|
return { action: spec3.matches(live, news) ? "noop" : "update" };
|
|
5480
5512
|
}),
|
|
5481
|
-
reconcile: ({ news }) =>
|
|
5513
|
+
reconcile: ({ news }) => Effect76.gen(function* () {
|
|
5482
5514
|
const live = yield* readOne4(news);
|
|
5483
5515
|
yield* guardCreate8(news, live === undefined);
|
|
5484
5516
|
yield* guardUpdate8(news);
|
|
@@ -5488,7 +5520,7 @@ var handlers12 = {
|
|
|
5488
5520
|
yield* updateOne4(news);
|
|
5489
5521
|
const after = yield* readOne4(news);
|
|
5490
5522
|
if (after === undefined) {
|
|
5491
|
-
return yield*
|
|
5523
|
+
return yield* Effect76.fail(new Error(`${spec3.path(news)}: write succeeded but job is absent.`));
|
|
5492
5524
|
}
|
|
5493
5525
|
return after;
|
|
5494
5526
|
}),
|
|
@@ -5497,15 +5529,15 @@ var handlers12 = {
|
|
|
5497
5529
|
|
|
5498
5530
|
// src/proxmox/pbs-verify-job.ts
|
|
5499
5531
|
var PbsVerifyJob = Resource24("Pbs.VerifyJob");
|
|
5500
|
-
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob,
|
|
5532
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect77.succeed(PbsVerifyJob.Provider.of(handlers11)));
|
|
5501
5533
|
// src/proxmox/pool.ts
|
|
5502
5534
|
import { Resource as Resource25 } from "alchemy";
|
|
5503
|
-
import { isResolved as
|
|
5535
|
+
import { isResolved as isResolved24 } from "alchemy/Diff";
|
|
5504
5536
|
import * as Provider25 from "alchemy/Provider";
|
|
5505
5537
|
import * as pools from "@distilled.cloud/proxmox/pools";
|
|
5506
5538
|
import { ProxmoxParseError as ProxmoxParseError5 } from "@distilled.cloud/proxmox/Errors";
|
|
5507
5539
|
import * as Schema5 from "effect/Schema";
|
|
5508
|
-
import * as
|
|
5540
|
+
import * as Effect78 from "effect/Effect";
|
|
5509
5541
|
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
5510
5542
|
var poolCreateForm = (props) => ({
|
|
5511
5543
|
comment: props.comment ?? "",
|
|
@@ -5531,16 +5563,16 @@ var spec4 = {
|
|
|
5531
5563
|
updateForm: poolUpdateForm
|
|
5532
5564
|
};
|
|
5533
5565
|
var { guardCreate: guardCreate9, guardUpdate: guardUpdate9 } = specGuards(spec4);
|
|
5534
|
-
var readPool = (props) => runPve(props.target, "read", false, pools.getPool({ poolid: props.poolid })).pipe(
|
|
5566
|
+
var readPool = (props) => runPve(props.target, "read", false, pools.getPool({ poolid: props.poolid })).pipe(Effect78.flatMap((live) => Schema5.decodeUnknownEffect(Schema5.toType(pools.GetPoolResponse))(live).pipe(Effect78.mapError(() => new ProxmoxParseError5({
|
|
5535
5567
|
body: undefined,
|
|
5536
5568
|
cause: "Pool response does not match its vendor schema"
|
|
5537
|
-
})),
|
|
5538
|
-
var deletePool2 = (props) => runPve(props.target, "provision", true, pools.deletePool({ poolid: props.poolid })).pipe(
|
|
5539
|
-
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool,
|
|
5540
|
-
list: () =>
|
|
5569
|
+
})), Effect78.as(live))), Effect78.map((live) => spec4.attributes({ ...live }, props)), Effect78.catchTag("PoolNotFound", () => Effect78.succeed(undefined)), Effect78.catchTag("NotFound", () => Effect78.succeed(undefined)));
|
|
5570
|
+
var deletePool2 = (props) => runPve(props.target, "provision", true, pools.deletePool({ poolid: props.poolid })).pipe(Effect78.catchTag("PoolNotFound", () => Effect78.void), Effect78.catchTag("NotFound", () => Effect78.void));
|
|
5571
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect78.succeed(ProxmoxPool.Provider.of({
|
|
5572
|
+
list: () => Effect78.succeed([]),
|
|
5541
5573
|
read: ({ olds }) => readPool(olds),
|
|
5542
|
-
diff:
|
|
5543
|
-
if (!
|
|
5574
|
+
diff: Effect78.fn(function* ({ news, output }) {
|
|
5575
|
+
if (!isResolved24(news))
|
|
5544
5576
|
return;
|
|
5545
5577
|
yield* guardCreate9(news, output === undefined);
|
|
5546
5578
|
yield* guardUpdate9(news);
|
|
@@ -5553,7 +5585,7 @@ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect77.succeed(
|
|
|
5553
5585
|
}
|
|
5554
5586
|
return { action: spec4.matches(live, news) ? "noop" : "update" };
|
|
5555
5587
|
}),
|
|
5556
|
-
reconcile:
|
|
5588
|
+
reconcile: Effect78.fn(function* ({ news }) {
|
|
5557
5589
|
const live = yield* readPool(news);
|
|
5558
5590
|
yield* guardCreate9(news, live === undefined);
|
|
5559
5591
|
yield* guardUpdate9(news);
|
|
@@ -5569,7 +5601,7 @@ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect77.succeed(
|
|
|
5569
5601
|
}
|
|
5570
5602
|
const after = yield* readPool(news);
|
|
5571
5603
|
if (after === undefined)
|
|
5572
|
-
return yield*
|
|
5604
|
+
return yield* Effect78.fail(new Error(`pools/${news.poolid}: write returned success but the pool is still absent`));
|
|
5573
5605
|
return after;
|
|
5574
5606
|
}),
|
|
5575
5607
|
delete: ({ olds }) => deletePool2(olds)
|
|
@@ -5766,14 +5798,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
5766
5798
|
// src/proxmox/provision-declare.ts
|
|
5767
5799
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
5768
5800
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
5769
|
-
import * as
|
|
5801
|
+
import * as Effect82 from "effect/Effect";
|
|
5770
5802
|
|
|
5771
5803
|
// src/proxmox/role.ts
|
|
5772
5804
|
import { Resource as Resource26 } from "alchemy";
|
|
5773
|
-
import { isResolved as
|
|
5805
|
+
import { isResolved as isResolved25 } from "alchemy/Diff";
|
|
5774
5806
|
import * as Provider26 from "alchemy/Provider";
|
|
5775
5807
|
import * as access5 from "@distilled.cloud/proxmox/access";
|
|
5776
|
-
import * as
|
|
5808
|
+
import * as Effect79 from "effect/Effect";
|
|
5777
5809
|
|
|
5778
5810
|
// src/proxmox/role-wire.ts
|
|
5779
5811
|
var ROLE_CREATE = "pve:POST /access/roles";
|
|
@@ -5783,36 +5815,36 @@ var createForm7 = (props) => ({
|
|
|
5783
5815
|
privs: canonical2(props.privs).join(","),
|
|
5784
5816
|
roleid: props.roleid
|
|
5785
5817
|
});
|
|
5786
|
-
var
|
|
5818
|
+
var updateForm5 = (props) => ({
|
|
5787
5819
|
privs: canonical2(props.privs).join(","),
|
|
5788
5820
|
roleid: props.roleid
|
|
5789
5821
|
});
|
|
5790
5822
|
var find2 = (rows, roleid) => rows.find((row) => row.roleid === roleid);
|
|
5791
|
-
var
|
|
5823
|
+
var attributesOf8 = (row, props) => ({
|
|
5792
5824
|
privs: canonical2(row.privs === undefined ? [] : row.privs.split(",")),
|
|
5793
5825
|
roleid: props.roleid
|
|
5794
5826
|
});
|
|
5795
|
-
var
|
|
5827
|
+
var matches8 = (attributes2, props) => canonical2(attributes2.privs).join(",") === canonical2(props.privs).join(",");
|
|
5796
5828
|
|
|
5797
5829
|
// src/proxmox/role.ts
|
|
5798
5830
|
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
5799
|
-
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(
|
|
5831
|
+
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect79.map((rows) => {
|
|
5800
5832
|
if (rows === UNREADABLE)
|
|
5801
5833
|
return UNREADABLE;
|
|
5802
5834
|
const row = find2(rows, props.roleid);
|
|
5803
|
-
return row === undefined ? undefined :
|
|
5835
|
+
return row === undefined ? undefined : attributesOf8(row, props);
|
|
5804
5836
|
}));
|
|
5805
5837
|
var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
|
|
5806
|
-
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole,
|
|
5807
|
-
list: () =>
|
|
5808
|
-
read:
|
|
5838
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect79.succeed(ProxmoxRole.Provider.of({
|
|
5839
|
+
list: () => Effect79.succeed([]),
|
|
5840
|
+
read: Effect79.fn(function* ({ olds }) {
|
|
5809
5841
|
return dropUnreadable5(yield* readRole(olds));
|
|
5810
5842
|
}),
|
|
5811
|
-
diff:
|
|
5812
|
-
if (!
|
|
5843
|
+
diff: Effect79.fn(function* ({ news, output }) {
|
|
5844
|
+
if (!isResolved25(news))
|
|
5813
5845
|
return;
|
|
5814
5846
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), output === undefined);
|
|
5815
|
-
yield* guardWrite2(ROLE_UPDATE,
|
|
5847
|
+
yield* guardWrite2(ROLE_UPDATE, updateForm5(news), false);
|
|
5816
5848
|
if (output === undefined)
|
|
5817
5849
|
return;
|
|
5818
5850
|
const live = yield* readRole(news);
|
|
@@ -5824,38 +5856,38 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect78.succeed(
|
|
|
5824
5856
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), true);
|
|
5825
5857
|
return { action: "update" };
|
|
5826
5858
|
}
|
|
5827
|
-
return
|
|
5859
|
+
return matches8(live, news) ? { action: "noop" } : { action: "update" };
|
|
5828
5860
|
}),
|
|
5829
|
-
reconcile:
|
|
5861
|
+
reconcile: Effect79.fn(function* ({ news }) {
|
|
5830
5862
|
const before = dropUnreadable5(yield* readRole(news));
|
|
5831
5863
|
yield* guardWrite2(ROLE_CREATE, createForm7(news), before === undefined);
|
|
5832
|
-
yield* guardWrite2(ROLE_UPDATE,
|
|
5864
|
+
yield* guardWrite2(ROLE_UPDATE, updateForm5(news), false);
|
|
5833
5865
|
if (before === undefined) {
|
|
5834
5866
|
yield* runPve(news.target, "provision", true, access5.createAccessRole(createForm7(news)));
|
|
5835
|
-
} else if (!
|
|
5836
|
-
yield* runPve(news.target, "provision", true, access5.putAccessRole(
|
|
5867
|
+
} else if (!matches8(before, news)) {
|
|
5868
|
+
yield* runPve(news.target, "provision", true, access5.putAccessRole(updateForm5(news)));
|
|
5837
5869
|
}
|
|
5838
5870
|
const after = dropUnreadable5(yield* readRole(news));
|
|
5839
5871
|
if (after === undefined) {
|
|
5840
|
-
return yield*
|
|
5872
|
+
return yield* Effect79.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."));
|
|
5841
5873
|
}
|
|
5842
5874
|
return after;
|
|
5843
5875
|
}),
|
|
5844
|
-
delete:
|
|
5876
|
+
delete: Effect79.fn(function* ({ olds }) {
|
|
5845
5877
|
yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
|
|
5846
5878
|
})
|
|
5847
5879
|
})));
|
|
5848
5880
|
|
|
5849
5881
|
// src/proxmox/user.ts
|
|
5850
5882
|
import { Resource as Resource27 } from "alchemy";
|
|
5851
|
-
import { isResolved as
|
|
5883
|
+
import { isResolved as isResolved26 } from "alchemy/Diff";
|
|
5852
5884
|
import * as Provider27 from "alchemy/Provider";
|
|
5853
5885
|
import * as access7 from "@distilled.cloud/proxmox/access";
|
|
5854
|
-
import * as
|
|
5886
|
+
import * as Effect81 from "effect/Effect";
|
|
5855
5887
|
|
|
5856
5888
|
// src/proxmox/user-wire.ts
|
|
5857
5889
|
import * as access6 from "@distilled.cloud/proxmox/access";
|
|
5858
|
-
import * as
|
|
5890
|
+
import * as Effect80 from "effect/Effect";
|
|
5859
5891
|
var USER_CREATE = "pve:POST /access/users";
|
|
5860
5892
|
var USER_UPDATE = "pve:PUT /access/users/{userid}";
|
|
5861
5893
|
var int2 = (value) => {
|
|
@@ -5881,11 +5913,11 @@ var createForm8 = (props) => ({
|
|
|
5881
5913
|
...shape8(props),
|
|
5882
5914
|
userid: props.userid
|
|
5883
5915
|
});
|
|
5884
|
-
var
|
|
5916
|
+
var updateForm6 = (props) => ({
|
|
5885
5917
|
...shape8(props),
|
|
5886
5918
|
userid: props.userid
|
|
5887
5919
|
});
|
|
5888
|
-
var
|
|
5920
|
+
var attributesOf9 = (live, props) => ({
|
|
5889
5921
|
comment: text(live.comment),
|
|
5890
5922
|
email: text(live.email),
|
|
5891
5923
|
enable: bool(live.enable, true),
|
|
@@ -5896,23 +5928,23 @@ var attributesOf8 = (live, props) => ({
|
|
|
5896
5928
|
tokens: tokenNames(live.tokens),
|
|
5897
5929
|
userid: props.userid
|
|
5898
5930
|
});
|
|
5899
|
-
var
|
|
5900
|
-
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(
|
|
5901
|
-
var readUser = (props) => readUserOrFail(props).pipe(
|
|
5931
|
+
var matches9 = (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(",");
|
|
5932
|
+
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect80.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf9(live, props)));
|
|
5933
|
+
var readUser = (props) => readUserOrFail(props).pipe(Effect80.catchTag("UserNotFound", () => Effect80.succeed(undefined)));
|
|
5902
5934
|
var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
|
|
5903
5935
|
|
|
5904
5936
|
// src/proxmox/user.ts
|
|
5905
5937
|
var ProxmoxUser = Resource27("Proxmox.User");
|
|
5906
|
-
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser,
|
|
5907
|
-
list: () =>
|
|
5908
|
-
read:
|
|
5938
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect81.succeed(ProxmoxUser.Provider.of({
|
|
5939
|
+
list: () => Effect81.succeed([]),
|
|
5940
|
+
read: Effect81.fn(function* ({ olds, output }) {
|
|
5909
5941
|
return dropUnreadable6(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
|
|
5910
5942
|
}),
|
|
5911
|
-
diff:
|
|
5912
|
-
if (!
|
|
5943
|
+
diff: Effect81.fn(function* ({ news, output }) {
|
|
5944
|
+
if (!isResolved26(news))
|
|
5913
5945
|
return;
|
|
5914
5946
|
yield* guardWrite2(USER_CREATE, createForm8(news), output === undefined);
|
|
5915
|
-
yield* guardWrite2(USER_UPDATE,
|
|
5947
|
+
yield* guardWrite2(USER_UPDATE, updateForm6(news), false);
|
|
5916
5948
|
if (output === undefined)
|
|
5917
5949
|
return;
|
|
5918
5950
|
const live = yield* readUserOrFail(news);
|
|
@@ -5924,31 +5956,31 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect80.succeed(
|
|
|
5924
5956
|
yield* guardWrite2(USER_CREATE, createForm8(news), true);
|
|
5925
5957
|
return { action: "update" };
|
|
5926
5958
|
}
|
|
5927
|
-
return
|
|
5959
|
+
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
5928
5960
|
}),
|
|
5929
|
-
reconcile:
|
|
5961
|
+
reconcile: Effect81.fn(function* ({ news }) {
|
|
5930
5962
|
const before = dropUnreadable6(yield* readUser(news));
|
|
5931
5963
|
yield* guardWrite2(USER_CREATE, createForm8(news), before === undefined);
|
|
5932
|
-
yield* guardWrite2(USER_UPDATE,
|
|
5964
|
+
yield* guardWrite2(USER_UPDATE, updateForm6(news), false);
|
|
5933
5965
|
if (before === undefined) {
|
|
5934
5966
|
yield* runPve(news.target, "provision", true, access7.createAccessUser(createForm8(news)));
|
|
5935
|
-
} else if (!
|
|
5936
|
-
yield* runPve(news.target, "provision", true, access7.putAccessUser(
|
|
5967
|
+
} else if (!matches9(before, news)) {
|
|
5968
|
+
yield* runPve(news.target, "provision", true, access7.putAccessUser(updateForm6(news)));
|
|
5937
5969
|
}
|
|
5938
5970
|
const after = dropUnreadable6(yield* readUser(news));
|
|
5939
5971
|
if (after === undefined) {
|
|
5940
|
-
return yield*
|
|
5972
|
+
return yield* Effect81.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."));
|
|
5941
5973
|
}
|
|
5942
5974
|
return after;
|
|
5943
5975
|
}),
|
|
5944
|
-
delete:
|
|
5976
|
+
delete: Effect81.fn(function* ({ olds }) {
|
|
5945
5977
|
yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
|
|
5946
5978
|
})
|
|
5947
5979
|
})));
|
|
5948
5980
|
|
|
5949
5981
|
// src/proxmox/provision-declare.ts
|
|
5950
|
-
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) =>
|
|
5951
|
-
const baseline = yield*
|
|
5982
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect82.gen(function* () {
|
|
5983
|
+
const baseline = yield* Effect82.try({
|
|
5952
5984
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
5953
5985
|
try: () => provisionBaseline(names2)
|
|
5954
5986
|
});
|
|
@@ -5962,13 +5994,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
5962
5994
|
target
|
|
5963
5995
|
}));
|
|
5964
5996
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
5965
|
-
const users = yield*
|
|
5997
|
+
const users = yield* Effect82.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
5966
5998
|
comment: user.comment,
|
|
5967
5999
|
groups: [...user.groups],
|
|
5968
6000
|
target,
|
|
5969
6001
|
userid: user.userid
|
|
5970
6002
|
}))));
|
|
5971
|
-
const grants = yield*
|
|
6003
|
+
const grants = yield* Effect82.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
5972
6004
|
path: "/",
|
|
5973
6005
|
propagate: true,
|
|
5974
6006
|
roleid: grant.roleid,
|
|
@@ -5981,12 +6013,12 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
5981
6013
|
// src/proxmox/qemu.ts
|
|
5982
6014
|
import { Resource as Resource28 } from "alchemy";
|
|
5983
6015
|
import * as Provider28 from "alchemy/Provider";
|
|
5984
|
-
import * as
|
|
6016
|
+
import * as Effect86 from "effect/Effect";
|
|
5985
6017
|
|
|
5986
6018
|
// src/proxmox/qemu-lifecycle.ts
|
|
5987
|
-
import { isResolved as
|
|
6019
|
+
import { isResolved as isResolved27 } from "alchemy/Diff";
|
|
5988
6020
|
import * as nodes17 from "@distilled.cloud/proxmox/nodes";
|
|
5989
|
-
import * as
|
|
6021
|
+
import * as Effect85 from "effect/Effect";
|
|
5990
6022
|
|
|
5991
6023
|
// src/proxmox/qemu-props.ts
|
|
5992
6024
|
var NOT_CONFIG2 = new Set(["node", "target", "vmid"]);
|
|
@@ -6047,7 +6079,7 @@ var createForm9 = (props) => ({
|
|
|
6047
6079
|
...form(props),
|
|
6048
6080
|
vmid: String(props.vmid)
|
|
6049
6081
|
});
|
|
6050
|
-
var
|
|
6082
|
+
var updateForm7 = form;
|
|
6051
6083
|
|
|
6052
6084
|
// src/proxmox/qemu-errors.ts
|
|
6053
6085
|
class QemuRefusedError extends Error {
|
|
@@ -6142,7 +6174,7 @@ var netPairs = (value) => new Map(value.split(",").map((part) => part.trim()).fi
|
|
|
6142
6174
|
const at = part.indexOf("=");
|
|
6143
6175
|
return at === -1 ? [part, ""] : [part.slice(0, at), part.slice(at + 1)];
|
|
6144
6176
|
}));
|
|
6145
|
-
var modelKey = (
|
|
6177
|
+
var modelKey = (map32) => NIC_MODELS.find((model) => map32.has(model));
|
|
6146
6178
|
var netMaps2 = (declared2, live) => {
|
|
6147
6179
|
const want = netPairs(declared2);
|
|
6148
6180
|
const have = netPairs(live);
|
|
@@ -6213,44 +6245,44 @@ var judge2 = (props, config7) => {
|
|
|
6213
6245
|
var identityRefusal = (vmid, was) => was === undefined || vmid === was ? undefined : `vmid: ${String(was)} -> ${String(vmid)} is a different VM. Declare it as a new resource; ` + "this one is retained when its declaration goes.";
|
|
6214
6246
|
|
|
6215
6247
|
// src/proxmox/qemu-read.ts
|
|
6216
|
-
import * as
|
|
6248
|
+
import * as cluster11 from "@distilled.cloud/proxmox/cluster";
|
|
6217
6249
|
import * as nodes15 from "@distilled.cloud/proxmox/nodes";
|
|
6218
|
-
import * as
|
|
6250
|
+
import * as Effect83 from "effect/Effect";
|
|
6219
6251
|
var guestTypes = ["lxc", "qemu"];
|
|
6220
|
-
var readVm = (props) =>
|
|
6252
|
+
var readVm = (props) => Effect83.gen(function* () {
|
|
6221
6253
|
const credential = yield* leased(props.target, "read");
|
|
6222
|
-
const answer = yield* runPveWith(props.target, credential, false, nodes15.getNodeQemuConfig({ node: props.node, vmid: String(props.vmid) })).pipe(
|
|
6254
|
+
const answer = yield* runPveWith(props.target, credential, false, nodes15.getNodeQemuConfig({ node: props.node, vmid: String(props.vmid) })).pipe(Effect83.map((data) => ({ data, error: undefined })), Effect83.catchTag("QemuConfigNotFound", (error) => Effect83.succeed({ data: undefined, error })));
|
|
6223
6255
|
if (answer.error === undefined) {
|
|
6224
6256
|
const live = answer.data;
|
|
6225
6257
|
if (typeof live.digest !== "string" || live.digest === "") {
|
|
6226
|
-
return yield*
|
|
6258
|
+
return yield* Effect83.fail(new QemuRefusedError(`VM ${String(props.vmid)}: config read did not return a digest-bearing config.`));
|
|
6227
6259
|
}
|
|
6228
6260
|
return live;
|
|
6229
6261
|
}
|
|
6230
|
-
const rows = yield* runPveWith(props.target, credential, false,
|
|
6262
|
+
const rows = yield* runPveWith(props.target, credential, false, cluster11.listClusterResources({ type: "vm" }));
|
|
6231
6263
|
if (!Array.isArray(rows) || rows.some((row) => !Number.isSafeInteger(Number(row?.vmid)) || Number(row?.vmid) <= 0 || typeof row?.node !== "string" || row.node === "" || !guestTypes.includes(row.type))) {
|
|
6232
|
-
return yield*
|
|
6264
|
+
return yield* Effect83.fail(new QemuRefusedError("The cluster guest index did not identify its rows."));
|
|
6233
6265
|
}
|
|
6234
6266
|
const found = rows.find((row) => Number(row.vmid) === props.vmid);
|
|
6235
6267
|
if (found === undefined)
|
|
6236
6268
|
return;
|
|
6237
6269
|
if (found.node === props.node && found.type === "qemu")
|
|
6238
|
-
return yield*
|
|
6239
|
-
return yield*
|
|
6270
|
+
return yield* Effect83.fail(answer.error);
|
|
6271
|
+
return yield* Effect83.fail(new QemuRefusedError(`vmid ${String(props.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a VM on ${props.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
|
|
6240
6272
|
});
|
|
6241
6273
|
|
|
6242
6274
|
// src/proxmox/qemu-task.ts
|
|
6243
6275
|
import * as nodes16 from "@distilled.cloud/proxmox/nodes";
|
|
6244
|
-
import * as
|
|
6245
|
-
var qemuTask = (props, operation, what, polls) =>
|
|
6276
|
+
import * as Effect84 from "effect/Effect";
|
|
6277
|
+
var qemuTask = (props, operation, what, polls) => Effect84.gen(function* () {
|
|
6246
6278
|
const credential = yield* mint(props.target, "provision");
|
|
6247
6279
|
const upid = text(yield* runPveWith(props.target, credential, true, operation));
|
|
6248
6280
|
if (upid === "") {
|
|
6249
|
-
return yield*
|
|
6281
|
+
return yield* Effect84.fail(new QemuRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
6250
6282
|
}
|
|
6251
6283
|
let exit = "still running when this provider stopped waiting";
|
|
6252
6284
|
for (let attempt = 0;attempt < polls; attempt++) {
|
|
6253
|
-
const status = yield* runPveWith(props.target, credential, false, nodes16.getNodeTaskStatus({ node: props.node, upid })).pipe(
|
|
6285
|
+
const status = yield* runPveWith(props.target, credential, false, nodes16.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect84.orElseSucceed(() => {
|
|
6254
6286
|
return;
|
|
6255
6287
|
}));
|
|
6256
6288
|
if (status === undefined || status.status === undefined) {
|
|
@@ -6261,66 +6293,66 @@ var qemuTask = (props, operation, what, polls) => Effect83.gen(function* () {
|
|
|
6261
6293
|
exit = text(status.exitstatus, "stopped with no exitstatus");
|
|
6262
6294
|
break;
|
|
6263
6295
|
}
|
|
6264
|
-
yield*
|
|
6296
|
+
yield* Effect84.sleep("1 second");
|
|
6265
6297
|
}
|
|
6266
6298
|
if (exit !== "OK") {
|
|
6267
|
-
return yield*
|
|
6299
|
+
return yield* Effect84.fail(new QemuRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
|
|
6268
6300
|
}
|
|
6269
6301
|
});
|
|
6270
6302
|
|
|
6271
6303
|
// src/proxmox/qemu-lifecycle.ts
|
|
6272
6304
|
var CREATE_POLLS2 = 180;
|
|
6273
6305
|
var DELETE_POLLS = 60;
|
|
6274
|
-
var
|
|
6306
|
+
var attributesOf10 = (live, props) => ({
|
|
6275
6307
|
config: storedConfig2(live),
|
|
6276
6308
|
node: props.node,
|
|
6277
6309
|
vmid: props.vmid
|
|
6278
6310
|
});
|
|
6279
|
-
var
|
|
6311
|
+
var matches10 = (attributes2, props) => declaredKeys2(props).filter(isManagedKey2).every((key) => attributes2.config[key] === wireValue2(declaredValue2(props, key)));
|
|
6280
6312
|
var spec5 = {
|
|
6281
|
-
attributes:
|
|
6313
|
+
attributes: attributesOf10,
|
|
6282
6314
|
collection: (props) => `nodes/${props.node}/qemu`,
|
|
6283
6315
|
createForm: createForm9,
|
|
6284
6316
|
endpoint: {
|
|
6285
6317
|
create: "pve:POST /nodes/{node}/qemu",
|
|
6286
6318
|
update: "pve:PUT /nodes/{node}/qemu/{vmid}/config"
|
|
6287
6319
|
},
|
|
6288
|
-
matches:
|
|
6320
|
+
matches: matches10,
|
|
6289
6321
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
6290
|
-
updateForm:
|
|
6322
|
+
updateForm: updateForm7
|
|
6291
6323
|
};
|
|
6292
6324
|
var { guardCreate: guardCreate10, guardUpdate: guardUpdate10 } = specGuards(spec5);
|
|
6293
|
-
var readQemu = (props) => readVm(props).pipe(
|
|
6294
|
-
var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(
|
|
6325
|
+
var readQemu = (props) => readVm(props).pipe(Effect85.map((live) => live === undefined ? undefined : attributesOf10(live, props)));
|
|
6326
|
+
var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(Effect85.catchTag("QemuConfigNotFound", () => Effect85.void));
|
|
6295
6327
|
var refuseUnmanaged = (props) => {
|
|
6296
6328
|
const refused2 = formRefusals(props);
|
|
6297
|
-
return refused2.length === 0 ?
|
|
6329
|
+
return refused2.length === 0 ? Effect85.void : Effect85.fail(new QemuRefusedError(refused2.join(`
|
|
6298
6330
|
`)));
|
|
6299
6331
|
};
|
|
6300
|
-
var refuseChange = (change) => change.refuse.length === 0 ?
|
|
6332
|
+
var refuseChange = (change) => change.refuse.length === 0 ? Effect85.void : Effect85.fail(new QemuRefusedError(change.refuse.join(`
|
|
6301
6333
|
`)));
|
|
6302
6334
|
var qemuHandlers = {
|
|
6303
|
-
list: () =>
|
|
6304
|
-
read:
|
|
6335
|
+
list: () => Effect85.succeed([]),
|
|
6336
|
+
read: Effect85.fn(function* ({
|
|
6305
6337
|
fqn,
|
|
6306
6338
|
instanceId,
|
|
6307
6339
|
olds,
|
|
6308
6340
|
output
|
|
6309
6341
|
}) {
|
|
6310
6342
|
const found = yield* readQemu(olds);
|
|
6311
|
-
const settled2 =
|
|
6343
|
+
const settled2 = Effect85.sync(() => found !== undefined && judge2(olds, found.config).drift.length === 0);
|
|
6312
6344
|
return yield* ownedRead({ fqn, instanceId, output }, found, settled2);
|
|
6313
6345
|
}),
|
|
6314
|
-
diff:
|
|
6346
|
+
diff: Effect85.fn(function* ({
|
|
6315
6347
|
news,
|
|
6316
6348
|
olds,
|
|
6317
6349
|
output
|
|
6318
6350
|
}) {
|
|
6319
|
-
if (!
|
|
6351
|
+
if (!isResolved27(news))
|
|
6320
6352
|
return;
|
|
6321
6353
|
const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds.vmid);
|
|
6322
6354
|
if (identity2 !== undefined)
|
|
6323
|
-
return yield*
|
|
6355
|
+
return yield* Effect85.fail(new QemuRefusedError(identity2));
|
|
6324
6356
|
yield* refuseUnmanaged(news);
|
|
6325
6357
|
yield* guardCreate10(news, output === undefined);
|
|
6326
6358
|
yield* guardUpdate10(news);
|
|
@@ -6328,7 +6360,7 @@ var qemuHandlers = {
|
|
|
6328
6360
|
return;
|
|
6329
6361
|
const live = yield* readQemu(news);
|
|
6330
6362
|
if (live === undefined) {
|
|
6331
|
-
yield*
|
|
6363
|
+
yield* Effect85.logWarning(`Proxmox.Vm ${news.node}/${String(news.vmid)}: the cluster lists no VM with this vmid -- ` + "a deploy CREATES it again, with new, empty volumes.");
|
|
6332
6364
|
yield* guardCreate10(news, true);
|
|
6333
6365
|
return { action: "update" };
|
|
6334
6366
|
}
|
|
@@ -6336,7 +6368,7 @@ var qemuHandlers = {
|
|
|
6336
6368
|
yield* refuseChange(change);
|
|
6337
6369
|
return { action: change.drift.length === 0 ? "noop" : "update" };
|
|
6338
6370
|
}),
|
|
6339
|
-
reconcile:
|
|
6371
|
+
reconcile: Effect85.fn(function* ({
|
|
6340
6372
|
fqn,
|
|
6341
6373
|
instanceId,
|
|
6342
6374
|
news,
|
|
@@ -6345,7 +6377,7 @@ var qemuHandlers = {
|
|
|
6345
6377
|
}) {
|
|
6346
6378
|
const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds?.vmid);
|
|
6347
6379
|
if (identity2 !== undefined)
|
|
6348
|
-
return yield*
|
|
6380
|
+
return yield* Effect85.fail(new QemuRefusedError(identity2));
|
|
6349
6381
|
yield* refuseUnmanaged(news);
|
|
6350
6382
|
const live = yield* readQemu(news);
|
|
6351
6383
|
yield* guardCreate10(news, live === undefined);
|
|
@@ -6362,11 +6394,11 @@ var qemuHandlers = {
|
|
|
6362
6394
|
}
|
|
6363
6395
|
const after = yield* readQemu(news);
|
|
6364
6396
|
if (after === undefined) {
|
|
6365
|
-
return yield*
|
|
6397
|
+
return yield* Effect85.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
|
|
6366
6398
|
}
|
|
6367
6399
|
const left = judge2(news, after.config);
|
|
6368
6400
|
if (left.drift.length > 0) {
|
|
6369
|
-
return yield*
|
|
6401
|
+
return yield* Effect85.fail(new QemuRefusedError(`${spec5.path(news)}: after the write, ${left.drift.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value -- declare what it stores."));
|
|
6370
6402
|
}
|
|
6371
6403
|
return after;
|
|
6372
6404
|
}),
|
|
@@ -6375,16 +6407,16 @@ var qemuHandlers = {
|
|
|
6375
6407
|
|
|
6376
6408
|
// src/proxmox/qemu.ts
|
|
6377
6409
|
var ProxmoxVm = Resource28("Proxmox.Vm", { defaultRemovalPolicy: "retain" });
|
|
6378
|
-
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm,
|
|
6410
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect86.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
|
|
6379
6411
|
// src/proxmox/storage-download.ts
|
|
6380
6412
|
import { Resource as Resource29 } from "alchemy";
|
|
6381
6413
|
import * as Provider29 from "alchemy/Provider";
|
|
6382
|
-
import * as
|
|
6414
|
+
import * as Effect89 from "effect/Effect";
|
|
6383
6415
|
|
|
6384
6416
|
// src/proxmox/storage-download-lifecycle.ts
|
|
6385
|
-
import { isResolved as
|
|
6417
|
+
import { isResolved as isResolved28 } from "alchemy/Diff";
|
|
6386
6418
|
import * as nodes19 from "@distilled.cloud/proxmox/nodes";
|
|
6387
|
-
import * as
|
|
6419
|
+
import * as Effect88 from "effect/Effect";
|
|
6388
6420
|
|
|
6389
6421
|
// src/proxmox/storage-download-identity.ts
|
|
6390
6422
|
var PINNED = [
|
|
@@ -6419,16 +6451,16 @@ class StorageDownloadRefusedError extends Error {
|
|
|
6419
6451
|
|
|
6420
6452
|
// src/proxmox/storage-download-task.ts
|
|
6421
6453
|
import * as nodes18 from "@distilled.cloud/proxmox/nodes";
|
|
6422
|
-
import * as
|
|
6423
|
-
var storageDownloadTask = (where, operation, what, polls) =>
|
|
6454
|
+
import * as Effect87 from "effect/Effect";
|
|
6455
|
+
var storageDownloadTask = (where, operation, what, polls) => Effect87.gen(function* () {
|
|
6424
6456
|
const credential = yield* mint(where.target, "provision");
|
|
6425
6457
|
const upid = text(yield* runPveWith(where.target, credential, true, operation));
|
|
6426
6458
|
if (upid === "") {
|
|
6427
|
-
return yield*
|
|
6459
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
6428
6460
|
}
|
|
6429
6461
|
let exit = "still running when this provider stopped waiting";
|
|
6430
6462
|
for (let attempt = 0;attempt < polls; attempt++) {
|
|
6431
|
-
const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(
|
|
6463
|
+
const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect87.orElseSucceed(() => {
|
|
6432
6464
|
return;
|
|
6433
6465
|
}));
|
|
6434
6466
|
if (status === undefined || status.status === undefined) {
|
|
@@ -6439,10 +6471,10 @@ var storageDownloadTask = (where, operation, what, polls) => Effect86.gen(functi
|
|
|
6439
6471
|
exit = text(status.exitstatus, "stopped with no exitstatus");
|
|
6440
6472
|
break;
|
|
6441
6473
|
}
|
|
6442
|
-
yield*
|
|
6474
|
+
yield* Effect87.sleep("1 second");
|
|
6443
6475
|
}
|
|
6444
6476
|
if (exit !== "OK") {
|
|
6445
|
-
return yield*
|
|
6477
|
+
return yield* Effect87.fail(new StorageDownloadRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
|
|
6446
6478
|
}
|
|
6447
6479
|
});
|
|
6448
6480
|
|
|
@@ -6468,14 +6500,14 @@ var createRefusals2 = (props) => {
|
|
|
6468
6500
|
}
|
|
6469
6501
|
return refuse3.concat(formViolations(DOWNLOAD_ENDPOINT, downloadForm(props), true).map((why) => `${props.filename}: ${why}`));
|
|
6470
6502
|
};
|
|
6471
|
-
var readDownload = (props) =>
|
|
6503
|
+
var readDownload = (props) => Effect88.gen(function* () {
|
|
6472
6504
|
const rows = yield* runPve(props.target, "read", false, nodes19.listNodeStorageContent({
|
|
6473
6505
|
content: "import",
|
|
6474
6506
|
node: props.node,
|
|
6475
6507
|
storage: props.storage
|
|
6476
6508
|
}));
|
|
6477
6509
|
if (!Array.isArray(rows)) {
|
|
6478
|
-
return yield*
|
|
6510
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(`${props.storage}: the content list did not come back as a list.`));
|
|
6479
6511
|
}
|
|
6480
6512
|
const found = rows.find((row) => row.volid.endsWith(`/${props.filename}`));
|
|
6481
6513
|
if (found === undefined)
|
|
@@ -6489,7 +6521,7 @@ var readDownload = (props) => Effect87.gen(function* () {
|
|
|
6489
6521
|
volid: text(found.volid, "")
|
|
6490
6522
|
};
|
|
6491
6523
|
});
|
|
6492
|
-
var destroyDownload = (props) =>
|
|
6524
|
+
var destroyDownload = (props) => Effect88.gen(function* () {
|
|
6493
6525
|
const live = yield* readDownload(props);
|
|
6494
6526
|
if (live === undefined)
|
|
6495
6527
|
return;
|
|
@@ -6500,26 +6532,26 @@ var destroyDownload = (props) => Effect87.gen(function* () {
|
|
|
6500
6532
|
}), `delete ${live.volid}`, DELETE_POLLS2);
|
|
6501
6533
|
});
|
|
6502
6534
|
var storageDownloadHandlers = {
|
|
6503
|
-
list: () =>
|
|
6504
|
-
read:
|
|
6535
|
+
list: () => Effect88.succeed([]),
|
|
6536
|
+
read: Effect88.fn(function* ({
|
|
6505
6537
|
fqn,
|
|
6506
6538
|
instanceId,
|
|
6507
6539
|
olds,
|
|
6508
6540
|
output
|
|
6509
6541
|
}) {
|
|
6510
6542
|
const found = yield* readDownload(olds);
|
|
6511
|
-
return yield* ownedRead({ fqn, instanceId, output }, found,
|
|
6543
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, Effect88.succeed(true));
|
|
6512
6544
|
}),
|
|
6513
|
-
diff:
|
|
6545
|
+
diff: Effect88.fn(function* ({
|
|
6514
6546
|
news,
|
|
6515
6547
|
olds,
|
|
6516
6548
|
output
|
|
6517
6549
|
}) {
|
|
6518
|
-
if (!
|
|
6550
|
+
if (!isResolved28(news))
|
|
6519
6551
|
return;
|
|
6520
6552
|
const refused2 = createRefusals2(news);
|
|
6521
6553
|
if (refused2.length > 0) {
|
|
6522
|
-
return yield*
|
|
6554
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(refused2.join(`
|
|
6523
6555
|
`)));
|
|
6524
6556
|
}
|
|
6525
6557
|
if (output === undefined)
|
|
@@ -6529,11 +6561,11 @@ var storageDownloadHandlers = {
|
|
|
6529
6561
|
return { action: "replace" };
|
|
6530
6562
|
const live = yield* readDownload(news);
|
|
6531
6563
|
if (identity2.kind === "pin-changed" && live !== undefined) {
|
|
6532
|
-
return yield*
|
|
6564
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(identity2.refuse));
|
|
6533
6565
|
}
|
|
6534
6566
|
return { action: live === undefined ? "update" : "noop" };
|
|
6535
6567
|
}),
|
|
6536
|
-
reconcile:
|
|
6568
|
+
reconcile: Effect88.fn(function* ({
|
|
6537
6569
|
fqn,
|
|
6538
6570
|
instanceId,
|
|
6539
6571
|
news,
|
|
@@ -6541,7 +6573,7 @@ var storageDownloadHandlers = {
|
|
|
6541
6573
|
}) {
|
|
6542
6574
|
const refused2 = createRefusals2(news);
|
|
6543
6575
|
if (refused2.length > 0) {
|
|
6544
|
-
return yield*
|
|
6576
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(refused2.join(`
|
|
6545
6577
|
`)));
|
|
6546
6578
|
}
|
|
6547
6579
|
const live = yield* readDownload(news);
|
|
@@ -6552,7 +6584,7 @@ var storageDownloadHandlers = {
|
|
|
6552
6584
|
}
|
|
6553
6585
|
const after = yield* readDownload(news);
|
|
6554
6586
|
if (after === undefined) {
|
|
6555
|
-
return yield*
|
|
6587
|
+
return yield* Effect88.fail(new StorageDownloadRefusedError(`${news.filename}: the write returned no error but ${news.storage} still has no ` + "matching content — PVE may have normalised the filename; read it back by hand."));
|
|
6556
6588
|
}
|
|
6557
6589
|
return after;
|
|
6558
6590
|
}),
|
|
@@ -6561,17 +6593,17 @@ var storageDownloadHandlers = {
|
|
|
6561
6593
|
|
|
6562
6594
|
// src/proxmox/storage-download.ts
|
|
6563
6595
|
var ProxmoxStorageDownload = Resource29("Proxmox.StorageDownload");
|
|
6564
|
-
var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload,
|
|
6596
|
+
var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload, Effect89.succeed(ProxmoxStorageDownload.Provider.of(storageDownloadHandlers)));
|
|
6565
6597
|
// src/proxmox/replication-job.ts
|
|
6566
6598
|
import { Resource as Resource30 } from "alchemy";
|
|
6567
6599
|
import * as Provider30 from "alchemy/Provider";
|
|
6568
|
-
import * as
|
|
6600
|
+
import * as Effect91 from "effect/Effect";
|
|
6569
6601
|
|
|
6570
6602
|
// src/proxmox/replication-job-lifecycle.ts
|
|
6571
|
-
import { isResolved as
|
|
6572
|
-
import * as
|
|
6603
|
+
import { isResolved as isResolved29 } from "alchemy/Diff";
|
|
6604
|
+
import * as cluster12 from "@distilled.cloud/proxmox/cluster";
|
|
6573
6605
|
import { ProxmoxParseError as ProxmoxParseError6 } from "@distilled.cloud/proxmox/Errors";
|
|
6574
|
-
import * as
|
|
6606
|
+
import * as Effect90 from "effect/Effect";
|
|
6575
6607
|
import * as Schema6 from "effect/Schema";
|
|
6576
6608
|
|
|
6577
6609
|
// src/proxmox/replication-job-form.ts
|
|
@@ -6632,21 +6664,21 @@ var malformed = () => new ProxmoxParseError6({
|
|
|
6632
6664
|
body: undefined,
|
|
6633
6665
|
cause: "Replication job response does not match the requested vendor identity"
|
|
6634
6666
|
});
|
|
6635
|
-
var readReplicationJob = (props) => runPve(props.target, "read", false,
|
|
6667
|
+
var readReplicationJob = (props) => runPve(props.target, "read", false, cluster12.getClusterReplication({ id: jobId(props) })).pipe(Effect90.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster12.GetClusterReplicationResponse))({
|
|
6636
6668
|
...live,
|
|
6637
6669
|
guest: int(live.guest, Number.NaN),
|
|
6638
6670
|
jobnum: int(live.jobnum, Number.NaN),
|
|
6639
6671
|
rate: undefined
|
|
6640
|
-
}).pipe(
|
|
6641
|
-
var deleteReplicationJob = (props) => runPve(props.target, "provision", true,
|
|
6672
|
+
}).pipe(Effect90.mapError(malformed), Effect90.as(live))), Effect90.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect90.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect90.fail(malformed())), Effect90.catchTag("ReplicationJobNotFound", () => Effect90.succeed(undefined)));
|
|
6673
|
+
var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster12.deleteClusterReplication({ id: jobId(props) })).pipe(Effect90.catchTag("ReplicationJobNotFound", () => Effect90.void));
|
|
6642
6674
|
var replicationJobHandlers = {
|
|
6643
|
-
list: () =>
|
|
6675
|
+
list: () => Effect90.succeed([]),
|
|
6644
6676
|
read: ({ olds }) => readReplicationJob(olds),
|
|
6645
|
-
diff:
|
|
6677
|
+
diff: Effect90.fn(function* ({
|
|
6646
6678
|
news,
|
|
6647
6679
|
output
|
|
6648
6680
|
}) {
|
|
6649
|
-
if (!
|
|
6681
|
+
if (!isResolved29(news))
|
|
6650
6682
|
return;
|
|
6651
6683
|
yield* guardCreate11(news, output === undefined);
|
|
6652
6684
|
yield* guardUpdate11(news);
|
|
@@ -6659,20 +6691,20 @@ var replicationJobHandlers = {
|
|
|
6659
6691
|
}
|
|
6660
6692
|
return { action: replicationJobSpec.matches(live, news) ? "noop" : "update" };
|
|
6661
6693
|
}),
|
|
6662
|
-
reconcile:
|
|
6694
|
+
reconcile: Effect90.fn(function* ({ news }) {
|
|
6663
6695
|
const live = yield* readReplicationJob(news);
|
|
6664
6696
|
yield* guardCreate11(news, live === undefined);
|
|
6665
6697
|
yield* guardUpdate11(news);
|
|
6666
6698
|
if (live === undefined) {
|
|
6667
|
-
yield* runPve(news.target, "provision", true,
|
|
6699
|
+
yield* runPve(news.target, "provision", true, cluster12.createClusterReplication(replicationJobSpec.createForm(news)));
|
|
6668
6700
|
} else {
|
|
6669
6701
|
const form2 = formToSend(replicationJobSpec.matches, live, news, replicationJobSpec.updateForm(news));
|
|
6670
6702
|
if (form2 !== undefined)
|
|
6671
|
-
yield* runPve(news.target, "provision", true,
|
|
6703
|
+
yield* runPve(news.target, "provision", true, cluster12.putClusterReplication({ ...form2, id: jobId(news) }));
|
|
6672
6704
|
}
|
|
6673
6705
|
const after = yield* readReplicationJob(news);
|
|
6674
6706
|
if (after === undefined)
|
|
6675
|
-
return yield*
|
|
6707
|
+
return yield* Effect90.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
|
|
6676
6708
|
return after;
|
|
6677
6709
|
}),
|
|
6678
6710
|
delete: ({ olds }) => deleteReplicationJob(olds)
|
|
@@ -6680,15 +6712,15 @@ var replicationJobHandlers = {
|
|
|
6680
6712
|
|
|
6681
6713
|
// src/proxmox/replication-job.ts
|
|
6682
6714
|
var ProxmoxReplicationJob = Resource30("Proxmox.ReplicationJob");
|
|
6683
|
-
var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob,
|
|
6715
|
+
var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob, Effect91.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
|
|
6684
6716
|
// src/proxmox/sdn-apply.ts
|
|
6685
6717
|
import { Resource as Resource31 } from "alchemy";
|
|
6686
|
-
import { isResolved as
|
|
6718
|
+
import { isResolved as isResolved30 } from "alchemy/Diff";
|
|
6687
6719
|
import * as Provider31 from "alchemy/Provider";
|
|
6688
|
-
import * as
|
|
6720
|
+
import * as Effect93 from "effect/Effect";
|
|
6689
6721
|
|
|
6690
6722
|
// src/proxmox/sdn-apply-read.ts
|
|
6691
|
-
import * as
|
|
6723
|
+
import * as Effect92 from "effect/Effect";
|
|
6692
6724
|
var MARKED = [
|
|
6693
6725
|
"cluster/sdn/zones",
|
|
6694
6726
|
"cluster/sdn/vnets",
|
|
@@ -6697,7 +6729,7 @@ var MARKED = [
|
|
|
6697
6729
|
"cluster/sdn/route-maps"
|
|
6698
6730
|
];
|
|
6699
6731
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
6700
|
-
var markedPending = (target) =>
|
|
6732
|
+
var markedPending = (target) => Effect92.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect92.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect92.catchIf(subsystemAbsent, () => Effect92.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect92.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
6701
6733
|
var fabricStaged = (staged, running) => {
|
|
6702
6734
|
if (staged === undefined && running === undefined)
|
|
6703
6735
|
return 0;
|
|
@@ -6705,9 +6737,9 @@ var fabricStaged = (staged, running) => {
|
|
|
6705
6737
|
return "inconsistent";
|
|
6706
6738
|
return staged === running ? 0 : 1;
|
|
6707
6739
|
};
|
|
6708
|
-
var fabricPending = (target) =>
|
|
6740
|
+
var fabricPending = (target) => Effect92.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect92.map(canonical3), Effect92.catchIf(subsystemAbsent, () => Effect92.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect92.flatMap(([staged, running]) => {
|
|
6709
6741
|
const verdict = fabricStaged(staged, running);
|
|
6710
|
-
return verdict === "inconsistent" ?
|
|
6742
|
+
return verdict === "inconsistent" ? Effect92.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.")) : Effect92.succeed(verdict);
|
|
6711
6743
|
}));
|
|
6712
6744
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
6713
6745
|
var sortDeep = (value) => {
|
|
@@ -6720,23 +6752,23 @@ var sortDeep = (value) => {
|
|
|
6720
6752
|
}
|
|
6721
6753
|
return value;
|
|
6722
6754
|
};
|
|
6723
|
-
var sdnPendingCount = (target) =>
|
|
6755
|
+
var sdnPendingCount = (target) => Effect92.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect92.map(([marked, fabric]) => marked + fabric));
|
|
6724
6756
|
|
|
6725
6757
|
// src/proxmox/sdn-apply.ts
|
|
6726
6758
|
var ProxmoxSdnApply = Resource31("Proxmox.SdnApply");
|
|
6727
|
-
var read5 = (props) => sdnPendingCount(props.target).pipe(
|
|
6728
|
-
var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply,
|
|
6729
|
-
list: () =>
|
|
6730
|
-
read:
|
|
6759
|
+
var read5 = (props) => sdnPendingCount(props.target).pipe(Effect93.map((pending) => ({ pending })));
|
|
6760
|
+
var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect93.succeed(ProxmoxSdnApply.Provider.of({
|
|
6761
|
+
list: () => Effect93.succeed([]),
|
|
6762
|
+
read: Effect93.fn(function* ({ olds }) {
|
|
6731
6763
|
return yield* read5(olds);
|
|
6732
6764
|
}),
|
|
6733
|
-
diff:
|
|
6734
|
-
if (!
|
|
6765
|
+
diff: Effect93.fn(function* ({ news }) {
|
|
6766
|
+
if (!isResolved30(news))
|
|
6735
6767
|
return;
|
|
6736
6768
|
const { pending } = yield* read5(news);
|
|
6737
6769
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
6738
6770
|
}),
|
|
6739
|
-
reconcile:
|
|
6771
|
+
reconcile: Effect93.fn(function* ({ news }) {
|
|
6740
6772
|
const staged = yield* read5(news);
|
|
6741
6773
|
if (staged.pending === 0)
|
|
6742
6774
|
return staged;
|
|
@@ -6744,16 +6776,16 @@ var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect92.
|
|
|
6744
6776
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
6745
6777
|
const after = yield* read5(news);
|
|
6746
6778
|
if (after.pending !== 0) {
|
|
6747
|
-
return yield*
|
|
6779
|
+
return yield* Effect93.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."));
|
|
6748
6780
|
}
|
|
6749
6781
|
return after;
|
|
6750
6782
|
}),
|
|
6751
|
-
delete: () =>
|
|
6783
|
+
delete: () => Effect93.void
|
|
6752
6784
|
})));
|
|
6753
6785
|
// src/proxmox/sdn-subnet.ts
|
|
6754
6786
|
import { Resource as Resource32 } from "alchemy";
|
|
6755
6787
|
import * as Provider32 from "alchemy/Provider";
|
|
6756
|
-
import * as
|
|
6788
|
+
import * as Effect94 from "effect/Effect";
|
|
6757
6789
|
|
|
6758
6790
|
// src/proxmox/sdn-subnet-form.ts
|
|
6759
6791
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -6777,14 +6809,14 @@ var createForm10 = (props) => ({
|
|
|
6777
6809
|
subnet: props.cidr,
|
|
6778
6810
|
type: "subnet"
|
|
6779
6811
|
});
|
|
6780
|
-
var
|
|
6812
|
+
var updateForm8 = (props) => {
|
|
6781
6813
|
const clear = Object.entries(optional3(props)).filter(([, value]) => value === undefined).map(([key]) => key);
|
|
6782
6814
|
return withClears(body5(props), clear);
|
|
6783
6815
|
};
|
|
6784
6816
|
|
|
6785
6817
|
// src/proxmox/sdn-subnet.ts
|
|
6786
6818
|
var ProxmoxSdnSubnet = Resource32("Proxmox.SdnSubnet");
|
|
6787
|
-
var
|
|
6819
|
+
var handlers12 = pveHandlers({
|
|
6788
6820
|
attributes: (live, props) => {
|
|
6789
6821
|
const liveVnet = text(live["vnet"]);
|
|
6790
6822
|
if (liveVnet !== "" && liveVnet !== props.vnet)
|
|
@@ -6811,13 +6843,13 @@ var handlers13 = pveHandlers({
|
|
|
6811
6843
|
},
|
|
6812
6844
|
matches: (attributes2, props) => attributes2.gateway === (props.gateway ?? "") && attributes2.snat === (props.snat === true) && attributes2.dnszoneprefix === (props.dnszoneprefix ?? "") && attributes2.dhcpDnsServer === (props.dhcpDnsServer ?? "") && attributes2.dhcpRange === declaredRanges(props.dhcpRange),
|
|
6813
6845
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
6814
|
-
updateForm:
|
|
6846
|
+
updateForm: updateForm8
|
|
6815
6847
|
});
|
|
6816
|
-
var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet,
|
|
6848
|
+
var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet, Effect94.succeed(ProxmoxSdnSubnet.Provider.of(handlers12)));
|
|
6817
6849
|
// src/proxmox/sdn-vnet.ts
|
|
6818
6850
|
import { Resource as Resource33 } from "alchemy";
|
|
6819
6851
|
import * as Provider33 from "alchemy/Provider";
|
|
6820
|
-
import * as
|
|
6852
|
+
import * as Effect95 from "effect/Effect";
|
|
6821
6853
|
var ProxmoxSdnVnet = Resource33("Proxmox.SdnVnet");
|
|
6822
6854
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
6823
6855
|
var shape10 = (props) => {
|
|
@@ -6830,14 +6862,14 @@ var shape10 = (props) => {
|
|
|
6830
6862
|
...props.tag === undefined ? {} : { tag: String(props.tag) }
|
|
6831
6863
|
};
|
|
6832
6864
|
};
|
|
6833
|
-
var
|
|
6865
|
+
var updateForm9 = (props) => {
|
|
6834
6866
|
const unset2 = [
|
|
6835
6867
|
...(props.alias ?? "") === "" ? ["alias"] : [],
|
|
6836
6868
|
...props.tag === undefined ? ["tag"] : []
|
|
6837
6869
|
];
|
|
6838
6870
|
return withClears(shape10(props), unset2);
|
|
6839
6871
|
};
|
|
6840
|
-
var
|
|
6872
|
+
var handlers13 = pveHandlers({
|
|
6841
6873
|
readRole: "provision",
|
|
6842
6874
|
attributes: (live, props) => ({
|
|
6843
6875
|
alias: typeof live["alias"] === "string" ? live["alias"] : "",
|
|
@@ -6853,13 +6885,13 @@ var handlers14 = pveHandlers({
|
|
|
6853
6885
|
endpoint: { create: "pve:POST /cluster/sdn/vnets", update: "pve:PUT /cluster/sdn/vnets/{vnet}" },
|
|
6854
6886
|
matches: (attributes2, props) => attributes2.zone === props.zone && attributes2.alias === (props.alias ?? "") && attributes2.tag === props.tag && attributes2.vlanaware === (props.vlanaware === true) && attributes2.isolatePorts === (props.isolatePorts === true),
|
|
6855
6887
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
6856
|
-
updateForm:
|
|
6888
|
+
updateForm: updateForm9
|
|
6857
6889
|
});
|
|
6858
|
-
var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet,
|
|
6890
|
+
var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet, Effect95.succeed(ProxmoxSdnVnet.Provider.of(handlers13)));
|
|
6859
6891
|
// src/proxmox/sdn-zone.ts
|
|
6860
6892
|
import { Resource as Resource34 } from "alchemy";
|
|
6861
6893
|
import * as Provider34 from "alchemy/Provider";
|
|
6862
|
-
import * as
|
|
6894
|
+
import * as Effect96 from "effect/Effect";
|
|
6863
6895
|
var ProxmoxSdnZone = Resource34("Proxmox.SdnZone");
|
|
6864
6896
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
6865
6897
|
var body6 = (props) => ({
|
|
@@ -6880,7 +6912,7 @@ var clearable = {
|
|
|
6880
6912
|
vlan: ["dns", "dnszone", "ipam", "mtu", "nodes"],
|
|
6881
6913
|
vxlan: ["dns", "dnszone", "ipam", "mtu", "nodes"]
|
|
6882
6914
|
};
|
|
6883
|
-
var
|
|
6915
|
+
var handlers14 = pveHandlers({
|
|
6884
6916
|
readRole: "provision",
|
|
6885
6917
|
attributes: (live, props) => {
|
|
6886
6918
|
const liveType = text(live["type"]);
|
|
@@ -6912,13 +6944,13 @@ var handlers15 = pveHandlers({
|
|
|
6912
6944
|
return withClears(fields2, clear);
|
|
6913
6945
|
}
|
|
6914
6946
|
});
|
|
6915
|
-
var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone,
|
|
6947
|
+
var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone, Effect96.succeed(ProxmoxSdnZone.Provider.of(handlers14)));
|
|
6916
6948
|
// src/proxmox/storage.ts
|
|
6917
6949
|
import { Resource as Resource35 } from "alchemy";
|
|
6918
|
-
import { isResolved as
|
|
6950
|
+
import { isResolved as isResolved31 } from "alchemy/Diff";
|
|
6919
6951
|
import * as Provider35 from "alchemy/Provider";
|
|
6920
6952
|
import * as storage2 from "@distilled.cloud/proxmox/storage";
|
|
6921
|
-
import * as
|
|
6953
|
+
import * as Effect98 from "effect/Effect";
|
|
6922
6954
|
|
|
6923
6955
|
// src/proxmox/storage-plugin-options.ts
|
|
6924
6956
|
var SHARED_ACCEPTED_TYPES = new Set(["dir", "lvm", "btrfs", "esxi"]);
|
|
@@ -6926,12 +6958,12 @@ var sharedAccepted = (type) => SHARED_ACCEPTED_TYPES.has(type);
|
|
|
6926
6958
|
|
|
6927
6959
|
// src/proxmox/storage-wire.ts
|
|
6928
6960
|
import * as storage from "@distilled.cloud/proxmox/storage";
|
|
6929
|
-
import * as
|
|
6961
|
+
import * as Effect97 from "effect/Effect";
|
|
6930
6962
|
var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
6931
6963
|
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
6932
6964
|
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
6933
6965
|
var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
|
|
6934
|
-
var
|
|
6966
|
+
var attributesOf11 = (live, props) => {
|
|
6935
6967
|
const data = live;
|
|
6936
6968
|
return {
|
|
6937
6969
|
comment: str2(data["comment"]),
|
|
@@ -6945,8 +6977,8 @@ var attributesOf10 = (live, props) => {
|
|
|
6945
6977
|
type: str2(data["type"], props.type)
|
|
6946
6978
|
};
|
|
6947
6979
|
};
|
|
6948
|
-
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(
|
|
6949
|
-
var readStorage = (props) => readStorageOrFail(props).pipe(
|
|
6980
|
+
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect97.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf11(live, props)));
|
|
6981
|
+
var readStorage = (props) => readStorageOrFail(props).pipe(Effect97.catchTag("StorageNotFound", () => Effect97.succeed(undefined)));
|
|
6950
6982
|
var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
|
|
6951
6983
|
var changedProps = (live, props) => ({
|
|
6952
6984
|
...sameList2(props.content, live.content) ? {} : { content: props.content },
|
|
@@ -6957,7 +6989,7 @@ var changedProps = (live, props) => ({
|
|
|
6957
6989
|
...same7(props.preallocation, live.preallocation) ? {} : { preallocation: props.preallocation },
|
|
6958
6990
|
...same7(props.comment, live.comment) ? {} : { comment: props.comment }
|
|
6959
6991
|
});
|
|
6960
|
-
var
|
|
6992
|
+
var matches11 = (attributes2, props) => !sharedAccepted(props.type) && !same7(props.shared, attributes2.shared) ? Effect97.die(new Error(`storage/${props.storage}: declared shared: ${String(props.shared)}, but PVE reports ` + `${String(attributes2.shared)} and '${props.type}' storages never accept a 'shared' ` + "write (storage-plugin-options.ts) -- remove the declared shared or set it to match " + "what PVE already reports; this value can never be applied.")) : Effect97.succeed(Object.keys(changedProps(attributes2, props)).length === 0);
|
|
6961
6993
|
|
|
6962
6994
|
// src/proxmox/storage-form.ts
|
|
6963
6995
|
var STORAGE_CREATE = "pve:POST /storage";
|
|
@@ -6980,7 +7012,7 @@ var createForm11 = (props) => ({
|
|
|
6980
7012
|
storage: props.storage,
|
|
6981
7013
|
type: props.type
|
|
6982
7014
|
});
|
|
6983
|
-
var
|
|
7015
|
+
var updateForm10 = (props, live) => ({
|
|
6984
7016
|
...mutable2(props.type, live === undefined ? props : changedProps(live, props)),
|
|
6985
7017
|
storage: props.storage
|
|
6986
7018
|
});
|
|
@@ -6991,16 +7023,16 @@ var toDistilledUpdate3 = (form2) => underscored(form2);
|
|
|
6991
7023
|
var ProxmoxStorage = Resource35("Proxmox.Storage", {
|
|
6992
7024
|
defaultRemovalPolicy: "retain"
|
|
6993
7025
|
});
|
|
6994
|
-
var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage,
|
|
6995
|
-
list: () =>
|
|
6996
|
-
read:
|
|
7026
|
+
var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect98.succeed(ProxmoxStorage.Provider.of({
|
|
7027
|
+
list: () => Effect98.succeed([]),
|
|
7028
|
+
read: Effect98.fn(function* ({ olds, output }) {
|
|
6997
7029
|
return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
|
|
6998
7030
|
}),
|
|
6999
|
-
diff:
|
|
7000
|
-
if (!
|
|
7031
|
+
diff: Effect98.fn(function* ({ news, output }) {
|
|
7032
|
+
if (!isResolved31(news))
|
|
7001
7033
|
return;
|
|
7002
7034
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
|
|
7003
|
-
yield* guardWrite2(STORAGE_UPDATE,
|
|
7035
|
+
yield* guardWrite2(STORAGE_UPDATE, updateForm10(news, undefined), false);
|
|
7004
7036
|
if (output === undefined)
|
|
7005
7037
|
return;
|
|
7006
7038
|
const live = yield* readStorageOrFail(news);
|
|
@@ -7012,61 +7044,61 @@ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect97.su
|
|
|
7012
7044
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), true);
|
|
7013
7045
|
return { action: "update" };
|
|
7014
7046
|
}
|
|
7015
|
-
return (yield*
|
|
7047
|
+
return (yield* matches11(live, news)) ? { action: "noop" } : { action: "update" };
|
|
7016
7048
|
}),
|
|
7017
|
-
reconcile:
|
|
7049
|
+
reconcile: Effect98.fn(function* ({ news }) {
|
|
7018
7050
|
const before = dropUnreadable7(yield* readStorage(news));
|
|
7019
7051
|
yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
|
|
7020
|
-
const update2 =
|
|
7052
|
+
const update2 = updateForm10(news, before);
|
|
7021
7053
|
yield* guardWrite2(STORAGE_UPDATE, update2, false);
|
|
7022
7054
|
if (before === undefined) {
|
|
7023
7055
|
yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate4(news)));
|
|
7024
|
-
} else if (!(yield*
|
|
7056
|
+
} else if (!(yield* matches11(before, news))) {
|
|
7025
7057
|
yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate3(update2)));
|
|
7026
7058
|
}
|
|
7027
7059
|
const after = dropUnreadable7(yield* readStorage(news));
|
|
7028
7060
|
if (after === undefined) {
|
|
7029
|
-
return yield*
|
|
7061
|
+
return yield* Effect98.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."));
|
|
7030
7062
|
}
|
|
7031
7063
|
return after;
|
|
7032
7064
|
}),
|
|
7033
|
-
delete:
|
|
7065
|
+
delete: Effect98.fn(function* ({ olds }) {
|
|
7034
7066
|
yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
|
|
7035
7067
|
})
|
|
7036
7068
|
})));
|
|
7037
7069
|
// src/proxmox/zfs-pool.ts
|
|
7038
7070
|
import { Resource as Resource36 } from "alchemy";
|
|
7039
|
-
import { isResolved as
|
|
7071
|
+
import { isResolved as isResolved32 } from "alchemy/Diff";
|
|
7040
7072
|
import * as Provider36 from "alchemy/Provider";
|
|
7041
|
-
import * as
|
|
7073
|
+
import * as Effect101 from "effect/Effect";
|
|
7042
7074
|
|
|
7043
7075
|
// src/proxmox/zfs-pool-wire.ts
|
|
7044
7076
|
import * as nodes20 from "@distilled.cloud/proxmox/nodes";
|
|
7045
|
-
import * as
|
|
7077
|
+
import * as Effect99 from "effect/Effect";
|
|
7046
7078
|
var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
|
|
7047
7079
|
const vdev = entry;
|
|
7048
7080
|
const nested = leafDevices(vdev.children);
|
|
7049
7081
|
return nested.length > 0 ? nested : [text(vdev.name)].filter((name) => name !== "");
|
|
7050
7082
|
}) : [];
|
|
7051
|
-
var
|
|
7083
|
+
var attributesOf12 = (live, props) => ({
|
|
7052
7084
|
devices: leafDevices(live.children).join(","),
|
|
7053
7085
|
errors: text(live.errors, "unknown"),
|
|
7054
7086
|
name: props.name,
|
|
7055
7087
|
node: props.node,
|
|
7056
7088
|
state: text(live.state, "unknown")
|
|
7057
7089
|
});
|
|
7058
|
-
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(
|
|
7090
|
+
var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect99.map((live) => {
|
|
7059
7091
|
if (live === UNREADABLE)
|
|
7060
7092
|
return UNREADABLE;
|
|
7061
|
-
return text(live.name) === "" ? undefined :
|
|
7093
|
+
return text(live.name) === "" ? undefined : attributesOf12(live, props);
|
|
7062
7094
|
}));
|
|
7063
|
-
var readPool2 = (props) => readPoolOrFail(props).pipe(
|
|
7095
|
+
var readPool2 = (props) => readPoolOrFail(props).pipe(Effect99.orElseSucceed(() => {
|
|
7064
7096
|
return;
|
|
7065
7097
|
}));
|
|
7066
7098
|
var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
|
|
7067
7099
|
|
|
7068
7100
|
// src/proxmox/zfs-pool-form.ts
|
|
7069
|
-
import * as
|
|
7101
|
+
import * as Effect100 from "effect/Effect";
|
|
7070
7102
|
import * as nodes21 from "@distilled.cloud/proxmox/nodes";
|
|
7071
7103
|
var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
|
|
7072
7104
|
var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
|
|
@@ -7087,25 +7119,25 @@ var toDistilledCreate5 = (props) => {
|
|
|
7087
7119
|
};
|
|
7088
7120
|
};
|
|
7089
7121
|
var SETTLE_ATTEMPTS = 30;
|
|
7090
|
-
var createPool2 = (props, read6) =>
|
|
7122
|
+
var createPool2 = (props, read6) => Effect100.gen(function* () {
|
|
7091
7123
|
const existing = yield* read6(props);
|
|
7092
7124
|
if (existing !== undefined)
|
|
7093
7125
|
return existing;
|
|
7094
7126
|
if (props.devices === undefined || props.raidlevel === undefined) {
|
|
7095
|
-
return yield*
|
|
7127
|
+
return yield* Effect100.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."));
|
|
7096
7128
|
}
|
|
7097
7129
|
yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
|
|
7098
7130
|
const upid = yield* runPve(props.target, "provision", true, nodes21.createNodeDiskZfs(toDistilledCreate5(props)));
|
|
7099
|
-
const settle3 = (attempts) =>
|
|
7131
|
+
const settle3 = (attempts) => Effect100.gen(function* () {
|
|
7100
7132
|
const live = yield* read6(props);
|
|
7101
7133
|
if (live !== undefined || attempts <= 0)
|
|
7102
7134
|
return live;
|
|
7103
|
-
yield*
|
|
7135
|
+
yield* Effect100.sleep("2 seconds");
|
|
7104
7136
|
return yield* settle3(attempts - 1);
|
|
7105
7137
|
});
|
|
7106
7138
|
const after = yield* settle3(SETTLE_ATTEMPTS);
|
|
7107
7139
|
if (after === undefined) {
|
|
7108
|
-
return yield*
|
|
7140
|
+
return yield* Effect100.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."));
|
|
7109
7141
|
}
|
|
7110
7142
|
return after;
|
|
7111
7143
|
});
|
|
@@ -7115,13 +7147,13 @@ var destroyPool = (props) => runPve(props.target, "provision", true, nodes21.del
|
|
|
7115
7147
|
var ProxmoxZfsPool = Resource36("Proxmox.ZfsPool", {
|
|
7116
7148
|
defaultRemovalPolicy: "retain"
|
|
7117
7149
|
});
|
|
7118
|
-
var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool,
|
|
7119
|
-
list: () =>
|
|
7120
|
-
read:
|
|
7150
|
+
var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect101.succeed(ProxmoxZfsPool.Provider.of({
|
|
7151
|
+
list: () => Effect101.succeed([]),
|
|
7152
|
+
read: Effect101.fn(function* ({ olds, output }) {
|
|
7121
7153
|
return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
|
|
7122
7154
|
}),
|
|
7123
|
-
diff:
|
|
7124
|
-
if (!
|
|
7155
|
+
diff: Effect101.fn(function* ({ news, output }) {
|
|
7156
|
+
if (!isResolved32(news))
|
|
7125
7157
|
return;
|
|
7126
7158
|
yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
|
|
7127
7159
|
if (output === undefined)
|
|
@@ -7137,10 +7169,10 @@ var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect100.s
|
|
|
7137
7169
|
}
|
|
7138
7170
|
return { action: "noop" };
|
|
7139
7171
|
}),
|
|
7140
|
-
reconcile:
|
|
7141
|
-
return yield* createPool2(news, (props) => readPool2(props).pipe(
|
|
7172
|
+
reconcile: Effect101.fn(function* ({ news }) {
|
|
7173
|
+
return yield* createPool2(news, (props) => readPool2(props).pipe(Effect101.map(dropUnreadable8)));
|
|
7142
7174
|
}),
|
|
7143
|
-
delete:
|
|
7175
|
+
delete: Effect101.fn(function* ({ olds }) {
|
|
7144
7176
|
yield* destroyPool(olds);
|
|
7145
7177
|
})
|
|
7146
7178
|
})));
|
|
@@ -7223,5 +7255,5 @@ export {
|
|
|
7223
7255
|
violations
|
|
7224
7256
|
};
|
|
7225
7257
|
|
|
7226
|
-
//# debugId=
|
|
7258
|
+
//# debugId=267899A4B122300564756E2164756E21
|
|
7227
7259
|
//# sourceMappingURL=index.js.map
|