@homeflare/alchemy 0.31.1 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -7
- package/dist/grafana/index.d.ts +6 -5
- package/dist/grafana/index.d.ts.map +1 -1
- package/dist/linux/container-form.d.ts +129 -0
- package/dist/linux/container-form.d.ts.map +1 -0
- package/dist/linux/container-generator.d.ts +74 -0
- package/dist/linux/container-generator.d.ts.map +1 -0
- package/dist/linux/container-handlers.d.ts +15 -0
- package/dist/linux/container-handlers.d.ts.map +1 -0
- package/dist/linux/container-lifecycle.d.ts +37 -0
- package/dist/linux/container-lifecycle.d.ts.map +1 -0
- package/dist/linux/container-preflight.d.ts +34 -0
- package/dist/linux/container-preflight.d.ts.map +1 -0
- package/dist/linux/container-secrets.d.ts +37 -0
- package/dist/linux/container-secrets.d.ts.map +1 -0
- package/dist/linux/container-settle.d.ts +34 -0
- package/dist/linux/container-settle.d.ts.map +1 -0
- package/dist/linux/container.d.ts +30 -0
- package/dist/linux/container.d.ts.map +1 -0
- package/dist/linux/fake-quadlet.d.ts +25 -0
- package/dist/linux/fake-quadlet.d.ts.map +1 -0
- package/dist/linux/index.d.ts +6 -3
- package/dist/linux/index.d.ts.map +1 -1
- package/dist/linux/index.js +641 -268
- package/dist/linux/index.js.map +15 -7
- package/dist/linux/providers.d.ts +1 -1
- package/dist/linux/providers.d.ts.map +1 -1
- package/dist/linux/systemctl.d.ts +7 -1
- package/dist/linux/systemctl.d.ts.map +1 -1
- package/dist/opnsense/alias-form.d.ts +29 -0
- package/dist/opnsense/alias-form.d.ts.map +1 -0
- package/dist/opnsense/alias.d.ts +81 -0
- package/dist/opnsense/alias.d.ts.map +1 -0
- package/dist/opnsense/category-form.d.ts +10 -0
- package/dist/opnsense/category-form.d.ts.map +1 -0
- package/dist/opnsense/category.d.ts +58 -0
- package/dist/opnsense/category.d.ts.map +1 -0
- package/dist/opnsense/credentials.d.ts +36 -0
- package/dist/opnsense/credentials.d.ts.map +1 -0
- package/dist/opnsense/fake-opnsense.d.ts +51 -0
- package/dist/opnsense/fake-opnsense.d.ts.map +1 -0
- package/dist/opnsense/group-form.d.ts +11 -0
- package/dist/opnsense/group-form.d.ts.map +1 -0
- package/dist/opnsense/group.d.ts +62 -0
- package/dist/opnsense/group.d.ts.map +1 -0
- package/dist/opnsense/index.d.ts +16 -0
- package/dist/opnsense/index.d.ts.map +1 -0
- package/dist/opnsense/index.js +211 -0
- package/dist/opnsense/index.js.map +20 -0
- package/dist/opnsense/policy.d.ts +20 -0
- package/dist/opnsense/policy.d.ts.map +1 -0
- package/dist/opnsense/providers.d.ts +13 -0
- package/dist/opnsense/providers.d.ts.map +1 -0
- package/dist/opnsense/resource.d.ts +74 -0
- package/dist/opnsense/resource.d.ts.map +1 -0
- package/dist/opnsense/wire.d.ts +39 -0
- package/dist/opnsense/wire.d.ts.map +1 -0
- package/dist/proxmox/acl.d.ts.map +1 -1
- package/dist/proxmox/api-token.d.ts.map +1 -1
- package/dist/proxmox/group-wire.d.ts +44 -5
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/group.d.ts.map +1 -1
- package/dist/proxmox/index.js +326 -264
- package/dist/proxmox/index.js.map +13 -11
- package/dist/proxmox/role.d.ts.map +1 -1
- package/dist/proxmox/storage-form.d.ts +54 -0
- package/dist/proxmox/storage-form.d.ts.map +1 -0
- package/dist/proxmox/storage-wire.d.ts +56 -0
- package/dist/proxmox/storage-wire.d.ts.map +1 -0
- package/dist/proxmox/storage.d.ts +55 -60
- package/dist/proxmox/storage.d.ts.map +1 -1
- package/dist/proxmox/user-wire.d.ts +34 -5
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- package/dist/proxmox/user.d.ts +6 -6
- package/dist/proxmox/user.d.ts.map +1 -1
- package/dist/unifi/fake-unifi.d.ts +48 -0
- package/dist/unifi/fake-unifi.d.ts.map +1 -0
- package/dist/unifi/firewall-zone-form.d.ts +40 -0
- package/dist/unifi/firewall-zone-form.d.ts.map +1 -0
- package/dist/unifi/firewall-zone.d.ts +50 -0
- package/dist/unifi/firewall-zone.d.ts.map +1 -0
- package/dist/unifi/index.d.ts +13 -0
- package/dist/unifi/index.d.ts.map +1 -0
- package/dist/unifi/index.js +190 -0
- package/dist/unifi/index.js.map +16 -0
- package/dist/unifi/network-form.d.ts +67 -0
- package/dist/unifi/network-form.d.ts.map +1 -0
- package/dist/unifi/network.d.ts +67 -0
- package/dist/unifi/network.d.ts.map +1 -0
- package/dist/unifi/policy.d.ts +20 -0
- package/dist/unifi/policy.d.ts.map +1 -0
- package/dist/unifi/providers.d.ts +13 -0
- package/dist/unifi/providers.d.ts.map +1 -0
- package/dist/unifi/resource.d.ts +64 -0
- package/dist/unifi/resource.d.ts.map +1 -0
- package/dist/verify/fake-engine.d.ts +14 -0
- package/dist/verify/fake-engine.d.ts.map +1 -1
- package/docs/grafana.md +47 -17
- package/docs/opnsense.md +146 -0
- package/docs/provider-standard.md +1 -1
- package/docs/quadlet-container.md +132 -0
- package/docs/unifi.md +93 -0
- package/docs/upstream-conformance.md +14 -4
- package/package.json +13 -3
- package/src/grafana/index.ts +6 -5
- package/src/linux/container-fixture.test.ts +92 -0
- package/src/linux/container-form.ts +243 -0
- package/src/linux/container-generator.test.ts +195 -0
- package/src/linux/container-generator.ts +113 -0
- package/src/linux/container-handlers.ts +73 -0
- package/src/linux/container-lifecycle.test.ts +209 -0
- package/src/linux/container-lifecycle.ts +217 -0
- package/src/linux/container-preflight.ts +97 -0
- package/src/linux/container-secrets.test.ts +171 -0
- package/src/linux/container-secrets.ts +112 -0
- package/src/linux/container-settle.ts +97 -0
- package/src/linux/container.ts +60 -0
- package/src/linux/fake-quadlet.ts +127 -0
- package/src/linux/index.ts +11 -3
- package/src/linux/providers.ts +2 -0
- package/src/linux/systemctl.ts +9 -0
- package/src/opnsense/alias-form.test.ts +89 -0
- package/src/opnsense/alias-form.ts +53 -0
- package/src/opnsense/alias.test.ts +203 -0
- package/src/opnsense/alias.ts +117 -0
- package/src/opnsense/category-form.test.ts +54 -0
- package/src/opnsense/category-form.ts +20 -0
- package/src/opnsense/category.test.ts +138 -0
- package/src/opnsense/category.ts +82 -0
- package/src/opnsense/credentials.ts +41 -0
- package/src/opnsense/fake-opnsense.ts +79 -0
- package/src/opnsense/group-form.test.ts +75 -0
- package/src/opnsense/group-form.ts +25 -0
- package/src/opnsense/group.test.ts +141 -0
- package/src/opnsense/group.ts +78 -0
- package/src/opnsense/index.ts +45 -0
- package/src/opnsense/policy.ts +49 -0
- package/src/opnsense/providers.ts +21 -0
- package/src/opnsense/resource.ts +146 -0
- package/src/opnsense/wire.ts +56 -0
- package/src/opnsense/write-refusal.test.ts +148 -0
- package/src/proxmox/acl.ts +10 -4
- package/src/proxmox/api-token.ts +20 -12
- package/src/proxmox/group-wire.ts +62 -8
- package/src/proxmox/group.ts +23 -35
- package/src/proxmox/read-failure-propagation.test.ts +183 -0
- package/src/proxmox/role.ts +9 -2
- package/src/proxmox/storage-form.ts +144 -0
- package/src/proxmox/storage-read-failure.test.ts +214 -0
- package/src/proxmox/storage-wire.ts +124 -0
- package/src/proxmox/storage.ts +165 -175
- package/src/proxmox/user-wire.ts +44 -8
- package/src/proxmox/user.ts +29 -27
- package/src/unifi/fake-unifi.ts +60 -0
- package/src/unifi/firewall-zone-form.ts +65 -0
- package/src/unifi/firewall-zone.test.ts +88 -0
- package/src/unifi/firewall-zone.ts +66 -0
- package/src/unifi/index.ts +26 -0
- package/src/unifi/network-form.ts +207 -0
- package/src/unifi/network.test.ts +209 -0
- package/src/unifi/network.ts +83 -0
- package/src/unifi/policy.ts +37 -0
- package/src/unifi/providers.ts +15 -0
- package/src/unifi/resource.test.ts +133 -0
- package/src/unifi/resource.ts +131 -0
- package/src/verify/fake-engine.ts +23 -0
package/dist/proxmox/index.js
CHANGED
|
@@ -1226,9 +1226,7 @@ var unreadableWarning = (type, identity2) => Effect6.logWarning(`${type} ${ident
|
|
|
1226
1226
|
|
|
1227
1227
|
// src/proxmox/acl.ts
|
|
1228
1228
|
var ProxmoxAcl = Resource("Proxmox.Acl");
|
|
1229
|
-
var readAttributes = (props) => readOrUnreadable(runPve(props.target, "provision", false, access.listAccessAcl({}))).pipe(Effect7.map((rows) => rows === UNREADABLE ? UNREADABLE : attributesOf(rows, props))
|
|
1230
|
-
return;
|
|
1231
|
-
}));
|
|
1229
|
+
var readAttributes = (props) => readOrUnreadable(runPve(props.target, "provision", false, access.listAccessAcl({}))).pipe(Effect7.map((rows) => rows === UNREADABLE ? UNREADABLE : attributesOf(rows, props)));
|
|
1232
1230
|
var dropUnreadable = (live) => live === UNREADABLE ? undefined : live;
|
|
1233
1231
|
var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl, Effect7.succeed(ProxmoxAcl.Provider.of({
|
|
1234
1232
|
list: () => Effect7.succeed([]),
|
|
@@ -1398,9 +1396,10 @@ var guardWrite2 = (endpoint, body, presence) => guardForm(endpoint, asForm2(body
|
|
|
1398
1396
|
var ProxmoxApiToken = Resource2("Proxmox.ApiToken", {
|
|
1399
1397
|
defaultRemovalPolicy: "retain"
|
|
1400
1398
|
});
|
|
1401
|
-
var readToken = (props) =>
|
|
1402
|
-
|
|
1403
|
-
|
|
1399
|
+
var readToken = (props) => {
|
|
1400
|
+
const label = { tokenid: props.tokenid, userid: props.userid };
|
|
1401
|
+
return readOrUnreadable(runPve(props.target, "provision", false, access2.getAccessUserToken(label))).pipe(Effect8.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf2(live, props)));
|
|
1402
|
+
};
|
|
1404
1403
|
var dropUnreadable2 = (live) => live === UNREADABLE ? undefined : live;
|
|
1405
1404
|
var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken, Effect8.succeed(ProxmoxApiToken.Provider.of({
|
|
1406
1405
|
list: () => Effect8.succeed([]),
|
|
@@ -2094,10 +2093,12 @@ var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
|
|
|
2094
2093
|
import { Resource as Resource10 } from "alchemy";
|
|
2095
2094
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2096
2095
|
import * as Provider10 from "alchemy/Provider";
|
|
2097
|
-
import * as
|
|
2098
|
-
import * as
|
|
2096
|
+
import * as access4 from "@distilled.cloud/proxmox/access";
|
|
2097
|
+
import * as Effect24 from "effect/Effect";
|
|
2099
2098
|
|
|
2100
2099
|
// src/proxmox/group-wire.ts
|
|
2100
|
+
import * as access3 from "@distilled.cloud/proxmox/access";
|
|
2101
|
+
import * as Effect23 from "effect/Effect";
|
|
2101
2102
|
var GROUP_CREATE = "pve:POST /access/groups";
|
|
2102
2103
|
var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
|
|
2103
2104
|
var storedComment = (comment2) => {
|
|
@@ -2122,28 +2123,29 @@ var attributesOf3 = (live, props) => ({
|
|
|
2122
2123
|
members: memberList(live.members)
|
|
2123
2124
|
});
|
|
2124
2125
|
var matches3 = (attributes, props) => attributes.comment === storedComment(props.comment);
|
|
2126
|
+
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect23.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf3(live, props)));
|
|
2127
|
+
var readGroup = (props) => readGroupOrFail(props).pipe(Effect23.orElseSucceed(() => {
|
|
2128
|
+
return;
|
|
2129
|
+
}));
|
|
2130
|
+
var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
|
|
2125
2131
|
|
|
2126
2132
|
// src/proxmox/group.ts
|
|
2127
2133
|
var ProxmoxGroup = Resource10("Proxmox.Group", {
|
|
2128
2134
|
defaultRemovalPolicy: "retain"
|
|
2129
2135
|
});
|
|
2130
|
-
var
|
|
2131
|
-
|
|
2132
|
-
})
|
|
2133
|
-
|
|
2134
|
-
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect23.succeed(ProxmoxGroup.Provider.of({
|
|
2135
|
-
list: () => Effect23.succeed([]),
|
|
2136
|
-
read: Effect23.fn(function* ({ olds }) {
|
|
2137
|
-
return dropUnreadable3(yield* readGroup(olds));
|
|
2136
|
+
var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect24.succeed(ProxmoxGroup.Provider.of({
|
|
2137
|
+
list: () => Effect24.succeed([]),
|
|
2138
|
+
read: Effect24.fn(function* ({ olds, output }) {
|
|
2139
|
+
return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
|
|
2138
2140
|
}),
|
|
2139
|
-
diff:
|
|
2141
|
+
diff: Effect24.fn(function* ({ news, output }) {
|
|
2140
2142
|
if (!isResolved7(news))
|
|
2141
2143
|
return;
|
|
2142
2144
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
|
|
2143
2145
|
yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
|
|
2144
2146
|
if (output === undefined)
|
|
2145
2147
|
return;
|
|
2146
|
-
const live = yield*
|
|
2148
|
+
const live = yield* readGroupOrFail(news);
|
|
2147
2149
|
if (live === UNREADABLE) {
|
|
2148
2150
|
yield* unreadableWarning("Proxmox.Group", news.groupid);
|
|
2149
2151
|
return { action: "noop" };
|
|
@@ -2154,29 +2156,29 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect23.succee
|
|
|
2154
2156
|
}
|
|
2155
2157
|
return matches3(live, news) ? { action: "noop" } : { action: "update" };
|
|
2156
2158
|
}),
|
|
2157
|
-
reconcile:
|
|
2159
|
+
reconcile: Effect24.fn(function* ({ news }) {
|
|
2158
2160
|
const before = dropUnreadable3(yield* readGroup(news));
|
|
2159
2161
|
yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
|
|
2160
2162
|
yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
|
|
2161
2163
|
if (before === undefined) {
|
|
2162
|
-
yield* runPve(news.target, "provision", true,
|
|
2164
|
+
yield* runPve(news.target, "provision", true, access4.createAccessGroup(createForm3(news)));
|
|
2163
2165
|
} else if (!matches3(before, news)) {
|
|
2164
|
-
yield* runPve(news.target, "provision", true,
|
|
2166
|
+
yield* runPve(news.target, "provision", true, access4.putAccessGroup(updateForm(news)));
|
|
2165
2167
|
}
|
|
2166
2168
|
const after = dropUnreadable3(yield* readGroup(news));
|
|
2167
2169
|
if (after === undefined) {
|
|
2168
|
-
return yield*
|
|
2170
|
+
return yield* Effect24.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."));
|
|
2169
2171
|
}
|
|
2170
2172
|
return after;
|
|
2171
2173
|
}),
|
|
2172
|
-
delete:
|
|
2173
|
-
yield* runPve(olds.target, "provision", true,
|
|
2174
|
+
delete: Effect24.fn(function* ({ olds }) {
|
|
2175
|
+
yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
|
|
2174
2176
|
})
|
|
2175
2177
|
})));
|
|
2176
2178
|
// src/proxmox/ha-resource.ts
|
|
2177
2179
|
import { Resource as Resource11 } from "alchemy";
|
|
2178
2180
|
import * as Provider11 from "alchemy/Provider";
|
|
2179
|
-
import * as
|
|
2181
|
+
import * as Effect25 from "effect/Effect";
|
|
2180
2182
|
var ProxmoxHaResource = Resource11("Proxmox.HaResource");
|
|
2181
2183
|
var kind = (sid) => sid.split(":")[0] ?? "";
|
|
2182
2184
|
var shape3 = (props) => ({
|
|
@@ -2204,11 +2206,11 @@ var handlers6 = pveHandlers({
|
|
|
2204
2206
|
path: (props) => `cluster/ha/resources/${props.sid}`,
|
|
2205
2207
|
updateForm: shape3
|
|
2206
2208
|
});
|
|
2207
|
-
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource,
|
|
2209
|
+
var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect25.succeed(ProxmoxHaResource.Provider.of(handlers6)));
|
|
2208
2210
|
// src/proxmox/ha-rule.ts
|
|
2209
2211
|
import { Resource as Resource12 } from "alchemy";
|
|
2210
2212
|
import * as Provider12 from "alchemy/Provider";
|
|
2211
|
-
import * as
|
|
2213
|
+
import * as Effect26 from "effect/Effect";
|
|
2212
2214
|
|
|
2213
2215
|
// src/proxmox/ha-rule-form.ts
|
|
2214
2216
|
var nodeList = (value) => {
|
|
@@ -2285,43 +2287,43 @@ var handlers7 = pveHandlers({
|
|
|
2285
2287
|
return withClears(fields, clear);
|
|
2286
2288
|
}
|
|
2287
2289
|
});
|
|
2288
|
-
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule,
|
|
2290
|
+
var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect26.succeed(ProxmoxHaRule.Provider.of(handlers7)));
|
|
2289
2291
|
// src/proxmox/lxc.ts
|
|
2290
2292
|
import { Resource as Resource13 } from "alchemy";
|
|
2291
2293
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2292
2294
|
import * as Provider13 from "alchemy/Provider";
|
|
2293
|
-
import * as
|
|
2295
|
+
import * as Effect36 from "effect/Effect";
|
|
2294
2296
|
|
|
2295
2297
|
// src/ownership/adopt.ts
|
|
2296
2298
|
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
2297
2299
|
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
2298
2300
|
import { Stack as Stack3 } from "alchemy/Stack";
|
|
2299
|
-
import * as
|
|
2301
|
+
import * as Effect30 from "effect/Effect";
|
|
2300
2302
|
import * as Option5 from "effect/Option";
|
|
2301
2303
|
|
|
2302
2304
|
// src/ownership/resume.ts
|
|
2303
2305
|
import { Unowned } from "alchemy/AdoptPolicy";
|
|
2304
2306
|
import { Artifacts } from "alchemy/Artifacts";
|
|
2305
|
-
import * as
|
|
2307
|
+
import * as Effect27 from "effect/Effect";
|
|
2306
2308
|
import * as Option2 from "effect/Option";
|
|
2307
2309
|
var PROVEN = "homeflare/ownership/resumes";
|
|
2308
2310
|
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
2309
|
-
var note = (key, instanceId) =>
|
|
2310
|
-
const bag = yield*
|
|
2311
|
+
var note = (key, instanceId) => Effect27.gen(function* () {
|
|
2312
|
+
const bag = yield* Effect27.serviceOption(Artifacts);
|
|
2311
2313
|
if (Option2.isSome(bag))
|
|
2312
2314
|
yield* bag.value.set(key, instanceId);
|
|
2313
2315
|
});
|
|
2314
|
-
var noted = (key, instanceId) =>
|
|
2315
|
-
const bag = yield*
|
|
2316
|
+
var noted = (key, instanceId) => Effect27.gen(function* () {
|
|
2317
|
+
const bag = yield* Effect27.serviceOption(Artifacts);
|
|
2316
2318
|
if (Option2.isNone(bag))
|
|
2317
2319
|
return false;
|
|
2318
2320
|
return (yield* bag.value.get(key)) === instanceId;
|
|
2319
2321
|
});
|
|
2320
|
-
var noteUnfinished = (instanceId) =>
|
|
2321
|
-
var noteResume = (instanceId, recovered) =>
|
|
2322
|
+
var noteUnfinished = (instanceId) => Effect27.as(note(UNFINISHED, instanceId), undefined);
|
|
2323
|
+
var noteResume = (instanceId, recovered) => Effect27.gen(function* () {
|
|
2322
2324
|
yield* noteUnfinished(instanceId);
|
|
2323
|
-
const unproven = () =>
|
|
2324
|
-
const found = yield* recovered.pipe(
|
|
2325
|
+
const unproven = () => Effect27.succeed(undefined);
|
|
2326
|
+
const found = yield* recovered.pipe(Effect27.catch(unproven), Effect27.catchDefect(unproven));
|
|
2325
2327
|
if (found === undefined || found === null || Unowned.is(found))
|
|
2326
2328
|
return;
|
|
2327
2329
|
yield* note(PROVEN, instanceId);
|
|
@@ -2332,7 +2334,7 @@ var provingResumes = (service) => {
|
|
|
2332
2334
|
const { diff, read } = service;
|
|
2333
2335
|
if (diff === undefined || read === undefined)
|
|
2334
2336
|
return service;
|
|
2335
|
-
const proving = (input) =>
|
|
2337
|
+
const proving = (input) => Effect27.gen(function* () {
|
|
2336
2338
|
if (input.output === undefined) {
|
|
2337
2339
|
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
2338
2340
|
}
|
|
@@ -2344,12 +2346,12 @@ var provingResumes = (service) => {
|
|
|
2344
2346
|
// src/ownership/rows.ts
|
|
2345
2347
|
import { Stack as Stack2 } from "alchemy/Stack";
|
|
2346
2348
|
import { State, isActionState } from "alchemy/State/State";
|
|
2347
|
-
import * as
|
|
2349
|
+
import * as Effect29 from "effect/Effect";
|
|
2348
2350
|
import * as Option4 from "effect/Option";
|
|
2349
2351
|
|
|
2350
2352
|
// src/ownership/whole.ts
|
|
2351
2353
|
import { Stack } from "alchemy/Stack";
|
|
2352
|
-
import * as
|
|
2354
|
+
import * as Effect28 from "effect/Effect";
|
|
2353
2355
|
import * as Option3 from "effect/Option";
|
|
2354
2356
|
var absent = (value) => value === undefined || value === null;
|
|
2355
2357
|
var isPlainObject = (value) => {
|
|
@@ -2375,22 +2377,22 @@ var carries = (declared, recorded) => {
|
|
|
2375
2377
|
}
|
|
2376
2378
|
return true;
|
|
2377
2379
|
};
|
|
2378
|
-
var wholeDeclaration = (fqn, props) =>
|
|
2380
|
+
var wholeDeclaration = (fqn, props) => Effect28.map(Effect28.serviceOption(Stack), (stack) => {
|
|
2379
2381
|
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
2380
2382
|
return declared !== undefined && carries(declared.Props, props);
|
|
2381
2383
|
});
|
|
2382
2384
|
|
|
2383
2385
|
// src/ownership/rows.ts
|
|
2384
|
-
var storeOf =
|
|
2385
|
-
const stack = yield*
|
|
2386
|
-
const state = yield*
|
|
2386
|
+
var storeOf = Effect29.gen(function* () {
|
|
2387
|
+
const stack = yield* Effect29.serviceOption(Stack2);
|
|
2388
|
+
const state = yield* Effect29.serviceOption(State);
|
|
2387
2389
|
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
2388
2390
|
return;
|
|
2389
2391
|
const store = yield* state.value;
|
|
2390
2392
|
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
2391
2393
|
return { resources: stack.value.resources, store, where };
|
|
2392
2394
|
});
|
|
2393
|
-
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(
|
|
2395
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect29.orElseSucceed(() => {
|
|
2394
2396
|
return;
|
|
2395
2397
|
}));
|
|
2396
2398
|
var generationOf = (row, instanceId) => {
|
|
@@ -2403,7 +2405,7 @@ var generationOf = (row, instanceId) => {
|
|
|
2403
2405
|
}
|
|
2404
2406
|
return;
|
|
2405
2407
|
};
|
|
2406
|
-
var recordedGeneration = (fqn, instanceId) =>
|
|
2408
|
+
var recordedGeneration = (fqn, instanceId) => Effect29.gen(function* () {
|
|
2407
2409
|
const found = yield* storeOf;
|
|
2408
2410
|
if (found === undefined)
|
|
2409
2411
|
return;
|
|
@@ -2414,14 +2416,14 @@ var recordedGeneration = (fqn, instanceId) => Effect28.gen(function* () {
|
|
|
2414
2416
|
}
|
|
2415
2417
|
return;
|
|
2416
2418
|
});
|
|
2417
|
-
var recordedInstance = (fqn, instanceId) =>
|
|
2419
|
+
var recordedInstance = (fqn, instanceId) => Effect29.gen(function* () {
|
|
2418
2420
|
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
2419
2421
|
if (generation === undefined)
|
|
2420
2422
|
return "absent";
|
|
2421
2423
|
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
2422
2424
|
});
|
|
2423
|
-
var isCreate = (fqn, instanceId) =>
|
|
2424
|
-
var forgetRefusedCreate = (fqn, instanceId) =>
|
|
2425
|
+
var isCreate = (fqn, instanceId) => Effect29.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
2426
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect29.gen(function* () {
|
|
2425
2427
|
const found = yield* storeOf;
|
|
2426
2428
|
if (found === undefined)
|
|
2427
2429
|
return;
|
|
@@ -2430,32 +2432,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect28.gen(function* () {
|
|
|
2430
2432
|
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
2431
2433
|
return;
|
|
2432
2434
|
}
|
|
2433
|
-
yield* found.store.delete({ ...found.where, fqn }).pipe(
|
|
2435
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect29.ignore);
|
|
2434
2436
|
});
|
|
2435
2437
|
|
|
2436
2438
|
// src/ownership/adopt.ts
|
|
2437
|
-
var adoptEnabled = (fqn) =>
|
|
2438
|
-
const stack = yield*
|
|
2439
|
+
var adoptEnabled = (fqn) => Effect30.gen(function* () {
|
|
2440
|
+
const stack = yield* Effect30.serviceOption(Stack3);
|
|
2439
2441
|
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
2440
2442
|
if (scoped !== undefined)
|
|
2441
2443
|
return scoped;
|
|
2442
|
-
const policy = yield*
|
|
2444
|
+
const policy = yield* Effect30.serviceOption(AdoptPolicy);
|
|
2443
2445
|
if (Option5.isSome(policy))
|
|
2444
2446
|
return policy.value;
|
|
2445
|
-
const context = yield*
|
|
2447
|
+
const context = yield* Effect30.serviceOption(AlchemyContext);
|
|
2446
2448
|
return Option5.isSome(context) ? context.value.adopt : false;
|
|
2447
2449
|
});
|
|
2448
|
-
var adoptable = (owner) =>
|
|
2450
|
+
var adoptable = (owner) => Effect30.gen(function* () {
|
|
2449
2451
|
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
2450
2452
|
return true;
|
|
2451
2453
|
return yield* unfinished(owner.instanceId);
|
|
2452
2454
|
});
|
|
2453
|
-
var adoptsAtApply = (owner) =>
|
|
2455
|
+
var adoptsAtApply = (owner) => Effect30.gen(function* () {
|
|
2454
2456
|
if (!(yield* adoptEnabled(owner.fqn)))
|
|
2455
2457
|
return false;
|
|
2456
2458
|
return yield* adoptable(owner);
|
|
2457
2459
|
});
|
|
2458
|
-
var refuseTakeover = (owner, what) =>
|
|
2460
|
+
var refuseTakeover = (owner, what) => Effect30.gen(function* () {
|
|
2459
2461
|
if (owner.output !== undefined)
|
|
2460
2462
|
return;
|
|
2461
2463
|
if (yield* resumes(owner.instanceId))
|
|
@@ -2465,25 +2467,25 @@ var refuseTakeover = (owner, what) => Effect29.gen(function* () {
|
|
|
2465
2467
|
return;
|
|
2466
2468
|
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
2467
2469
|
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.";
|
|
2468
|
-
return yield*
|
|
2470
|
+
return yield* Effect30.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}`));
|
|
2469
2471
|
});
|
|
2470
2472
|
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
2471
2473
|
|
|
2472
2474
|
// src/ownership/probe.ts
|
|
2473
2475
|
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
2474
|
-
import * as
|
|
2475
|
-
var provenOurs = (ask, settled2) =>
|
|
2476
|
+
import * as Effect31 from "effect/Effect";
|
|
2477
|
+
var provenOurs = (ask, settled2) => Effect31.gen(function* () {
|
|
2476
2478
|
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
2477
2479
|
if (recorded === "absent")
|
|
2478
2480
|
return false;
|
|
2479
2481
|
if (recorded === "partial") {
|
|
2480
|
-
yield*
|
|
2482
|
+
yield* Effect31.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");
|
|
2481
2483
|
return false;
|
|
2482
2484
|
}
|
|
2483
|
-
const unproven = (reason) =>
|
|
2484
|
-
return yield* settled2.pipe(
|
|
2485
|
+
const unproven = (reason) => Effect31.as(Effect31.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);
|
|
2486
|
+
return yield* settled2.pipe(Effect31.catch(unproven), Effect31.catchDefect(unproven));
|
|
2485
2487
|
});
|
|
2486
|
-
var ownedRead = (ask, found, settled2) =>
|
|
2488
|
+
var ownedRead = (ask, found, settled2) => Effect31.gen(function* () {
|
|
2487
2489
|
if (found === undefined || ask.output !== undefined)
|
|
2488
2490
|
return found;
|
|
2489
2491
|
return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
|
|
@@ -2938,11 +2940,11 @@ var identityRefusals = (news, olds, output) => {
|
|
|
2938
2940
|
};
|
|
2939
2941
|
|
|
2940
2942
|
// src/proxmox/lxc-adoption.ts
|
|
2941
|
-
import * as
|
|
2943
|
+
import * as Effect35 from "effect/Effect";
|
|
2942
2944
|
|
|
2943
2945
|
// src/ownership/adopting.ts
|
|
2944
|
-
import * as
|
|
2945
|
-
var adopting = (owner, settled2) =>
|
|
2946
|
+
import * as Effect32 from "effect/Effect";
|
|
2947
|
+
var adopting = (owner, settled2) => Effect32.gen(function* () {
|
|
2946
2948
|
if (owner.output === undefined)
|
|
2947
2949
|
return false;
|
|
2948
2950
|
const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
|
|
@@ -2954,11 +2956,11 @@ var adopting = (owner, settled2) => Effect31.gen(function* () {
|
|
|
2954
2956
|
});
|
|
2955
2957
|
|
|
2956
2958
|
// src/proxmox/lxc-lifecycle.ts
|
|
2957
|
-
import * as
|
|
2959
|
+
import * as Effect34 from "effect/Effect";
|
|
2958
2960
|
|
|
2959
2961
|
// src/proxmox/network-apply-read.ts
|
|
2960
|
-
import * as
|
|
2961
|
-
var stagedDiff = (target, node) =>
|
|
2962
|
+
import * as Effect33 from "effect/Effect";
|
|
2963
|
+
var stagedDiff = (target, node) => Effect33.gen(function* () {
|
|
2962
2964
|
const path = `nodes/${node}/network`;
|
|
2963
2965
|
const credential = yield* leased(target, "read");
|
|
2964
2966
|
const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
|
|
@@ -2971,8 +2973,8 @@ var pendingLines = (diff) => {
|
|
|
2971
2973
|
`).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
|
|
2972
2974
|
return Math.max(changed, 1);
|
|
2973
2975
|
};
|
|
2974
|
-
var pendingCount = (target, node) => stagedDiff(target, node).pipe(
|
|
2975
|
-
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(
|
|
2976
|
+
var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect33.map(pendingLines));
|
|
2977
|
+
var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect33.map((rows) => {
|
|
2976
2978
|
const all = rows ?? [];
|
|
2977
2979
|
const cluster = all.find((row) => row.type === "cluster");
|
|
2978
2980
|
return {
|
|
@@ -2980,21 +2982,21 @@ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pip
|
|
|
2980
2982
|
quorate: cluster === undefined ? true : bool(cluster.quorate)
|
|
2981
2983
|
};
|
|
2982
2984
|
}));
|
|
2983
|
-
var degradedReason = (target) => clusterHealth(target).pipe(
|
|
2985
|
+
var degradedReason = (target) => clusterHealth(target).pipe(Effect33.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
|
|
2984
2986
|
var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
2985
2987
|
var STILL_RUNNING = "still running when this provider stopped waiting";
|
|
2986
2988
|
var ATTEMPTS = 30;
|
|
2987
|
-
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) =>
|
|
2989
|
+
var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect33.gen(function* () {
|
|
2988
2990
|
const path = `nodes/${node}/tasks/${upid}/status`;
|
|
2989
2991
|
for (let attempt = 0;attempt < attempts; attempt += 1) {
|
|
2990
|
-
const status = yield* pveWith(target, credential, "GET", path).pipe(
|
|
2992
|
+
const status = yield* pveWith(target, credential, "GET", path).pipe(Effect33.orElseSucceed(() => {
|
|
2991
2993
|
return;
|
|
2992
2994
|
}));
|
|
2993
2995
|
if (status === undefined)
|
|
2994
2996
|
return UNREACHABLE;
|
|
2995
2997
|
if (status.status === "stopped")
|
|
2996
2998
|
return text(status.exitstatus, "stopped with no exitstatus");
|
|
2997
|
-
yield*
|
|
2999
|
+
yield* Effect33.sleep("1 second");
|
|
2998
3000
|
}
|
|
2999
3001
|
return STILL_RUNNING;
|
|
3000
3002
|
});
|
|
@@ -3012,17 +3014,17 @@ var LXC_ENDPOINTS = {
|
|
|
3012
3014
|
var CREATE_POLLS = 180;
|
|
3013
3015
|
var TASK_POLLS = 60;
|
|
3014
3016
|
var isServerError = (error) => error instanceof PveError && error.status === 500;
|
|
3015
|
-
var readLive = (where) =>
|
|
3016
|
-
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(
|
|
3017
|
+
var readLive = (where) => Effect34.gen(function* () {
|
|
3018
|
+
const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect34.map((data) => ({ data, error: undefined })), Effect34.catchIf(isServerError, (error) => Effect34.succeed({ data: undefined, error })));
|
|
3017
3019
|
if (answer.data !== undefined && answer.data !== null)
|
|
3018
3020
|
return answer.data;
|
|
3019
3021
|
const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
|
|
3020
3022
|
const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
|
|
3021
3023
|
if (found !== undefined && found.node === where.node && found.type === "lxc") {
|
|
3022
|
-
return yield*
|
|
3024
|
+
return yield* Effect34.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
|
|
3023
3025
|
}
|
|
3024
3026
|
if (found !== undefined) {
|
|
3025
|
-
return yield*
|
|
3027
|
+
return yield* Effect34.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."));
|
|
3026
3028
|
}
|
|
3027
3029
|
return;
|
|
3028
3030
|
});
|
|
@@ -3032,23 +3034,23 @@ var attributesOf4 = (where, live) => ({
|
|
|
3032
3034
|
rawKeys: rawKeysOf(live),
|
|
3033
3035
|
vmid: where.vmid
|
|
3034
3036
|
});
|
|
3035
|
-
var task = (where, method, path, what, polls, form) =>
|
|
3037
|
+
var task = (where, method, path, what, polls, form) => Effect34.gen(function* () {
|
|
3036
3038
|
const credential = yield* mint(where.target, "provision");
|
|
3037
3039
|
const upid = text(yield* pveWith(where.target, credential, method, path, form));
|
|
3038
3040
|
if (upid === "") {
|
|
3039
|
-
return yield*
|
|
3041
|
+
return yield* Effect34.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
|
|
3040
3042
|
}
|
|
3041
3043
|
const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
|
|
3042
3044
|
if (exit !== "OK") {
|
|
3043
|
-
return yield*
|
|
3045
|
+
return yield* Effect34.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
|
|
3044
3046
|
}
|
|
3045
3047
|
});
|
|
3046
|
-
var createGuest = (props) =>
|
|
3048
|
+
var createGuest = (props) => Effect34.gen(function* () {
|
|
3047
3049
|
const form = createForm4(props);
|
|
3048
3050
|
yield* guardForm(LXC_ENDPOINTS.create, form, true);
|
|
3049
3051
|
return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
|
|
3050
3052
|
});
|
|
3051
|
-
var updateGuest = (props, change, digest) =>
|
|
3053
|
+
var updateGuest = (props, change, digest) => Effect34.gen(function* () {
|
|
3052
3054
|
if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
|
|
3053
3055
|
const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
|
|
3054
3056
|
yield* guardForm(LXC_ENDPOINTS.update, form, false);
|
|
@@ -3060,33 +3062,33 @@ var updateGuest = (props, change, digest) => Effect33.gen(function* () {
|
|
|
3060
3062
|
yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
|
|
3061
3063
|
}
|
|
3062
3064
|
});
|
|
3063
|
-
var destroyGuest = (where, declared) =>
|
|
3065
|
+
var destroyGuest = (where, declared) => Effect34.gen(function* () {
|
|
3064
3066
|
const live = yield* readLive(where);
|
|
3065
3067
|
if (live === undefined)
|
|
3066
3068
|
return;
|
|
3067
3069
|
const drift = judge(declared, live).drift;
|
|
3068
3070
|
if (drift.length > 0) {
|
|
3069
|
-
return yield*
|
|
3071
|
+
return yield* Effect34.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."));
|
|
3070
3072
|
}
|
|
3071
3073
|
yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
|
|
3072
3074
|
});
|
|
3073
3075
|
|
|
3074
3076
|
// src/proxmox/lxc-adoption.ts
|
|
3075
3077
|
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.";
|
|
3076
|
-
var refuseAdoptedDrift = (owner, props, live, change) =>
|
|
3078
|
+
var refuseAdoptedDrift = (owner, props, live, change) => Effect35.gen(function* () {
|
|
3077
3079
|
if (change.drift.length === 0)
|
|
3078
3080
|
return;
|
|
3079
|
-
const settled2 = (recorded) =>
|
|
3081
|
+
const settled2 = (recorded) => Effect35.sync(() => judge(recorded, live).drift.length === 0);
|
|
3080
3082
|
if (!(yield* adopting(owner, settled2)))
|
|
3081
3083
|
return;
|
|
3082
|
-
return yield*
|
|
3084
|
+
return yield* Effect35.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
|
|
3083
3085
|
});
|
|
3084
3086
|
|
|
3085
3087
|
// src/proxmox/lxc.ts
|
|
3086
3088
|
var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
|
|
3087
|
-
var refused = (reasons) =>
|
|
3089
|
+
var refused = (reasons) => Effect36.fail(new LxcRefusedError(reasons.join(`
|
|
3088
3090
|
`)));
|
|
3089
|
-
var diff = (owner, news, olds) =>
|
|
3091
|
+
var diff = (owner, news, olds) => Effect36.gen(function* () {
|
|
3090
3092
|
const { output } = owner;
|
|
3091
3093
|
const identity2 = identityRefusals(news, olds, output);
|
|
3092
3094
|
if (identity2.length > 0)
|
|
@@ -3100,7 +3102,7 @@ var diff = (owner, news, olds) => Effect35.gen(function* () {
|
|
|
3100
3102
|
const refusals = createRefusals(news);
|
|
3101
3103
|
if (refusals.length > 0)
|
|
3102
3104
|
return yield* refused(refusals);
|
|
3103
|
-
yield*
|
|
3105
|
+
yield* Effect36.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.");
|
|
3104
3106
|
return { action: "update" };
|
|
3105
3107
|
}
|
|
3106
3108
|
const change = judge(news, live);
|
|
@@ -3111,10 +3113,10 @@ var diff = (owner, news, olds) => Effect35.gen(function* () {
|
|
|
3111
3113
|
if (change.drift.length === 0 && !moved)
|
|
3112
3114
|
return { action: "noop" };
|
|
3113
3115
|
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.";
|
|
3114
|
-
yield*
|
|
3116
|
+
yield* Effect36.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
|
|
3115
3117
|
return { action: "update" };
|
|
3116
3118
|
});
|
|
3117
|
-
var reconcile = (owner, news) =>
|
|
3119
|
+
var reconcile = (owner, news) => Effect36.gen(function* () {
|
|
3118
3120
|
const { output } = owner;
|
|
3119
3121
|
const identity2 = identityRefusals(news, news, output);
|
|
3120
3122
|
if (identity2.length > 0)
|
|
@@ -3160,12 +3162,12 @@ var whereOf = (olds, output) => ({
|
|
|
3160
3162
|
target: olds.target,
|
|
3161
3163
|
vmid: output?.vmid ?? olds.vmid
|
|
3162
3164
|
});
|
|
3163
|
-
var read = (owner, olds) =>
|
|
3165
|
+
var read = (owner, olds) => Effect36.gen(function* () {
|
|
3164
3166
|
const where = whereOf(olds, owner.output);
|
|
3165
3167
|
const live = yield* readLive(where);
|
|
3166
3168
|
if (live === undefined)
|
|
3167
3169
|
return;
|
|
3168
|
-
const settled2 =
|
|
3170
|
+
const settled2 = Effect36.sync(() => judge(olds, live).drift.length === 0);
|
|
3169
3171
|
return yield* ownedRead(owner, attributesOf4(where, live), settled2);
|
|
3170
3172
|
});
|
|
3171
3173
|
var handlers8 = {
|
|
@@ -3177,7 +3179,7 @@ var handlers8 = {
|
|
|
3177
3179
|
olds,
|
|
3178
3180
|
output
|
|
3179
3181
|
}) => diff({ fqn, instanceId, output }, news, olds),
|
|
3180
|
-
list: () =>
|
|
3182
|
+
list: () => Effect36.succeed([]),
|
|
3181
3183
|
read: ({
|
|
3182
3184
|
fqn,
|
|
3183
3185
|
instanceId,
|
|
@@ -3191,11 +3193,11 @@ var handlers8 = {
|
|
|
3191
3193
|
output
|
|
3192
3194
|
}) => reconcile({ fqn, instanceId, output }, news)
|
|
3193
3195
|
};
|
|
3194
|
-
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc,
|
|
3196
|
+
var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect36.succeed(ProxmoxLxc.Provider.of(handlers8)).pipe(Effect36.map(provingResumes)));
|
|
3195
3197
|
// src/proxmox/metric-server.ts
|
|
3196
3198
|
import { Resource as Resource14 } from "alchemy";
|
|
3197
3199
|
import * as Provider14 from "alchemy/Provider";
|
|
3198
|
-
import * as
|
|
3200
|
+
import * as Effect37 from "effect/Effect";
|
|
3199
3201
|
|
|
3200
3202
|
// src/proxmox/metric-server-form.ts
|
|
3201
3203
|
var UNSET2 = -1;
|
|
@@ -3308,12 +3310,12 @@ var handlers9 = pveHandlers({
|
|
|
3308
3310
|
path: (props) => `cluster/metrics/server/${props.id}`,
|
|
3309
3311
|
updateForm: update
|
|
3310
3312
|
});
|
|
3311
|
-
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer,
|
|
3313
|
+
var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect37.succeed(ProxmoxMetricServer.Provider.of(handlers9)));
|
|
3312
3314
|
// src/proxmox/network-apply.ts
|
|
3313
3315
|
import { Resource as Resource15 } from "alchemy";
|
|
3314
3316
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
3315
3317
|
import * as Provider15 from "alchemy/Provider";
|
|
3316
|
-
import * as
|
|
3318
|
+
import * as Effect38 from "effect/Effect";
|
|
3317
3319
|
|
|
3318
3320
|
// src/proxmox/apply-endpoints.ts
|
|
3319
3321
|
var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
|
|
@@ -3323,15 +3325,15 @@ var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
|
|
|
3323
3325
|
|
|
3324
3326
|
// src/proxmox/network-apply.ts
|
|
3325
3327
|
var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
|
|
3326
|
-
var read2 = (props) => pendingCount(props.target, props.node).pipe(
|
|
3327
|
-
var diff2 = (news) =>
|
|
3328
|
+
var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect38.map((pending) => ({ node: props.node, pending })));
|
|
3329
|
+
var diff2 = (news) => Effect38.gen(function* () {
|
|
3328
3330
|
if (!isResolved9(news))
|
|
3329
3331
|
return;
|
|
3330
3332
|
const { pending } = yield* read2(news);
|
|
3331
3333
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3332
3334
|
});
|
|
3333
|
-
var refuse = (node, why) =>
|
|
3334
|
-
var apply = (props) =>
|
|
3335
|
+
var refuse = (node, why) => Effect38.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
|
|
3336
|
+
var apply = (props) => Effect38.gen(function* () {
|
|
3335
3337
|
const node = props.node;
|
|
3336
3338
|
const staged = yield* pendingCount(props.target, node);
|
|
3337
3339
|
if (staged === 0)
|
|
@@ -3361,17 +3363,17 @@ var apply = (props) => Effect37.gen(function* () {
|
|
|
3361
3363
|
return { node, pending: left };
|
|
3362
3364
|
});
|
|
3363
3365
|
var handlers10 = {
|
|
3364
|
-
delete: () =>
|
|
3366
|
+
delete: () => Effect38.void,
|
|
3365
3367
|
diff: ({ news }) => diff2(news),
|
|
3366
|
-
list: () =>
|
|
3368
|
+
list: () => Effect38.succeed([]),
|
|
3367
3369
|
read: ({ olds }) => read2(olds),
|
|
3368
3370
|
reconcile: ({ news }) => apply(news)
|
|
3369
3371
|
};
|
|
3370
|
-
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply,
|
|
3372
|
+
var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect38.succeed(ProxmoxNetworkApply.Provider.of(handlers10)));
|
|
3371
3373
|
// src/proxmox/node-network.ts
|
|
3372
3374
|
import { Resource as Resource16 } from "alchemy";
|
|
3373
3375
|
import * as Provider16 from "alchemy/Provider";
|
|
3374
|
-
import * as
|
|
3376
|
+
import * as Effect39 from "effect/Effect";
|
|
3375
3377
|
|
|
3376
3378
|
// src/proxmox/node-network-form.ts
|
|
3377
3379
|
var UNSET3 = -1;
|
|
@@ -3459,11 +3461,11 @@ var handlers11 = pveHandlers({
|
|
|
3459
3461
|
path: (props) => `nodes/${props.node}/network/${props.iface}`,
|
|
3460
3462
|
updateForm: updateBody2
|
|
3461
3463
|
});
|
|
3462
|
-
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork,
|
|
3464
|
+
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect39.succeed(ProxmoxNodeNetwork.Provider.of(handlers11)));
|
|
3463
3465
|
// src/proxmox/notification-matcher.ts
|
|
3464
3466
|
import { Resource as Resource17 } from "alchemy";
|
|
3465
3467
|
import * as Provider17 from "alchemy/Provider";
|
|
3466
|
-
import * as
|
|
3468
|
+
import * as Effect40 from "effect/Effect";
|
|
3467
3469
|
|
|
3468
3470
|
// src/proxmox/notification-matcher-form.ts
|
|
3469
3471
|
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
@@ -3553,11 +3555,11 @@ var handlers12 = pveHandlers({
|
|
|
3553
3555
|
path: (props) => `cluster/notifications/matchers/${props.name}`,
|
|
3554
3556
|
updateForm: matcherUpdateForm
|
|
3555
3557
|
});
|
|
3556
|
-
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher,
|
|
3558
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect40.succeed(ProxmoxNotificationMatcher.Provider.of(handlers12)));
|
|
3557
3559
|
// src/proxmox/notification-target.ts
|
|
3558
3560
|
import { Resource as Resource18 } from "alchemy";
|
|
3559
3561
|
import * as Provider18 from "alchemy/Provider";
|
|
3560
|
-
import * as
|
|
3562
|
+
import * as Effect41 from "effect/Effect";
|
|
3561
3563
|
|
|
3562
3564
|
// src/proxmox/notification-target-endpoint.ts
|
|
3563
3565
|
var ENDPOINTS = {
|
|
@@ -3639,15 +3641,15 @@ var handlers13 = pveHandlers({
|
|
|
3639
3641
|
path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
|
|
3640
3642
|
updateForm: shape4
|
|
3641
3643
|
});
|
|
3642
|
-
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget,
|
|
3644
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect41.succeed(ProxmoxNotificationTarget.Provider.of(handlers13)));
|
|
3643
3645
|
// src/proxmox/pbs-datastore.ts
|
|
3644
3646
|
import { Resource as Resource19 } from "alchemy";
|
|
3645
3647
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
3646
3648
|
import * as Provider19 from "alchemy/Provider";
|
|
3647
|
-
import * as
|
|
3649
|
+
import * as Effect45 from "effect/Effect";
|
|
3648
3650
|
|
|
3649
3651
|
// src/proxmox/pbs-datastore-form.ts
|
|
3650
|
-
import * as
|
|
3652
|
+
import * as Effect42 from "effect/Effect";
|
|
3651
3653
|
var attributes = (live, props) => ({
|
|
3652
3654
|
backend: propertyString(live["backend"]),
|
|
3653
3655
|
comment: text(live["comment"]),
|
|
@@ -3699,35 +3701,35 @@ var createForm5 = (props) => ({
|
|
|
3699
3701
|
});
|
|
3700
3702
|
var updateForm2 = (props) => mutable(props);
|
|
3701
3703
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
3702
|
-
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(
|
|
3704
|
+
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect42.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect42.orElseSucceed(() => {
|
|
3703
3705
|
return;
|
|
3704
3706
|
}));
|
|
3705
3707
|
|
|
3706
3708
|
// src/proxmox/pbs-datastore-guard.ts
|
|
3707
|
-
import * as
|
|
3709
|
+
import * as Effect43 from "effect/Effect";
|
|
3708
3710
|
var samePath = (left, right) => {
|
|
3709
3711
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
3710
3712
|
return trim(left) === trim(right);
|
|
3711
3713
|
};
|
|
3712
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
3713
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
3714
|
-
var settle3 = (read3, done) =>
|
|
3714
|
+
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect43.void : Effect43.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."));
|
|
3715
|
+
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect43.void : Effect43.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."));
|
|
3716
|
+
var settle3 = (read3, done) => Effect43.gen(function* () {
|
|
3715
3717
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
3716
3718
|
const live = yield* read3;
|
|
3717
3719
|
if (done(live))
|
|
3718
3720
|
return live;
|
|
3719
|
-
yield*
|
|
3721
|
+
yield* Effect43.sleep("2 seconds");
|
|
3720
3722
|
}
|
|
3721
3723
|
return yield* read3;
|
|
3722
3724
|
});
|
|
3723
3725
|
|
|
3724
3726
|
// src/proxmox/pbs-datastore-endpoint.ts
|
|
3725
|
-
import * as
|
|
3727
|
+
import * as Effect44 from "effect/Effect";
|
|
3726
3728
|
var DATASTORE_ENDPOINT = {
|
|
3727
3729
|
create: "pbs:POST /config/datastore",
|
|
3728
3730
|
update: "pbs:PUT /config/datastore/{name}"
|
|
3729
3731
|
};
|
|
3730
|
-
var guardDatastoreForms = (props) =>
|
|
3732
|
+
var guardDatastoreForms = (props) => Effect44.gen(function* () {
|
|
3731
3733
|
yield* guardForm(DATASTORE_ENDPOINT.create, createForm5(props), true);
|
|
3732
3734
|
yield* guardForm(DATASTORE_ENDPOINT.update, updateForm2(props), false);
|
|
3733
3735
|
});
|
|
@@ -3736,10 +3738,10 @@ var guardDatastoreForms = (props) => Effect43.gen(function* () {
|
|
|
3736
3738
|
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
3737
3739
|
defaultRemovalPolicy: "retain"
|
|
3738
3740
|
});
|
|
3739
|
-
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore,
|
|
3740
|
-
list: () =>
|
|
3741
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect45.succeed(PbsDatastore.Provider.of({
|
|
3742
|
+
list: () => Effect45.succeed([]),
|
|
3741
3743
|
read: ({ olds }) => readOne(olds),
|
|
3742
|
-
diff: ({ news, output }) =>
|
|
3744
|
+
diff: ({ news, output }) => Effect45.gen(function* () {
|
|
3743
3745
|
if (!isResolved10(news))
|
|
3744
3746
|
return;
|
|
3745
3747
|
yield* guardDatastoreForms(news);
|
|
@@ -3752,7 +3754,7 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect44.succee
|
|
|
3752
3754
|
yield* guardBackend(live, news);
|
|
3753
3755
|
return matches4(live, news) ? { action: "noop" } : { action: "update" };
|
|
3754
3756
|
}),
|
|
3755
|
-
reconcile:
|
|
3757
|
+
reconcile: Effect45.fn(function* ({ news }) {
|
|
3756
3758
|
yield* guardDatastoreForms(news);
|
|
3757
3759
|
const live = yield* readOne(news);
|
|
3758
3760
|
let upid;
|
|
@@ -3768,22 +3770,22 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect44.succee
|
|
|
3768
3770
|
}
|
|
3769
3771
|
const after = yield* settle3(readOne(news), (row) => row !== undefined && matches4(row, news));
|
|
3770
3772
|
if (after === undefined || !matches4(after, news)) {
|
|
3771
|
-
return yield*
|
|
3773
|
+
return yield* Effect45.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + `match the declaration after 120s. PBS answered with task ${upid ?? "(none)"} ` + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
|
|
3772
3774
|
}
|
|
3773
3775
|
return after;
|
|
3774
3776
|
}),
|
|
3775
|
-
delete:
|
|
3777
|
+
delete: Effect45.fn(function* ({ olds }) {
|
|
3776
3778
|
yield* pve(olds.target, "provision", "DELETE", object2(olds));
|
|
3777
3779
|
const left = yield* settle3(readOne(olds), (row) => row === undefined);
|
|
3778
3780
|
if (left !== undefined) {
|
|
3779
|
-
return yield*
|
|
3781
|
+
return yield* Effect45.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>\`.`));
|
|
3780
3782
|
}
|
|
3781
3783
|
})
|
|
3782
3784
|
})));
|
|
3783
3785
|
// src/proxmox/pbs-notification-matcher.ts
|
|
3784
3786
|
import { Resource as Resource20 } from "alchemy";
|
|
3785
3787
|
import * as Provider20 from "alchemy/Provider";
|
|
3786
|
-
import * as
|
|
3788
|
+
import * as Effect46 from "effect/Effect";
|
|
3787
3789
|
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
3788
3790
|
var handlers14 = pveHandlers({
|
|
3789
3791
|
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
@@ -3797,15 +3799,15 @@ var handlers14 = pveHandlers({
|
|
|
3797
3799
|
path: (props) => `config/notifications/matchers/${props.name}`,
|
|
3798
3800
|
updateForm: matcherUpdateForm
|
|
3799
3801
|
});
|
|
3800
|
-
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher,
|
|
3802
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect46.succeed(PbsNotificationMatcher.Provider.of(handlers14)));
|
|
3801
3803
|
// src/proxmox/pbs-notification-target.ts
|
|
3802
3804
|
import { Resource as Resource21 } from "alchemy";
|
|
3803
3805
|
import * as Provider21 from "alchemy/Provider";
|
|
3804
|
-
import * as
|
|
3806
|
+
import * as Effect48 from "effect/Effect";
|
|
3805
3807
|
|
|
3806
3808
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
3807
3809
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
3808
|
-
import * as
|
|
3810
|
+
import * as Effect47 from "effect/Effect";
|
|
3809
3811
|
|
|
3810
3812
|
// src/proxmox/pbs-notification-target-endpoint.ts
|
|
3811
3813
|
var ENDPOINTS2 = {
|
|
@@ -4082,12 +4084,12 @@ var targetForm = (props, groups, carry, mode) => {
|
|
|
4082
4084
|
|
|
4083
4085
|
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
4084
4086
|
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
4085
|
-
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(
|
|
4087
|
+
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect47.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect47.orElseSucceed(() => {
|
|
4086
4088
|
return;
|
|
4087
4089
|
}));
|
|
4088
4090
|
var refuse2 = (props) => {
|
|
4089
4091
|
const reasons = refusals(props);
|
|
4090
|
-
return reasons.length === 0 ?
|
|
4092
|
+
return reasons.length === 0 ? Effect47.void : Effect47.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
4091
4093
|
};
|
|
4092
4094
|
var toCarry = (live, props, groups, sealed) => {
|
|
4093
4095
|
const header = headerState(live, props, groups) === "stale";
|
|
@@ -4099,16 +4101,16 @@ var requireValues = (props, groups, carry) => {
|
|
|
4099
4101
|
...carry.header ? groups.header.missing : [],
|
|
4100
4102
|
...carry.sealed ? groups.sealed.missing : []
|
|
4101
4103
|
];
|
|
4102
|
-
return missing.length === 0 ?
|
|
4104
|
+
return missing.length === 0 ? Effect47.void : Effect47.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."));
|
|
4103
4105
|
};
|
|
4104
4106
|
var handlers15 = {
|
|
4105
|
-
list: () =>
|
|
4106
|
-
read: ({ olds, output }) => (output === undefined ? refuse2(olds) :
|
|
4107
|
+
list: () => Effect47.succeed([]),
|
|
4108
|
+
read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect47.void).pipe(Effect47.andThen(readLive2(olds)), Effect47.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
|
|
4107
4109
|
diff: ({
|
|
4108
4110
|
news,
|
|
4109
4111
|
olds,
|
|
4110
4112
|
output
|
|
4111
|
-
}) =>
|
|
4113
|
+
}) => Effect47.gen(function* () {
|
|
4112
4114
|
if (output === undefined || !isResolved11(news))
|
|
4113
4115
|
return;
|
|
4114
4116
|
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
@@ -4120,7 +4122,7 @@ var handlers15 = {
|
|
|
4120
4122
|
return { action: "update" };
|
|
4121
4123
|
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
4122
4124
|
}),
|
|
4123
|
-
reconcile: ({ news, output }) =>
|
|
4125
|
+
reconcile: ({ news, output }) => Effect47.gen(function* () {
|
|
4124
4126
|
yield* refuse2(news);
|
|
4125
4127
|
const groups = resolveGroups(news);
|
|
4126
4128
|
const live = yield* readLive2(news);
|
|
@@ -4146,7 +4148,7 @@ var handlers15 = {
|
|
|
4146
4148
|
}
|
|
4147
4149
|
const after = yield* readLive2(news);
|
|
4148
4150
|
if (after === undefined) {
|
|
4149
|
-
return yield*
|
|
4151
|
+
return yield* Effect47.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
4150
4152
|
}
|
|
4151
4153
|
return { ...after, sealed };
|
|
4152
4154
|
}),
|
|
@@ -4155,11 +4157,11 @@ var handlers15 = {
|
|
|
4155
4157
|
|
|
4156
4158
|
// src/proxmox/pbs-notification-target.ts
|
|
4157
4159
|
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
4158
|
-
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget,
|
|
4160
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect48.succeed(PbsNotificationTarget.Provider.of(handlers15)));
|
|
4159
4161
|
// src/proxmox/pbs-prune-job.ts
|
|
4160
4162
|
import { Resource as Resource22 } from "alchemy";
|
|
4161
4163
|
import * as Provider22 from "alchemy/Provider";
|
|
4162
|
-
import * as
|
|
4164
|
+
import * as Effect49 from "effect/Effect";
|
|
4163
4165
|
|
|
4164
4166
|
// src/proxmox/pbs-prune-job-form.ts
|
|
4165
4167
|
var KEEP_KEYS = [
|
|
@@ -4235,11 +4237,11 @@ var handlers16 = pveHandlers({
|
|
|
4235
4237
|
path: (props) => `config/prune/${props.id}`,
|
|
4236
4238
|
updateForm: updateBody3
|
|
4237
4239
|
});
|
|
4238
|
-
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob,
|
|
4240
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect49.succeed(PbsPruneJob.Provider.of(handlers16)));
|
|
4239
4241
|
// src/proxmox/pbs-sync-job.ts
|
|
4240
4242
|
import { Resource as Resource23 } from "alchemy";
|
|
4241
4243
|
import * as Provider23 from "alchemy/Provider";
|
|
4242
|
-
import * as
|
|
4244
|
+
import * as Effect50 from "effect/Effect";
|
|
4243
4245
|
|
|
4244
4246
|
// src/proxmox/pbs-sync-job-form.ts
|
|
4245
4247
|
var UNSET4 = -1;
|
|
@@ -4316,11 +4318,11 @@ var handlers17 = pveHandlers({
|
|
|
4316
4318
|
|
|
4317
4319
|
// src/proxmox/pbs-sync-job.ts
|
|
4318
4320
|
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
4319
|
-
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob,
|
|
4321
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect50.succeed(PbsSyncJob.Provider.of(handlers17)));
|
|
4320
4322
|
// src/proxmox/pbs-verify-job.ts
|
|
4321
4323
|
import { Resource as Resource24 } from "alchemy";
|
|
4322
4324
|
import * as Provider24 from "alchemy/Provider";
|
|
4323
|
-
import * as
|
|
4325
|
+
import * as Effect51 from "effect/Effect";
|
|
4324
4326
|
|
|
4325
4327
|
// src/proxmox/pbs-verify-job-form.ts
|
|
4326
4328
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -4365,11 +4367,11 @@ var handlers18 = pveHandlers({
|
|
|
4365
4367
|
path: (props) => `config/verify/${props.id}`,
|
|
4366
4368
|
updateForm: shape7
|
|
4367
4369
|
});
|
|
4368
|
-
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob,
|
|
4370
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect51.succeed(PbsVerifyJob.Provider.of(handlers18)));
|
|
4369
4371
|
// src/proxmox/pool.ts
|
|
4370
4372
|
import { Resource as Resource25 } from "alchemy";
|
|
4371
4373
|
import * as Provider25 from "alchemy/Provider";
|
|
4372
|
-
import * as
|
|
4374
|
+
import * as Effect52 from "effect/Effect";
|
|
4373
4375
|
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
4374
4376
|
var poolCreateForm = (props) => ({
|
|
4375
4377
|
comment: props.comment ?? "",
|
|
@@ -4394,7 +4396,7 @@ var handlers19 = pveHandlers({
|
|
|
4394
4396
|
path: (props) => `pools/${props.poolid}`,
|
|
4395
4397
|
updateForm: poolUpdateForm
|
|
4396
4398
|
});
|
|
4397
|
-
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool,
|
|
4399
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect52.succeed(ProxmoxPool.Provider.of(handlers19)));
|
|
4398
4400
|
// src/proxmox/provision-baseline.ts
|
|
4399
4401
|
var PROVISION_PRIVILEGES = Object.freeze([
|
|
4400
4402
|
"Datastore.Allocate",
|
|
@@ -4587,14 +4589,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
4587
4589
|
// src/proxmox/provision-declare.ts
|
|
4588
4590
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
4589
4591
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
4590
|
-
import * as
|
|
4592
|
+
import * as Effect56 from "effect/Effect";
|
|
4591
4593
|
|
|
4592
4594
|
// src/proxmox/role.ts
|
|
4593
4595
|
import { Resource as Resource26 } from "alchemy";
|
|
4594
4596
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
4595
4597
|
import * as Provider26 from "alchemy/Provider";
|
|
4596
|
-
import * as
|
|
4597
|
-
import * as
|
|
4598
|
+
import * as access5 from "@distilled.cloud/proxmox/access";
|
|
4599
|
+
import * as Effect53 from "effect/Effect";
|
|
4598
4600
|
|
|
4599
4601
|
// src/proxmox/role-wire.ts
|
|
4600
4602
|
var ROLE_CREATE = "pve:POST /access/roles";
|
|
@@ -4617,21 +4619,19 @@ var matches5 = (attributes2, props) => canonical2(attributes2.privs).join(",") =
|
|
|
4617
4619
|
|
|
4618
4620
|
// src/proxmox/role.ts
|
|
4619
4621
|
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
4620
|
-
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false,
|
|
4622
|
+
var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect53.map((rows) => {
|
|
4621
4623
|
if (rows === UNREADABLE)
|
|
4622
4624
|
return UNREADABLE;
|
|
4623
4625
|
const row = find2(rows, props.roleid);
|
|
4624
4626
|
return row === undefined ? undefined : attributesOf5(row, props);
|
|
4625
|
-
}), Effect52.orElseSucceed(() => {
|
|
4626
|
-
return;
|
|
4627
4627
|
}));
|
|
4628
4628
|
var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
|
|
4629
|
-
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole,
|
|
4630
|
-
list: () =>
|
|
4631
|
-
read:
|
|
4629
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect53.succeed(ProxmoxRole.Provider.of({
|
|
4630
|
+
list: () => Effect53.succeed([]),
|
|
4631
|
+
read: Effect53.fn(function* ({ olds }) {
|
|
4632
4632
|
return dropUnreadable4(yield* readRole(olds));
|
|
4633
4633
|
}),
|
|
4634
|
-
diff:
|
|
4634
|
+
diff: Effect53.fn(function* ({ news, output }) {
|
|
4635
4635
|
if (!isResolved12(news))
|
|
4636
4636
|
return;
|
|
4637
4637
|
yield* guardWrite2(ROLE_CREATE, createForm6(news), output === undefined);
|
|
@@ -4649,23 +4649,23 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect52.succeed(
|
|
|
4649
4649
|
}
|
|
4650
4650
|
return matches5(live, news) ? { action: "noop" } : { action: "update" };
|
|
4651
4651
|
}),
|
|
4652
|
-
reconcile:
|
|
4652
|
+
reconcile: Effect53.fn(function* ({ news }) {
|
|
4653
4653
|
const before = dropUnreadable4(yield* readRole(news));
|
|
4654
4654
|
yield* guardWrite2(ROLE_CREATE, createForm6(news), before === undefined);
|
|
4655
4655
|
yield* guardWrite2(ROLE_UPDATE, updateForm3(news), false);
|
|
4656
4656
|
if (before === undefined) {
|
|
4657
|
-
yield* runPve(news.target, "provision", true,
|
|
4657
|
+
yield* runPve(news.target, "provision", true, access5.createAccessRole(createForm6(news)));
|
|
4658
4658
|
} else if (!matches5(before, news)) {
|
|
4659
|
-
yield* runPve(news.target, "provision", true,
|
|
4659
|
+
yield* runPve(news.target, "provision", true, access5.putAccessRole(updateForm3(news)));
|
|
4660
4660
|
}
|
|
4661
4661
|
const after = dropUnreadable4(yield* readRole(news));
|
|
4662
4662
|
if (after === undefined) {
|
|
4663
|
-
return yield*
|
|
4663
|
+
return yield* Effect53.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."));
|
|
4664
4664
|
}
|
|
4665
4665
|
return after;
|
|
4666
4666
|
}),
|
|
4667
|
-
delete:
|
|
4668
|
-
yield* runPve(olds.target, "provision", true,
|
|
4667
|
+
delete: Effect53.fn(function* ({ olds }) {
|
|
4668
|
+
yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
|
|
4669
4669
|
})
|
|
4670
4670
|
})));
|
|
4671
4671
|
|
|
@@ -4673,10 +4673,12 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect52.succeed(
|
|
|
4673
4673
|
import { Resource as Resource27 } from "alchemy";
|
|
4674
4674
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
4675
4675
|
import * as Provider27 from "alchemy/Provider";
|
|
4676
|
-
import * as
|
|
4677
|
-
import * as
|
|
4676
|
+
import * as access7 from "@distilled.cloud/proxmox/access";
|
|
4677
|
+
import * as Effect55 from "effect/Effect";
|
|
4678
4678
|
|
|
4679
4679
|
// src/proxmox/user-wire.ts
|
|
4680
|
+
import * as access6 from "@distilled.cloud/proxmox/access";
|
|
4681
|
+
import * as Effect54 from "effect/Effect";
|
|
4680
4682
|
var USER_CREATE = "pve:POST /access/users";
|
|
4681
4683
|
var USER_UPDATE = "pve:PUT /access/users/{userid}";
|
|
4682
4684
|
var int2 = (value) => {
|
|
@@ -4718,26 +4720,27 @@ var attributesOf6 = (live, props) => ({
|
|
|
4718
4720
|
userid: props.userid
|
|
4719
4721
|
});
|
|
4720
4722
|
var matches6 = (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(",");
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
var ProxmoxUser = Resource27("Proxmox.User");
|
|
4724
|
-
var readUser = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.getAccessUser(props))).pipe(Effect53.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf6(live, props)), Effect53.orElseSucceed(() => {
|
|
4723
|
+
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect54.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf6(live, props)));
|
|
4724
|
+
var readUser = (props) => readUserOrFail(props).pipe(Effect54.orElseSucceed(() => {
|
|
4725
4725
|
return;
|
|
4726
4726
|
}));
|
|
4727
4727
|
var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4728
|
+
|
|
4729
|
+
// src/proxmox/user.ts
|
|
4730
|
+
var ProxmoxUser = Resource27("Proxmox.User");
|
|
4731
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect55.succeed(ProxmoxUser.Provider.of({
|
|
4732
|
+
list: () => Effect55.succeed([]),
|
|
4733
|
+
read: Effect55.fn(function* ({ olds, output }) {
|
|
4734
|
+
return dropUnreadable5(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
|
|
4732
4735
|
}),
|
|
4733
|
-
diff:
|
|
4736
|
+
diff: Effect55.fn(function* ({ news, output }) {
|
|
4734
4737
|
if (!isResolved13(news))
|
|
4735
4738
|
return;
|
|
4736
4739
|
yield* guardWrite2(USER_CREATE, createForm7(news), output === undefined);
|
|
4737
4740
|
yield* guardWrite2(USER_UPDATE, updateForm4(news), false);
|
|
4738
4741
|
if (output === undefined)
|
|
4739
4742
|
return;
|
|
4740
|
-
const live = yield*
|
|
4743
|
+
const live = yield* readUserOrFail(news);
|
|
4741
4744
|
if (live === UNREADABLE) {
|
|
4742
4745
|
yield* unreadableWarning("Proxmox.User", news.userid);
|
|
4743
4746
|
return { action: "noop" };
|
|
@@ -4748,29 +4751,29 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect53.succeed(
|
|
|
4748
4751
|
}
|
|
4749
4752
|
return matches6(live, news) ? { action: "noop" } : { action: "update" };
|
|
4750
4753
|
}),
|
|
4751
|
-
reconcile:
|
|
4754
|
+
reconcile: Effect55.fn(function* ({ news }) {
|
|
4752
4755
|
const before = dropUnreadable5(yield* readUser(news));
|
|
4753
4756
|
yield* guardWrite2(USER_CREATE, createForm7(news), before === undefined);
|
|
4754
4757
|
yield* guardWrite2(USER_UPDATE, updateForm4(news), false);
|
|
4755
4758
|
if (before === undefined) {
|
|
4756
|
-
yield* runPve(news.target, "provision", true,
|
|
4759
|
+
yield* runPve(news.target, "provision", true, access7.createAccessUser(createForm7(news)));
|
|
4757
4760
|
} else if (!matches6(before, news)) {
|
|
4758
|
-
yield* runPve(news.target, "provision", true,
|
|
4761
|
+
yield* runPve(news.target, "provision", true, access7.putAccessUser(updateForm4(news)));
|
|
4759
4762
|
}
|
|
4760
4763
|
const after = dropUnreadable5(yield* readUser(news));
|
|
4761
4764
|
if (after === undefined) {
|
|
4762
|
-
return yield*
|
|
4765
|
+
return yield* Effect55.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."));
|
|
4763
4766
|
}
|
|
4764
4767
|
return after;
|
|
4765
4768
|
}),
|
|
4766
|
-
delete:
|
|
4767
|
-
yield* runPve(olds.target, "provision", true,
|
|
4769
|
+
delete: Effect55.fn(function* ({ olds }) {
|
|
4770
|
+
yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
|
|
4768
4771
|
})
|
|
4769
4772
|
})));
|
|
4770
4773
|
|
|
4771
4774
|
// src/proxmox/provision-declare.ts
|
|
4772
|
-
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) =>
|
|
4773
|
-
const baseline = yield*
|
|
4775
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect56.gen(function* () {
|
|
4776
|
+
const baseline = yield* Effect56.try({
|
|
4774
4777
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
4775
4778
|
try: () => provisionBaseline(names2)
|
|
4776
4779
|
});
|
|
@@ -4784,13 +4787,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
4784
4787
|
target
|
|
4785
4788
|
}));
|
|
4786
4789
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
4787
|
-
const users = yield*
|
|
4790
|
+
const users = yield* Effect56.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
4788
4791
|
comment: user.comment,
|
|
4789
4792
|
groups: [...user.groups],
|
|
4790
4793
|
target,
|
|
4791
4794
|
userid: user.userid
|
|
4792
4795
|
}))));
|
|
4793
|
-
const grants = yield*
|
|
4796
|
+
const grants = yield* Effect56.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
4794
4797
|
path: "/",
|
|
4795
4798
|
propagate: true,
|
|
4796
4799
|
roleid: grant.roleid,
|
|
@@ -4803,7 +4806,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
|
|
|
4803
4806
|
// src/proxmox/qemu.ts
|
|
4804
4807
|
import { Resource as Resource28 } from "alchemy";
|
|
4805
4808
|
import * as Provider28 from "alchemy/Provider";
|
|
4806
|
-
import * as
|
|
4809
|
+
import * as Effect57 from "effect/Effect";
|
|
4807
4810
|
var ProxmoxVm = Resource28("Proxmox.Vm");
|
|
4808
4811
|
var createForm8 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
|
|
4809
4812
|
var shape9 = (props) => ({
|
|
@@ -4834,11 +4837,11 @@ var handlers20 = pveHandlers({
|
|
|
4834
4837
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
4835
4838
|
updateForm: shape9
|
|
4836
4839
|
});
|
|
4837
|
-
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm,
|
|
4840
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect57.succeed(ProxmoxVm.Provider.of(handlers20)));
|
|
4838
4841
|
// src/proxmox/replication-job.ts
|
|
4839
4842
|
import { Resource as Resource29 } from "alchemy";
|
|
4840
4843
|
import * as Provider29 from "alchemy/Provider";
|
|
4841
|
-
import * as
|
|
4844
|
+
import * as Effect58 from "effect/Effect";
|
|
4842
4845
|
|
|
4843
4846
|
// src/proxmox/replication-job-form.ts
|
|
4844
4847
|
var DEFAULT_SCHEDULE = "*/15";
|
|
@@ -4892,15 +4895,15 @@ var handlers21 = pveHandlers({
|
|
|
4892
4895
|
path: (props) => `cluster/replication/${jobId(props)}`,
|
|
4893
4896
|
updateForm: updateBody5
|
|
4894
4897
|
});
|
|
4895
|
-
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob,
|
|
4898
|
+
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect58.succeed(ProxmoxReplicationJob.Provider.of(handlers21)));
|
|
4896
4899
|
// src/proxmox/sdn-apply.ts
|
|
4897
4900
|
import { Resource as Resource30 } from "alchemy";
|
|
4898
4901
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
4899
4902
|
import * as Provider30 from "alchemy/Provider";
|
|
4900
|
-
import * as
|
|
4903
|
+
import * as Effect60 from "effect/Effect";
|
|
4901
4904
|
|
|
4902
4905
|
// src/proxmox/sdn-apply-read.ts
|
|
4903
|
-
import * as
|
|
4906
|
+
import * as Effect59 from "effect/Effect";
|
|
4904
4907
|
var MARKED = [
|
|
4905
4908
|
"cluster/sdn/zones",
|
|
4906
4909
|
"cluster/sdn/vnets",
|
|
@@ -4909,7 +4912,7 @@ var MARKED = [
|
|
|
4909
4912
|
"cluster/sdn/route-maps"
|
|
4910
4913
|
];
|
|
4911
4914
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
4912
|
-
var markedPending = (target) =>
|
|
4915
|
+
var markedPending = (target) => Effect59.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect59.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect59.catchIf(subsystemAbsent, () => Effect59.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect59.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
4913
4916
|
var fabricStaged = (staged, running) => {
|
|
4914
4917
|
if (staged === undefined && running === undefined)
|
|
4915
4918
|
return 0;
|
|
@@ -4917,9 +4920,9 @@ var fabricStaged = (staged, running) => {
|
|
|
4917
4920
|
return "inconsistent";
|
|
4918
4921
|
return staged === running ? 0 : 1;
|
|
4919
4922
|
};
|
|
4920
|
-
var fabricPending = (target) =>
|
|
4923
|
+
var fabricPending = (target) => Effect59.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect59.map(canonical3), Effect59.catchIf(subsystemAbsent, () => Effect59.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect59.flatMap(([staged, running]) => {
|
|
4921
4924
|
const verdict = fabricStaged(staged, running);
|
|
4922
|
-
return verdict === "inconsistent" ?
|
|
4925
|
+
return verdict === "inconsistent" ? Effect59.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.")) : Effect59.succeed(verdict);
|
|
4923
4926
|
}));
|
|
4924
4927
|
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
4925
4928
|
var sortDeep = (value) => {
|
|
@@ -4932,23 +4935,23 @@ var sortDeep = (value) => {
|
|
|
4932
4935
|
}
|
|
4933
4936
|
return value;
|
|
4934
4937
|
};
|
|
4935
|
-
var sdnPendingCount = (target) =>
|
|
4938
|
+
var sdnPendingCount = (target) => Effect59.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect59.map(([marked, fabric]) => marked + fabric));
|
|
4936
4939
|
|
|
4937
4940
|
// src/proxmox/sdn-apply.ts
|
|
4938
4941
|
var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
|
|
4939
|
-
var read3 = (props) => sdnPendingCount(props.target).pipe(
|
|
4940
|
-
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply,
|
|
4941
|
-
list: () =>
|
|
4942
|
-
read:
|
|
4942
|
+
var read3 = (props) => sdnPendingCount(props.target).pipe(Effect60.map((pending) => ({ pending })));
|
|
4943
|
+
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect60.succeed(ProxmoxSdnApply.Provider.of({
|
|
4944
|
+
list: () => Effect60.succeed([]),
|
|
4945
|
+
read: Effect60.fn(function* ({ olds }) {
|
|
4943
4946
|
return yield* read3(olds);
|
|
4944
4947
|
}),
|
|
4945
|
-
diff:
|
|
4948
|
+
diff: Effect60.fn(function* ({ news }) {
|
|
4946
4949
|
if (!isResolved14(news))
|
|
4947
4950
|
return;
|
|
4948
4951
|
const { pending } = yield* read3(news);
|
|
4949
4952
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
4950
4953
|
}),
|
|
4951
|
-
reconcile:
|
|
4954
|
+
reconcile: Effect60.fn(function* ({ news }) {
|
|
4952
4955
|
const staged = yield* read3(news);
|
|
4953
4956
|
if (staged.pending === 0)
|
|
4954
4957
|
return staged;
|
|
@@ -4956,16 +4959,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect58.
|
|
|
4956
4959
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
4957
4960
|
const after = yield* read3(news);
|
|
4958
4961
|
if (after.pending !== 0) {
|
|
4959
|
-
return yield*
|
|
4962
|
+
return yield* Effect60.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."));
|
|
4960
4963
|
}
|
|
4961
4964
|
return after;
|
|
4962
4965
|
}),
|
|
4963
|
-
delete: () =>
|
|
4966
|
+
delete: () => Effect60.void
|
|
4964
4967
|
})));
|
|
4965
4968
|
// src/proxmox/sdn-subnet.ts
|
|
4966
4969
|
import { Resource as Resource31 } from "alchemy";
|
|
4967
4970
|
import * as Provider31 from "alchemy/Provider";
|
|
4968
|
-
import * as
|
|
4971
|
+
import * as Effect61 from "effect/Effect";
|
|
4969
4972
|
|
|
4970
4973
|
// src/proxmox/sdn-subnet-form.ts
|
|
4971
4974
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -5025,11 +5028,11 @@ var handlers22 = pveHandlers({
|
|
|
5025
5028
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
5026
5029
|
updateForm: updateForm5
|
|
5027
5030
|
});
|
|
5028
|
-
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet,
|
|
5031
|
+
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect61.succeed(ProxmoxSdnSubnet.Provider.of(handlers22)));
|
|
5029
5032
|
// src/proxmox/sdn-vnet.ts
|
|
5030
5033
|
import { Resource as Resource32 } from "alchemy";
|
|
5031
5034
|
import * as Provider32 from "alchemy/Provider";
|
|
5032
|
-
import * as
|
|
5035
|
+
import * as Effect62 from "effect/Effect";
|
|
5033
5036
|
var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
|
|
5034
5037
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
5035
5038
|
var shape11 = (props) => {
|
|
@@ -5067,11 +5070,11 @@ var handlers23 = pveHandlers({
|
|
|
5067
5070
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
5068
5071
|
updateForm: updateForm6
|
|
5069
5072
|
});
|
|
5070
|
-
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet,
|
|
5073
|
+
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect62.succeed(ProxmoxSdnVnet.Provider.of(handlers23)));
|
|
5071
5074
|
// src/proxmox/sdn-zone.ts
|
|
5072
5075
|
import { Resource as Resource33 } from "alchemy";
|
|
5073
5076
|
import * as Provider33 from "alchemy/Provider";
|
|
5074
|
-
import * as
|
|
5077
|
+
import * as Effect63 from "effect/Effect";
|
|
5075
5078
|
var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
|
|
5076
5079
|
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
5077
5080
|
var body6 = (props) => ({
|
|
@@ -5124,67 +5127,126 @@ var handlers24 = pveHandlers({
|
|
|
5124
5127
|
return withClears(fields, clear);
|
|
5125
5128
|
}
|
|
5126
5129
|
});
|
|
5127
|
-
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone,
|
|
5130
|
+
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect63.succeed(ProxmoxSdnZone.Provider.of(handlers24)));
|
|
5128
5131
|
// src/proxmox/storage.ts
|
|
5129
5132
|
import { Resource as Resource34 } from "alchemy";
|
|
5133
|
+
import { isResolved as isResolved15 } from "alchemy/Diff";
|
|
5130
5134
|
import * as Provider34 from "alchemy/Provider";
|
|
5131
|
-
import * as
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
var
|
|
5135
|
+
import * as storage2 from "@distilled.cloud/proxmox/storage";
|
|
5136
|
+
import * as Effect65 from "effect/Effect";
|
|
5137
|
+
|
|
5138
|
+
// src/proxmox/storage-form.ts
|
|
5139
|
+
var STORAGE_CREATE = "pve:POST /storage";
|
|
5140
|
+
var STORAGE_UPDATE = "pve:PUT /storage/{storage}";
|
|
5136
5141
|
var field6 = (name, value) => value === undefined ? {} : { [name]: value };
|
|
5137
5142
|
var locatorForm = (locator) => ({ ...locator });
|
|
5138
|
-
var
|
|
5139
|
-
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
5140
|
-
var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
|
|
5143
|
+
var underscored = (form) => Object.fromEntries(Object.entries(form).map(([key, value]) => [key.replaceAll("-", "_"), value]));
|
|
5141
5144
|
var mutable2 = (props) => ({
|
|
5142
5145
|
...field6("comment", props.comment),
|
|
5143
5146
|
...field6("content", props.content),
|
|
5144
5147
|
...field6("disable", flag(props.disable)),
|
|
5145
|
-
...field6("maxfiles", props.maxfiles === undefined ? undefined : String(props.maxfiles)),
|
|
5146
5148
|
...field6("nodes", props.nodes),
|
|
5147
5149
|
...field6("preallocation", props.preallocation),
|
|
5148
5150
|
...field6("prune-backups", props["prune-backups"]),
|
|
5149
5151
|
...field6("shared", flag(props.shared))
|
|
5150
5152
|
});
|
|
5151
|
-
var
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5153
|
+
var createForm10 = (props) => ({
|
|
5154
|
+
...locatorForm(props.locator),
|
|
5155
|
+
...mutable2(props),
|
|
5156
|
+
storage: props.storage,
|
|
5157
|
+
type: props.type
|
|
5158
|
+
});
|
|
5159
|
+
var updateForm7 = (props) => ({
|
|
5160
|
+
...mutable2(props),
|
|
5161
|
+
storage: props.storage
|
|
5162
|
+
});
|
|
5163
|
+
var toDistilledCreate = (props) => underscored(createForm10(props));
|
|
5164
|
+
var toDistilledUpdate = (props) => underscored(updateForm7(props));
|
|
5165
|
+
|
|
5166
|
+
// src/proxmox/storage-wire.ts
|
|
5167
|
+
import * as storage from "@distilled.cloud/proxmox/storage";
|
|
5168
|
+
import * as Effect64 from "effect/Effect";
|
|
5169
|
+
var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
5170
|
+
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
5171
|
+
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
5172
|
+
var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
|
|
5173
|
+
var attributesOf7 = (live, props) => {
|
|
5174
|
+
const data = live;
|
|
5175
|
+
return {
|
|
5176
|
+
comment: str2(data["comment"]),
|
|
5177
|
+
content: str2(data["content"]),
|
|
5178
|
+
disable: bool(data["disable"]),
|
|
5179
|
+
nodes: str2(data["nodes"]),
|
|
5180
|
+
preallocation: str2(data["preallocation"]),
|
|
5181
|
+
"prune-backups": str2(data["prune-backups"]),
|
|
5182
|
+
shared: bool(data["shared"]),
|
|
5162
5183
|
storage: props.storage,
|
|
5163
|
-
type: str2(
|
|
5184
|
+
type: str2(data["type"], props.type)
|
|
5185
|
+
};
|
|
5186
|
+
};
|
|
5187
|
+
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect64.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf7(live, props)));
|
|
5188
|
+
var readStorage = (props) => readStorageOrFail(props).pipe(Effect64.orElseSucceed(() => {
|
|
5189
|
+
return;
|
|
5190
|
+
}));
|
|
5191
|
+
var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
|
|
5192
|
+
var matches7 = (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment);
|
|
5193
|
+
|
|
5194
|
+
// src/proxmox/storage.ts
|
|
5195
|
+
var ProxmoxStorage = Resource34("Proxmox.Storage", {
|
|
5196
|
+
defaultRemovalPolicy: "retain"
|
|
5197
|
+
});
|
|
5198
|
+
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect65.succeed(ProxmoxStorage.Provider.of({
|
|
5199
|
+
list: () => Effect65.succeed([]),
|
|
5200
|
+
read: Effect65.fn(function* ({ olds, output }) {
|
|
5201
|
+
return dropUnreadable6(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
|
|
5164
5202
|
}),
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5203
|
+
diff: Effect65.fn(function* ({ news, output }) {
|
|
5204
|
+
if (!isResolved15(news))
|
|
5205
|
+
return;
|
|
5206
|
+
yield* guardWrite2(STORAGE_CREATE, createForm10(news), output === undefined);
|
|
5207
|
+
yield* guardWrite2(STORAGE_UPDATE, updateForm7(news), false);
|
|
5208
|
+
if (output === undefined)
|
|
5209
|
+
return;
|
|
5210
|
+
const live = yield* readStorageOrFail(news);
|
|
5211
|
+
if (live === UNREADABLE) {
|
|
5212
|
+
yield* unreadableWarning("Proxmox.Storage", news.storage);
|
|
5213
|
+
return { action: "noop" };
|
|
5214
|
+
}
|
|
5215
|
+
if (live === undefined) {
|
|
5216
|
+
yield* guardWrite2(STORAGE_CREATE, createForm10(news), true);
|
|
5217
|
+
return { action: "update" };
|
|
5218
|
+
}
|
|
5219
|
+
return matches7(live, news) ? { action: "noop" } : { action: "update" };
|
|
5171
5220
|
}),
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5221
|
+
reconcile: Effect65.fn(function* ({ news }) {
|
|
5222
|
+
const before = dropUnreadable6(yield* readStorage(news));
|
|
5223
|
+
yield* guardWrite2(STORAGE_CREATE, createForm10(news), before === undefined);
|
|
5224
|
+
yield* guardWrite2(STORAGE_UPDATE, updateForm7(news), false);
|
|
5225
|
+
if (before === undefined) {
|
|
5226
|
+
yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate(news)));
|
|
5227
|
+
} else if (!matches7(before, news)) {
|
|
5228
|
+
yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate(news)));
|
|
5229
|
+
}
|
|
5230
|
+
const after = dropUnreadable6(yield* readStorage(news));
|
|
5231
|
+
if (after === undefined) {
|
|
5232
|
+
return yield* Effect65.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."));
|
|
5233
|
+
}
|
|
5234
|
+
return after;
|
|
5235
|
+
}),
|
|
5236
|
+
delete: Effect65.fn(function* ({ olds }) {
|
|
5237
|
+
yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
|
|
5238
|
+
})
|
|
5239
|
+
})));
|
|
5178
5240
|
// src/proxmox/zfs-pool.ts
|
|
5179
5241
|
import { Resource as Resource35 } from "alchemy";
|
|
5180
5242
|
import * as Provider35 from "alchemy/Provider";
|
|
5181
|
-
import * as
|
|
5243
|
+
import * as Effect67 from "effect/Effect";
|
|
5182
5244
|
|
|
5183
5245
|
// src/proxmox/zfs-pool-write.ts
|
|
5184
|
-
import * as
|
|
5246
|
+
import * as Effect66 from "effect/Effect";
|
|
5185
5247
|
var ZFS_POOL_ENDPOINT = { create: "pve:POST /nodes/{node}/disks/zfs" };
|
|
5186
5248
|
var zfsPoolEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? {} : ZFS_POOL_ENDPOINT;
|
|
5187
|
-
var
|
|
5249
|
+
var createForm11 = (props) => ({
|
|
5188
5250
|
...props.devices === undefined ? {} : { devices: props.devices.join(",") },
|
|
5189
5251
|
name: props.name,
|
|
5190
5252
|
...props.raidlevel === undefined ? {} : { raidlevel: props.raidlevel },
|
|
@@ -5193,24 +5255,24 @@ var createForm10 = (props) => ({
|
|
|
5193
5255
|
...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
|
|
5194
5256
|
});
|
|
5195
5257
|
var SETTLE_ATTEMPTS = 30;
|
|
5196
|
-
var createPool = (props, collection2, path2, read4) =>
|
|
5258
|
+
var createPool = (props, collection2, path2, read4) => Effect66.gen(function* () {
|
|
5197
5259
|
const existing = yield* read4(props);
|
|
5198
5260
|
if (existing !== undefined)
|
|
5199
5261
|
return existing;
|
|
5200
5262
|
if (props.devices === undefined || props.raidlevel === undefined) {
|
|
5201
|
-
return yield*
|
|
5263
|
+
return yield* Effect66.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."));
|
|
5202
5264
|
}
|
|
5203
|
-
const upid = yield* pve(props.target, "provision", "POST", collection2,
|
|
5204
|
-
const settle4 = (attempts) =>
|
|
5265
|
+
const upid = yield* pve(props.target, "provision", "POST", collection2, createForm11(props));
|
|
5266
|
+
const settle4 = (attempts) => Effect66.gen(function* () {
|
|
5205
5267
|
const live = yield* read4(props);
|
|
5206
5268
|
if (live !== undefined || attempts <= 0)
|
|
5207
5269
|
return live;
|
|
5208
|
-
yield*
|
|
5270
|
+
yield* Effect66.sleep("2 seconds");
|
|
5209
5271
|
return yield* settle4(attempts - 1);
|
|
5210
5272
|
});
|
|
5211
5273
|
const after = yield* settle4(SETTLE_ATTEMPTS);
|
|
5212
5274
|
if (after === undefined) {
|
|
5213
|
-
return yield*
|
|
5275
|
+
return yield* Effect66.die(new Error(`${path2}: 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."));
|
|
5214
5276
|
}
|
|
5215
5277
|
return after;
|
|
5216
5278
|
});
|
|
@@ -5235,7 +5297,7 @@ var spec2 = {
|
|
|
5235
5297
|
};
|
|
5236
5298
|
},
|
|
5237
5299
|
collection: (props) => `nodes/${props.node}/disks/zfs`,
|
|
5238
|
-
createForm:
|
|
5300
|
+
createForm: createForm11,
|
|
5239
5301
|
endpoint: zfsPoolEndpoint,
|
|
5240
5302
|
matches: () => true,
|
|
5241
5303
|
path: (props) => `nodes/${props.node}/disks/zfs/${props.name}`
|
|
@@ -5246,14 +5308,14 @@ var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
|
|
|
5246
5308
|
defaultRemovalPolicy: "retain"
|
|
5247
5309
|
});
|
|
5248
5310
|
var ops3 = pveOperations(spec2);
|
|
5249
|
-
var
|
|
5311
|
+
var handlers25 = {
|
|
5250
5312
|
...pveHandlers(spec2),
|
|
5251
|
-
delete:
|
|
5313
|
+
delete: Effect67.fn(function* ({ olds }) {
|
|
5252
5314
|
yield* destroyPool(olds, spec2.path(olds));
|
|
5253
5315
|
}),
|
|
5254
5316
|
reconcile: ({ news }) => createPool(news, spec2.collection(news), spec2.path(news), ops3.read)
|
|
5255
5317
|
};
|
|
5256
|
-
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool,
|
|
5318
|
+
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect67.succeed(ProxmoxZfsPool.Provider.of(handlers25)));
|
|
5257
5319
|
export {
|
|
5258
5320
|
PROVISION_DEFAULTS,
|
|
5259
5321
|
PROVISION_PRIVILEGES,
|
|
@@ -5330,5 +5392,5 @@ export {
|
|
|
5330
5392
|
violations
|
|
5331
5393
|
};
|
|
5332
5394
|
|
|
5333
|
-
//# debugId=
|
|
5395
|
+
//# debugId=1F128D1971E713E364756E2164756E21
|
|
5334
5396
|
//# sourceMappingURL=index.js.map
|