@homeflare/alchemy 0.12.0 → 0.14.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 +7 -0
- package/dist/github/index.d.ts +18 -0
- package/dist/github/index.d.ts.map +1 -0
- package/dist/github/index.js +161 -0
- package/dist/github/index.js.map +12 -0
- package/dist/github/repo-policy-form.d.ts +86 -0
- package/dist/github/repo-policy-form.d.ts.map +1 -0
- package/dist/github/repo-policy-guards.d.ts +72 -0
- package/dist/github/repo-policy-guards.d.ts.map +1 -0
- package/dist/github/repo-policy.d.ts +21 -0
- package/dist/github/repo-policy.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/proxmox/alertmanager-body.d.ts +54 -0
- package/dist/proxmox/alertmanager-body.d.ts.map +1 -0
- package/dist/proxmox/credential-literals.d.ts +36 -0
- package/dist/proxmox/credential-literals.d.ts.map +1 -0
- package/dist/proxmox/fake-pbs-notify.d.ts +23 -0
- package/dist/proxmox/fake-pbs-notify.d.ts.map +1 -0
- package/dist/proxmox/fake-pve.d.ts +5 -0
- package/dist/proxmox/fake-pve.d.ts.map +1 -1
- package/dist/proxmox/generated/pbs.d.ts +278 -0
- package/dist/proxmox/generated/pbs.d.ts.map +1 -1
- package/dist/proxmox/generated/pve.d.ts +57 -0
- package/dist/proxmox/generated/pve.d.ts.map +1 -1
- package/dist/proxmox/index.d.ts +8 -0
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +681 -183
- package/dist/proxmox/index.js.map +14 -4
- package/dist/proxmox/notification-matcher-form.d.ts +100 -0
- package/dist/proxmox/notification-matcher-form.d.ts.map +1 -0
- package/dist/proxmox/notification-matcher.d.ts +46 -0
- package/dist/proxmox/notification-matcher.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-matcher.d.ts +53 -0
- package/dist/proxmox/pbs-notification-matcher.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-target-form.d.ts +63 -0
- package/dist/proxmox/pbs-notification-target-form.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-target-lifecycle.d.ts +100 -0
- package/dist/proxmox/pbs-notification-target-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-target-wire.d.ts +30 -0
- package/dist/proxmox/pbs-notification-target-wire.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-target.d.ts +123 -0
- package/dist/proxmox/pbs-notification-target.d.ts.map +1 -0
- package/dist/proxmox/resource.d.ts +4 -3
- package/dist/proxmox/resource.d.ts.map +1 -1
- package/dist/proxmox/write-only.d.ts +35 -0
- package/dist/proxmox/write-only.d.ts.map +1 -0
- package/dist/verify/fake-engine.d.ts +5 -0
- package/dist/verify/fake-engine.d.ts.map +1 -1
- package/docs/adopted-deploys.md +8 -0
- package/docs/pbs-alertmanager-body.md +73 -0
- package/docs/pbs-notifications.md +163 -0
- package/docs/proxmox.md +3 -0
- package/docs/repo-policy-ruleset-hazards.md +65 -0
- package/docs/repo-policy.md +155 -0
- package/package.json +5 -1
- package/src/github/index.ts +23 -0
- package/src/github/repo-policy-form.test.ts +239 -0
- package/src/github/repo-policy-form.ts +173 -0
- package/src/github/repo-policy-guards.ts +179 -0
- package/src/github/repo-policy.test.ts +58 -0
- package/src/github/repo-policy.ts +65 -0
- package/src/index.ts +1 -0
- package/src/proxmox/alertmanager-body.ts +125 -0
- package/src/proxmox/credential-literals.test.ts +148 -0
- package/src/proxmox/credential-literals.ts +74 -0
- package/src/proxmox/fake-pbs-notify.ts +108 -0
- package/src/proxmox/fake-pve.ts +12 -2
- package/src/proxmox/generated/pbs.ts +329 -0
- package/src/proxmox/generated/pve.ts +62 -0
- package/src/proxmox/index.test.ts +3 -0
- package/src/proxmox/index.ts +18 -0
- package/src/proxmox/notification-matcher-form.ts +221 -0
- package/src/proxmox/notification-matcher.test.ts +234 -0
- package/src/proxmox/notification-matcher.ts +76 -0
- package/src/proxmox/pbs-notification-matcher.ts +81 -0
- package/src/proxmox/pbs-notification-target-drift.test.ts +83 -0
- package/src/proxmox/pbs-notification-target-form.ts +229 -0
- package/src/proxmox/pbs-notification-target-lifecycle.ts +177 -0
- package/src/proxmox/pbs-notification-target-state.test.ts +191 -0
- package/src/proxmox/pbs-notification-target-wire.ts +112 -0
- package/src/proxmox/pbs-notification-target.test.ts +226 -0
- package/src/proxmox/pbs-notification-target.ts +139 -0
- package/src/proxmox/pbs-notifications-stack.test.ts +94 -0
- package/src/proxmox/resource.ts +6 -6
- package/src/proxmox/write-only.test.ts +75 -0
- package/src/proxmox/write-only.ts +106 -0
- package/src/verify/fake-engine.ts +8 -1
package/dist/proxmox/index.js
CHANGED
|
@@ -230,7 +230,7 @@ var formToSend = (matches, live, props, form) => matches(live, props) || Object.
|
|
|
230
230
|
|
|
231
231
|
// src/proxmox/resource.ts
|
|
232
232
|
var pveOperations = (spec) => {
|
|
233
|
-
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect5.map((data) => data
|
|
233
|
+
const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect5.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect5.orElseSucceed(() => {
|
|
234
234
|
return;
|
|
235
235
|
}));
|
|
236
236
|
return {
|
|
@@ -336,6 +336,56 @@ var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl, Effect6.succeed(Proxm
|
|
|
336
336
|
yield* pve(olds.target, "provision", "PUT", "access/acl", removal);
|
|
337
337
|
})
|
|
338
338
|
})));
|
|
339
|
+
// src/proxmox/alertmanager-body.ts
|
|
340
|
+
var literal = (label, value) => {
|
|
341
|
+
if (/[{}\\]/.test(value) || value === "") {
|
|
342
|
+
throw new Error(`alertmanagerAlertBody: ${label} must be non-empty and hold no '{', '}' or '\\'`);
|
|
343
|
+
}
|
|
344
|
+
return JSON.stringify(value);
|
|
345
|
+
};
|
|
346
|
+
var absoluteUrl = (value) => {
|
|
347
|
+
const text = literal("generatorURL", value);
|
|
348
|
+
let protocol = "";
|
|
349
|
+
try {
|
|
350
|
+
protocol = new URL(value).protocol;
|
|
351
|
+
} catch {}
|
|
352
|
+
if (protocol !== "https:" && protocol !== "http:") {
|
|
353
|
+
throw new Error("alertmanagerAlertBody: generatorURL must be an absolute http(s) URL");
|
|
354
|
+
}
|
|
355
|
+
return text;
|
|
356
|
+
};
|
|
357
|
+
var FIELD_LABELS = [
|
|
358
|
+
["job_type", "type"],
|
|
359
|
+
["job_id", "job-id"],
|
|
360
|
+
["datastore", "datastore"],
|
|
361
|
+
["hostname", "hostname"]
|
|
362
|
+
];
|
|
363
|
+
var alertmanagerAlertBody = (options = {}) => {
|
|
364
|
+
const alertname = literal("alertname", options.alertname ?? "PbsNotification");
|
|
365
|
+
const source = literal("source", options.source ?? "pbs");
|
|
366
|
+
const labels = FIELD_LABELS.map(([label, field]) => ` {{#if fields.${field}}}"${label}": {{ json fields.${field} }},{{/if}}`);
|
|
367
|
+
const link = options.generatorURL === undefined ? "" : `,
|
|
368
|
+
"generatorURL": ${absoluteUrl(options.generatorURL)}`;
|
|
369
|
+
return [
|
|
370
|
+
"[",
|
|
371
|
+
" {",
|
|
372
|
+
' "labels": {',
|
|
373
|
+
...labels,
|
|
374
|
+
' "severity": {{ json severity }},',
|
|
375
|
+
` "alertname": ${alertname},`,
|
|
376
|
+
` "source": ${source}`,
|
|
377
|
+
" },",
|
|
378
|
+
' "annotations": {',
|
|
379
|
+
' "summary": {{ json title }},',
|
|
380
|
+
' "description": {{ json message }},',
|
|
381
|
+
' "timestamp": "{{ timestamp }}"',
|
|
382
|
+
` }${link}`,
|
|
383
|
+
" }",
|
|
384
|
+
"]",
|
|
385
|
+
""
|
|
386
|
+
].join(`
|
|
387
|
+
`);
|
|
388
|
+
};
|
|
339
389
|
// src/proxmox/api-token.ts
|
|
340
390
|
import { Resource as Resource2 } from "alchemy";
|
|
341
391
|
import * as Provider2 from "alchemy/Provider";
|
|
@@ -2184,11 +2234,101 @@ var handlers13 = pveHandlers({
|
|
|
2184
2234
|
updateForm: updateBody2
|
|
2185
2235
|
});
|
|
2186
2236
|
var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect34.succeed(ProxmoxNodeNetwork.Provider.of(handlers13)));
|
|
2187
|
-
// src/proxmox/notification-
|
|
2237
|
+
// src/proxmox/notification-matcher.ts
|
|
2188
2238
|
import { Resource as Resource17 } from "alchemy";
|
|
2189
2239
|
import * as Provider17 from "alchemy/Provider";
|
|
2190
2240
|
import * as Effect35 from "effect/Effect";
|
|
2191
2241
|
|
|
2242
|
+
// src/proxmox/notification-matcher-form.ts
|
|
2243
|
+
var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
2244
|
+
var items = (values, canonical) => values.map((item) => canonical(item.trim())).filter((item) => item !== "");
|
|
2245
|
+
var severity = (item) => item.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
2246
|
+
var field4 = (item) => {
|
|
2247
|
+
if (!item.startsWith("exact:"))
|
|
2248
|
+
return item;
|
|
2249
|
+
const at = item.indexOf("=");
|
|
2250
|
+
if (at < 0)
|
|
2251
|
+
return item;
|
|
2252
|
+
const values = item.slice(at + 1).split(",");
|
|
2253
|
+
return `${item.slice(0, at)}=${values.map((value) => value.trim()).join(",")}`;
|
|
2254
|
+
};
|
|
2255
|
+
var same3 = (item) => item;
|
|
2256
|
+
var canonicalRules = (fields) => ({
|
|
2257
|
+
"match-calendar": items(fields["match-calendar"] ?? [], same3).sort(),
|
|
2258
|
+
"match-field": items(fields["match-field"] ?? [], field4).sort(),
|
|
2259
|
+
"match-severity": items(fields["match-severity"] ?? [], severity).sort(),
|
|
2260
|
+
targets: items(fields.targets, same3).sort()
|
|
2261
|
+
});
|
|
2262
|
+
var matcherAttributes = (live, name) => ({
|
|
2263
|
+
comment: text(live["comment"]),
|
|
2264
|
+
disable: bool(live["disable"]),
|
|
2265
|
+
"invert-match": bool(live["invert-match"]),
|
|
2266
|
+
"match-calendar": items(list(live["match-calendar"]), same3).sort(),
|
|
2267
|
+
"match-field": items(list(live["match-field"]), field4).sort(),
|
|
2268
|
+
"match-severity": items(list(live["match-severity"]), severity).sort(),
|
|
2269
|
+
mode: text(live["mode"], "all") || "all",
|
|
2270
|
+
name,
|
|
2271
|
+
origin: text(live["origin"]),
|
|
2272
|
+
targets: items(list(live["target"]), same3).sort()
|
|
2273
|
+
});
|
|
2274
|
+
var equal = (a, b) => a.length === b.length && a.every((item, index) => item === b[index]);
|
|
2275
|
+
var matcherMatches = (attributes, fields) => {
|
|
2276
|
+
const rules = canonicalRules(fields);
|
|
2277
|
+
return attributes.disable === (fields.disable === true) && attributes["invert-match"] === (fields["invert-match"] === true) && attributes.mode === (fields.mode ?? "all") && equal(attributes.targets, rules.targets) && equal(attributes["match-severity"], rules["match-severity"]) && equal(attributes["match-field"], rules["match-field"]) && equal(attributes["match-calendar"], rules["match-calendar"]) && (fields.comment === undefined || attributes.comment === fields.comment);
|
|
2278
|
+
};
|
|
2279
|
+
var always = (fields) => ({
|
|
2280
|
+
disable: fields.disable === true ? "1" : "0",
|
|
2281
|
+
"invert-match": fields["invert-match"] === true ? "1" : "0",
|
|
2282
|
+
mode: fields.mode ?? "all"
|
|
2283
|
+
});
|
|
2284
|
+
var lists = (fields) => {
|
|
2285
|
+
const rules = canonicalRules(fields);
|
|
2286
|
+
const out = {};
|
|
2287
|
+
if (rules["match-calendar"].length > 0)
|
|
2288
|
+
out["match-calendar"] = rules["match-calendar"];
|
|
2289
|
+
if (rules["match-field"].length > 0)
|
|
2290
|
+
out["match-field"] = rules["match-field"];
|
|
2291
|
+
if (rules["match-severity"].length > 0)
|
|
2292
|
+
out["match-severity"] = rules["match-severity"];
|
|
2293
|
+
if (rules.targets.length > 0)
|
|
2294
|
+
out.target = rules.targets;
|
|
2295
|
+
return out;
|
|
2296
|
+
};
|
|
2297
|
+
var matcherCreateForm = (fields) => ({
|
|
2298
|
+
...always(fields),
|
|
2299
|
+
...lists(fields),
|
|
2300
|
+
...fields.comment === undefined || fields.comment === "" ? {} : { comment: fields.comment },
|
|
2301
|
+
name: fields.name
|
|
2302
|
+
});
|
|
2303
|
+
var matcherUpdateForm = (fields) => {
|
|
2304
|
+
const present = lists(fields);
|
|
2305
|
+
const cleared = ["match-calendar", "match-field", "match-severity", "target"].filter((key) => present[key] === undefined);
|
|
2306
|
+
if (fields.comment === "")
|
|
2307
|
+
cleared.push("comment");
|
|
2308
|
+
return {
|
|
2309
|
+
...always(fields),
|
|
2310
|
+
...present,
|
|
2311
|
+
...fields.comment === undefined || fields.comment === "" ? {} : { comment: fields.comment },
|
|
2312
|
+
...cleared.length === 0 ? {} : { delete: cleared }
|
|
2313
|
+
};
|
|
2314
|
+
};
|
|
2315
|
+
|
|
2316
|
+
// src/proxmox/notification-matcher.ts
|
|
2317
|
+
var ProxmoxNotificationMatcher = Resource17("Proxmox.NotificationMatcher");
|
|
2318
|
+
var handlers14 = pveHandlers({
|
|
2319
|
+
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
2320
|
+
collection: () => "cluster/notifications/matchers",
|
|
2321
|
+
createForm: matcherCreateForm,
|
|
2322
|
+
matches: matcherMatches,
|
|
2323
|
+
path: (props) => `cluster/notifications/matchers/${props.name}`,
|
|
2324
|
+
updateForm: matcherUpdateForm
|
|
2325
|
+
});
|
|
2326
|
+
var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect35.succeed(ProxmoxNotificationMatcher.Provider.of(handlers14)));
|
|
2327
|
+
// src/proxmox/notification-target.ts
|
|
2328
|
+
import { Resource as Resource18 } from "alchemy";
|
|
2329
|
+
import * as Provider18 from "alchemy/Provider";
|
|
2330
|
+
import * as Effect36 from "effect/Effect";
|
|
2331
|
+
|
|
2192
2332
|
// src/proxmox/notification-target-form.ts
|
|
2193
2333
|
var REPEATED_KEY = "\x00";
|
|
2194
2334
|
var portOf = (value) => {
|
|
@@ -2217,8 +2357,8 @@ var shape4 = (props) => ({
|
|
|
2217
2357
|
});
|
|
2218
2358
|
|
|
2219
2359
|
// src/proxmox/notification-target.ts
|
|
2220
|
-
var ProxmoxNotificationTarget =
|
|
2221
|
-
var
|
|
2360
|
+
var ProxmoxNotificationTarget = Resource18("Proxmox.NotificationTarget");
|
|
2361
|
+
var handlers15 = pveHandlers({
|
|
2222
2362
|
attributes: (live, props) => ({
|
|
2223
2363
|
author: text(live["author"]),
|
|
2224
2364
|
body: text(live["body"]),
|
|
@@ -2243,15 +2383,15 @@ var handlers14 = pveHandlers({
|
|
|
2243
2383
|
path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
|
|
2244
2384
|
updateForm: shape4
|
|
2245
2385
|
});
|
|
2246
|
-
var ProxmoxNotificationTargetProvider = () =>
|
|
2386
|
+
var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect36.succeed(ProxmoxNotificationTarget.Provider.of(handlers15)));
|
|
2247
2387
|
// src/proxmox/pbs-datastore.ts
|
|
2248
|
-
import { Resource as
|
|
2388
|
+
import { Resource as Resource19 } from "alchemy";
|
|
2249
2389
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2250
|
-
import * as
|
|
2251
|
-
import * as
|
|
2390
|
+
import * as Provider19 from "alchemy/Provider";
|
|
2391
|
+
import * as Effect39 from "effect/Effect";
|
|
2252
2392
|
|
|
2253
2393
|
// src/proxmox/pbs-datastore-form.ts
|
|
2254
|
-
import * as
|
|
2394
|
+
import * as Effect37 from "effect/Effect";
|
|
2255
2395
|
var attributes = (live, props) => ({
|
|
2256
2396
|
backend: propertyString(live["backend"]),
|
|
2257
2397
|
comment: text(live["comment"]),
|
|
@@ -2273,8 +2413,8 @@ var attributes = (live, props) => ({
|
|
|
2273
2413
|
tuning: propertyString(live["tuning"]),
|
|
2274
2414
|
"verify-new": bool(live["verify-new"])
|
|
2275
2415
|
});
|
|
2276
|
-
var
|
|
2277
|
-
var matches = (live, props) =>
|
|
2416
|
+
var same4 = (declared, live) => declared === undefined || declared === live;
|
|
2417
|
+
var matches = (live, props) => same4(props.comment, live.comment) && same4(props["gc-schedule"]?.trim(), live["gc-schedule"]) && same4(props["prune-schedule"]?.trim(), live["prune-schedule"]) && same4(props["keep-last"], live["keep-last"]) && same4(props["keep-hourly"], live["keep-hourly"]) && same4(props["keep-daily"], live["keep-daily"]) && same4(props["keep-weekly"], live["keep-weekly"]) && same4(props["keep-monthly"], live["keep-monthly"]) && same4(props["keep-yearly"], live["keep-yearly"]) && same4(props["notify-user"], live["notify-user"]) && same4(props["counter-reset-schedule"]?.trim(), live["counter-reset-schedule"]) && (props["notification-thresholds"] === undefined || propertyString(props["notification-thresholds"]) === live["notification-thresholds"]) && same4(props["verify-new"], live["verify-new"]) && (props.notify === undefined || propertyString(props.notify) === live.notify) && (props.tuning === undefined || propertyString(props.tuning) === live.tuning) && (props["maintenance-mode"] === undefined || propertyString(props["maintenance-mode"], "type") === live["maintenance-mode"]);
|
|
2278
2418
|
var set2 = (key, value) => value === undefined ? {} : { [key]: value };
|
|
2279
2419
|
var count = (value) => value === undefined ? undefined : String(value);
|
|
2280
2420
|
var mutable = (props) => ({
|
|
@@ -2303,36 +2443,36 @@ var createForm4 = (props) => ({
|
|
|
2303
2443
|
});
|
|
2304
2444
|
var updateForm = (props) => mutable(props);
|
|
2305
2445
|
var object2 = (props) => `config/datastore/${props.name}`;
|
|
2306
|
-
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(
|
|
2446
|
+
var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect37.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect37.orElseSucceed(() => {
|
|
2307
2447
|
return;
|
|
2308
2448
|
}));
|
|
2309
2449
|
|
|
2310
2450
|
// src/proxmox/pbs-datastore-guard.ts
|
|
2311
|
-
import * as
|
|
2451
|
+
import * as Effect38 from "effect/Effect";
|
|
2312
2452
|
var samePath = (left, right) => {
|
|
2313
2453
|
const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
|
|
2314
2454
|
return trim(left) === trim(right);
|
|
2315
2455
|
};
|
|
2316
|
-
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ?
|
|
2317
|
-
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ?
|
|
2318
|
-
var settle3 = (read3, done) =>
|
|
2456
|
+
var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect38.void : Effect38.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."));
|
|
2457
|
+
var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect38.void : Effect38.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."));
|
|
2458
|
+
var settle3 = (read3, done) => Effect38.gen(function* () {
|
|
2319
2459
|
for (let attempt = 0;attempt < 60; attempt += 1) {
|
|
2320
2460
|
const live = yield* read3;
|
|
2321
2461
|
if (done(live))
|
|
2322
2462
|
return live;
|
|
2323
|
-
yield*
|
|
2463
|
+
yield* Effect38.sleep("2 seconds");
|
|
2324
2464
|
}
|
|
2325
2465
|
return yield* read3;
|
|
2326
2466
|
});
|
|
2327
2467
|
|
|
2328
2468
|
// src/proxmox/pbs-datastore.ts
|
|
2329
|
-
var PbsDatastore =
|
|
2469
|
+
var PbsDatastore = Resource19("Pbs.Datastore", {
|
|
2330
2470
|
defaultRemovalPolicy: "retain"
|
|
2331
2471
|
});
|
|
2332
|
-
var PbsDatastoreProvider = () =>
|
|
2333
|
-
list: () =>
|
|
2472
|
+
var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect39.succeed(PbsDatastore.Provider.of({
|
|
2473
|
+
list: () => Effect39.succeed([]),
|
|
2334
2474
|
read: ({ olds }) => readOne(olds),
|
|
2335
|
-
diff: ({ news, output }) =>
|
|
2475
|
+
diff: ({ news, output }) => Effect39.gen(function* () {
|
|
2336
2476
|
if (output === undefined || !isResolved8(news))
|
|
2337
2477
|
return;
|
|
2338
2478
|
const live = yield* readOne(news);
|
|
@@ -2342,7 +2482,7 @@ var PbsDatastoreProvider = () => Provider18.effect(PbsDatastore, Effect38.succee
|
|
|
2342
2482
|
yield* guardBackend(live, news);
|
|
2343
2483
|
return matches(live, news) ? { action: "noop" } : { action: "update" };
|
|
2344
2484
|
}),
|
|
2345
|
-
reconcile:
|
|
2485
|
+
reconcile: Effect39.fn(function* ({ news }) {
|
|
2346
2486
|
const live = yield* readOne(news);
|
|
2347
2487
|
let upid;
|
|
2348
2488
|
if (live === undefined) {
|
|
@@ -2357,22 +2497,373 @@ var PbsDatastoreProvider = () => Provider18.effect(PbsDatastore, Effect38.succee
|
|
|
2357
2497
|
}
|
|
2358
2498
|
const after = yield* settle3(readOne(news), (row) => row !== undefined && matches(row, news));
|
|
2359
2499
|
if (after === undefined || !matches(after, news)) {
|
|
2360
|
-
return yield*
|
|
2500
|
+
return yield* Effect39.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."));
|
|
2361
2501
|
}
|
|
2362
2502
|
return after;
|
|
2363
2503
|
}),
|
|
2364
|
-
delete:
|
|
2504
|
+
delete: Effect39.fn(function* ({ olds }) {
|
|
2365
2505
|
yield* pve(olds.target, "provision", "DELETE", object2(olds));
|
|
2366
2506
|
const left = yield* settle3(readOne(olds), (row) => row === undefined);
|
|
2367
2507
|
if (left !== undefined) {
|
|
2368
|
-
return yield*
|
|
2508
|
+
return yield* Effect39.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>\`.`));
|
|
2369
2509
|
}
|
|
2370
2510
|
})
|
|
2371
2511
|
})));
|
|
2512
|
+
// src/proxmox/pbs-notification-matcher.ts
|
|
2513
|
+
import { Resource as Resource20 } from "alchemy";
|
|
2514
|
+
import * as Provider20 from "alchemy/Provider";
|
|
2515
|
+
import * as Effect40 from "effect/Effect";
|
|
2516
|
+
var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
|
|
2517
|
+
var handlers16 = pveHandlers({
|
|
2518
|
+
attributes: (live, props) => matcherAttributes(live, props.name),
|
|
2519
|
+
collection: () => "config/notifications/matchers",
|
|
2520
|
+
createForm: matcherCreateForm,
|
|
2521
|
+
matches: matcherMatches,
|
|
2522
|
+
path: (props) => `config/notifications/matchers/${props.name}`,
|
|
2523
|
+
updateForm: matcherUpdateForm
|
|
2524
|
+
});
|
|
2525
|
+
var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect40.succeed(PbsNotificationMatcher.Provider.of(handlers16)));
|
|
2526
|
+
// src/proxmox/pbs-notification-target.ts
|
|
2527
|
+
import { Resource as Resource21 } from "alchemy";
|
|
2528
|
+
import * as Provider21 from "alchemy/Provider";
|
|
2529
|
+
import * as Effect42 from "effect/Effect";
|
|
2530
|
+
|
|
2531
|
+
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
2532
|
+
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2533
|
+
import * as Effect41 from "effect/Effect";
|
|
2534
|
+
|
|
2535
|
+
// src/proxmox/credential-literals.ts
|
|
2536
|
+
var READS_SECRET = /\{\{[^}]*\bsecrets\./;
|
|
2537
|
+
var CREDENTIAL_WORD = /(^|[-_])(api[-_]?key|apikey|key|token|secret|password|passwd|pwd|pass|auth|signature|sig|code)($|[-_])/i;
|
|
2538
|
+
var CREDENTIAL_HEADER = /^(proxy-authorization|authorization|cookie)$/i;
|
|
2539
|
+
var isCredentialName = (name) => CREDENTIAL_HEADER.test(name) || CREDENTIAL_WORD.test(name);
|
|
2540
|
+
var literal2 = (value) => value !== "" && !READS_SECRET.test(value);
|
|
2541
|
+
var literalCredentialHeaders = (header) => Object.entries(header ?? {}).filter(([name, value]) => typeof value === "string" && isCredentialName(name)).filter(([, value]) => literal2(value)).map(([name]) => name).sort();
|
|
2542
|
+
var literalCredentialsInUrl = (url) => {
|
|
2543
|
+
if (url === undefined)
|
|
2544
|
+
return [];
|
|
2545
|
+
const out = [];
|
|
2546
|
+
const authority = /^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i.exec(url)?.[1] ?? "";
|
|
2547
|
+
const at = authority.lastIndexOf("@");
|
|
2548
|
+
if (at >= 0) {
|
|
2549
|
+
const userinfo = authority.slice(0, at);
|
|
2550
|
+
const colon = userinfo.indexOf(":");
|
|
2551
|
+
if (colon >= 0 && literal2(userinfo.slice(colon + 1)))
|
|
2552
|
+
out.push("userinfo");
|
|
2553
|
+
}
|
|
2554
|
+
const params = url.replace(/^[^?#]*/, "");
|
|
2555
|
+
for (const pair of params.split(/[?&#]/)) {
|
|
2556
|
+
const eq = pair.indexOf("=");
|
|
2557
|
+
const name = eq < 0 ? pair : pair.slice(0, eq);
|
|
2558
|
+
if (eq >= 0 && isCredentialName(name) && literal2(pair.slice(eq + 1)))
|
|
2559
|
+
out.push(`?${name}`);
|
|
2560
|
+
}
|
|
2561
|
+
return out;
|
|
2562
|
+
};
|
|
2563
|
+
|
|
2564
|
+
// src/proxmox/pbs-notification-target-wire.ts
|
|
2565
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
2566
|
+
|
|
2567
|
+
// src/proxmox/write-only.ts
|
|
2568
|
+
import { Buffer } from "node:buffer";
|
|
2569
|
+
import { randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
|
|
2570
|
+
var resolveAll = (refs, env = process.env) => {
|
|
2571
|
+
const values = {};
|
|
2572
|
+
const missing = [];
|
|
2573
|
+
for (const [key, ref] of Object.entries(refs)) {
|
|
2574
|
+
const value = env[ref.fromEnv];
|
|
2575
|
+
if (value === undefined || value === "")
|
|
2576
|
+
missing.push(ref.fromEnv);
|
|
2577
|
+
else
|
|
2578
|
+
values[key] = value;
|
|
2579
|
+
}
|
|
2580
|
+
return { missing: [...new Set(missing)].sort(), values };
|
|
2581
|
+
};
|
|
2582
|
+
var COST = { N: 16384, maxmem: 64 * 1024 * 1024, p: 1, r: 8 };
|
|
2583
|
+
var PREFIX = "scrypt";
|
|
2584
|
+
var canonical = (values) => JSON.stringify(Object.keys(values).sort().map((key) => [key, values[key]]));
|
|
2585
|
+
var digest = (salt, values) => scryptSync(canonical(values), salt, 32, COST);
|
|
2586
|
+
var seal = (values, salt) => {
|
|
2587
|
+
if (Object.keys(values).length === 0)
|
|
2588
|
+
return "";
|
|
2589
|
+
const bytes = salt === undefined ? randomBytes(16) : Buffer.from(salt, "utf8");
|
|
2590
|
+
return `${PREFIX}:${bytes.toString("base64url")}:${digest(bytes, values).toString("base64url")}`;
|
|
2591
|
+
};
|
|
2592
|
+
var sealMatches = (sealed, values) => {
|
|
2593
|
+
if (sealed === "")
|
|
2594
|
+
return Object.keys(values).length === 0;
|
|
2595
|
+
const [prefix, salt, stored, extra] = sealed.split(":");
|
|
2596
|
+
if (prefix !== PREFIX || salt === undefined || stored === undefined || extra !== undefined) {
|
|
2597
|
+
return false;
|
|
2598
|
+
}
|
|
2599
|
+
const expected = Buffer.from(stored, "base64url");
|
|
2600
|
+
const actual = digest(Buffer.from(salt, "base64url"), values);
|
|
2601
|
+
return expected.length === actual.length && timingSafeEqual(expected, actual);
|
|
2602
|
+
};
|
|
2603
|
+
|
|
2604
|
+
// src/proxmox/pbs-notification-target-wire.ts
|
|
2605
|
+
var base64 = (value) => Buffer2.from(value, "utf8").toString("base64");
|
|
2606
|
+
var unbase64 = (value) => Buffer2.from(value, "base64").toString("utf8");
|
|
2607
|
+
var keyAndValue = (item) => {
|
|
2608
|
+
const parts = {};
|
|
2609
|
+
for (const part of item.split(",")) {
|
|
2610
|
+
const at = part.indexOf("=");
|
|
2611
|
+
if (at > 0)
|
|
2612
|
+
parts[part.slice(0, at).trim()] = part.slice(at + 1).trim();
|
|
2613
|
+
}
|
|
2614
|
+
const value = parts["value"];
|
|
2615
|
+
return value === undefined ? { name: parts["name"] ?? "" } : { name: parts["name"] ?? "", value };
|
|
2616
|
+
};
|
|
2617
|
+
var wireItem = (name, value) => `name=${name},value=${base64(value)}`;
|
|
2618
|
+
var list2 = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
|
|
2619
|
+
var names = (keys) => [...keys].filter((key) => key !== "").sort().join(",");
|
|
2620
|
+
var headerDigest = (target, pairs2) => seal(pairs2, `hf:pbs-notification-target:${target}:header`);
|
|
2621
|
+
var targetAttributes = (live, props) => {
|
|
2622
|
+
const headers = {};
|
|
2623
|
+
for (const item of list2(live["header"])) {
|
|
2624
|
+
const { name, value } = keyAndValue(item);
|
|
2625
|
+
if (name !== "")
|
|
2626
|
+
headers[name] = unbase64(value ?? "");
|
|
2627
|
+
}
|
|
2628
|
+
const secrets = list2(live["secret"]).map((item) => keyAndValue(item).name);
|
|
2629
|
+
return {
|
|
2630
|
+
author: text(live["author"]),
|
|
2631
|
+
body: unbase64(text(live["body"])),
|
|
2632
|
+
comment: text(live["comment"]),
|
|
2633
|
+
disable: bool(live["disable"]),
|
|
2634
|
+
"from-address": text(live["from-address"]),
|
|
2635
|
+
header: names(Object.keys(headers)),
|
|
2636
|
+
headerDigest: headerDigest(props.name, headers),
|
|
2637
|
+
mailto: addressList(live["mailto"]),
|
|
2638
|
+
"mailto-user": addressList(live["mailto-user"]),
|
|
2639
|
+
method: text(live["method"]),
|
|
2640
|
+
mode: text(live["mode"]),
|
|
2641
|
+
name: props.name,
|
|
2642
|
+
origin: text(live["origin"]),
|
|
2643
|
+
port: portOf(live["port"]),
|
|
2644
|
+
secret: names(secrets),
|
|
2645
|
+
sealed: "",
|
|
2646
|
+
server: text(live["server"]),
|
|
2647
|
+
type: props.type,
|
|
2648
|
+
url: text(live["url"]),
|
|
2649
|
+
username: text(live["username"])
|
|
2650
|
+
};
|
|
2651
|
+
};
|
|
2652
|
+
|
|
2653
|
+
// src/proxmox/pbs-notification-target-form.ts
|
|
2654
|
+
var OWNED = {
|
|
2655
|
+
author: ["sendmail", "smtp"],
|
|
2656
|
+
body: ["webhook"],
|
|
2657
|
+
"from-address": ["sendmail", "smtp"],
|
|
2658
|
+
header: ["webhook"],
|
|
2659
|
+
mailto: ["sendmail", "smtp"],
|
|
2660
|
+
"mailto-user": ["sendmail", "smtp"],
|
|
2661
|
+
method: ["webhook"],
|
|
2662
|
+
mode: ["smtp"],
|
|
2663
|
+
password: ["smtp"],
|
|
2664
|
+
port: ["smtp"],
|
|
2665
|
+
secret: ["webhook"],
|
|
2666
|
+
server: ["smtp"],
|
|
2667
|
+
url: ["webhook"],
|
|
2668
|
+
username: ["smtp"]
|
|
2669
|
+
};
|
|
2670
|
+
var REQUIRED = {
|
|
2671
|
+
sendmail: [],
|
|
2672
|
+
smtp: ["server", "from-address"],
|
|
2673
|
+
webhook: ["url", "method"]
|
|
2674
|
+
};
|
|
2675
|
+
var CLEAN_NAME = /^[^,=\s]+$/;
|
|
2676
|
+
var WRITE_ONLY = "declare it { fromEnv: 'NAME' }, or keep it in 'secret' and write {{ secrets.<name> }}";
|
|
2677
|
+
var refusals = (props) => {
|
|
2678
|
+
const out = [];
|
|
2679
|
+
for (const [field5, types] of Object.entries(OWNED)) {
|
|
2680
|
+
if (props[field5] !== undefined && !types.includes(props.type)) {
|
|
2681
|
+
out.push(`'${field5}' belongs to ${types.join("/")} targets, not ${props.type}`);
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
for (const field5 of REQUIRED[props.type]) {
|
|
2685
|
+
if (props[field5] === undefined || props[field5] === "")
|
|
2686
|
+
out.push(`${props.type} needs '${field5}'`);
|
|
2687
|
+
}
|
|
2688
|
+
for (const key of [...Object.keys(props.header ?? {}), ...Object.keys(props.secret ?? {})]) {
|
|
2689
|
+
if (!CLEAN_NAME.test(key))
|
|
2690
|
+
out.push(`'${key}' cannot be a header or secret name`);
|
|
2691
|
+
}
|
|
2692
|
+
for (const name of literalCredentialHeaders(props.header)) {
|
|
2693
|
+
out.push(`header '${name}' holds a literal credential; ${WRITE_ONLY}`);
|
|
2694
|
+
}
|
|
2695
|
+
for (const where of literalCredentialsInUrl(props.url)) {
|
|
2696
|
+
out.push(`'url' ${where} holds a literal credential; ${WRITE_ONLY}`);
|
|
2697
|
+
}
|
|
2698
|
+
return out;
|
|
2699
|
+
};
|
|
2700
|
+
var isFromEnv = (value) => typeof value !== "string";
|
|
2701
|
+
var resolveGroups = (props, env = process.env) => {
|
|
2702
|
+
const headerRefs = {};
|
|
2703
|
+
const headers = {};
|
|
2704
|
+
for (const [name, value] of Object.entries(props.header ?? {})) {
|
|
2705
|
+
if (isFromEnv(value))
|
|
2706
|
+
headerRefs[name] = value;
|
|
2707
|
+
else
|
|
2708
|
+
headers[name] = value;
|
|
2709
|
+
}
|
|
2710
|
+
const header = resolveAll(headerRefs, env);
|
|
2711
|
+
const sealedRefs = {};
|
|
2712
|
+
for (const [name, ref] of Object.entries(props.secret ?? {}))
|
|
2713
|
+
sealedRefs[`secret:${name}`] = ref;
|
|
2714
|
+
if (props.password !== undefined)
|
|
2715
|
+
sealedRefs["password"] = props.password;
|
|
2716
|
+
const sealed = resolveAll(sealedRefs, env);
|
|
2717
|
+
return {
|
|
2718
|
+
header: { missing: header.missing, values: { ...headers, ...header.values } },
|
|
2719
|
+
sealed
|
|
2720
|
+
};
|
|
2721
|
+
};
|
|
2722
|
+
var same5 = (declared, live) => declared === undefined || declared === live;
|
|
2723
|
+
var plainMatches = (live, props) => live.disable === (props.disable === true) && same5(props.comment, live.comment) && same5(props.author, live.author) && same5(props["from-address"], live["from-address"]) && same5(props.server, live.server) && (props.port === undefined || props.port === live.port) && same5(props.mode, live.mode) && same5(props.username, live.username) && same5(props.url, live.url) && same5(props.method, live.method) && same5(props.body, live.body) && (props.mailto === undefined || addressList(props.mailto) === live.mailto) && (props["mailto-user"] === undefined || addressList(props["mailto-user"]) === live["mailto-user"]);
|
|
2724
|
+
var headerState = (live, props, groups) => {
|
|
2725
|
+
if (props.header === undefined)
|
|
2726
|
+
return "match";
|
|
2727
|
+
if (names(Object.keys(props.header)) !== live.header)
|
|
2728
|
+
return "stale";
|
|
2729
|
+
if (groups.header.missing.length > 0)
|
|
2730
|
+
return "unknown";
|
|
2731
|
+
return headerDigest(props.name, groups.header.values) === live.headerDigest ? "match" : "stale";
|
|
2732
|
+
};
|
|
2733
|
+
var sealedState = (live, props, groups, sealed) => {
|
|
2734
|
+
if (props.secret === undefined && props.password === undefined)
|
|
2735
|
+
return "match";
|
|
2736
|
+
if (props.secret !== undefined && names(Object.keys(props.secret)) !== live.secret)
|
|
2737
|
+
return "stale";
|
|
2738
|
+
if (groups.sealed.missing.length > 0 || sealed === "")
|
|
2739
|
+
return "unknown";
|
|
2740
|
+
return sealMatches(sealed, groups.sealed.values) ? "match" : "stale";
|
|
2741
|
+
};
|
|
2742
|
+
var secretItems = (props, groups) => Object.keys(props.secret ?? {}).map((name) => wireItem(name, groups.sealed.values[`secret:${name}`] ?? ""));
|
|
2743
|
+
var headerItems = (props, groups) => Object.keys(props.header ?? {}).map((name) => wireItem(name, groups.header.values[name] ?? ""));
|
|
2744
|
+
var plainPairs = (props) => [
|
|
2745
|
+
["author", props.author ?? ""],
|
|
2746
|
+
["body", props.body === undefined ? "" : base64(props.body)],
|
|
2747
|
+
["comment", props.comment ?? ""],
|
|
2748
|
+
["from-address", props["from-address"] ?? ""],
|
|
2749
|
+
["method", props.method ?? ""],
|
|
2750
|
+
["mode", props.mode ?? ""],
|
|
2751
|
+
["port", props.port === undefined ? "" : String(props.port)],
|
|
2752
|
+
["server", props.server ?? ""],
|
|
2753
|
+
["url", props.url ?? ""],
|
|
2754
|
+
["username", props.username ?? ""],
|
|
2755
|
+
["mailto", props.mailto === undefined ? [] : addressList(props.mailto).split(",")],
|
|
2756
|
+
[
|
|
2757
|
+
"mailto-user",
|
|
2758
|
+
props["mailto-user"] === undefined ? [] : addressList(props["mailto-user"]).split(",")
|
|
2759
|
+
]
|
|
2760
|
+
];
|
|
2761
|
+
var declared = (props, key) => props[key] !== undefined;
|
|
2762
|
+
var empty = (value) => typeof value === "string" ? value === "" : value.filter((item) => item !== "").length === 0;
|
|
2763
|
+
var targetForm = (props, groups, carry, mode) => {
|
|
2764
|
+
const form = {
|
|
2765
|
+
disable: props.disable === true ? "1" : "0"
|
|
2766
|
+
};
|
|
2767
|
+
const cleared = [];
|
|
2768
|
+
const put = (key, value) => {
|
|
2769
|
+
if (!empty(value))
|
|
2770
|
+
form[key] = value;
|
|
2771
|
+
else if (mode === "update")
|
|
2772
|
+
cleared.push(key);
|
|
2773
|
+
};
|
|
2774
|
+
for (const [key, value] of plainPairs(props))
|
|
2775
|
+
if (declared(props, key))
|
|
2776
|
+
put(key, value);
|
|
2777
|
+
if (carry.header && props.header !== undefined)
|
|
2778
|
+
put("header", headerItems(props, groups));
|
|
2779
|
+
if (carry.sealed && props.secret !== undefined)
|
|
2780
|
+
put("secret", secretItems(props, groups));
|
|
2781
|
+
if (carry.sealed && props.password !== undefined) {
|
|
2782
|
+
form["password"] = groups.sealed.values["password"] ?? "";
|
|
2783
|
+
}
|
|
2784
|
+
if (mode === "create")
|
|
2785
|
+
form["name"] = props.name;
|
|
2786
|
+
if (cleared.length > 0)
|
|
2787
|
+
form["delete"] = cleared;
|
|
2788
|
+
return form;
|
|
2789
|
+
};
|
|
2790
|
+
|
|
2791
|
+
// src/proxmox/pbs-notification-target-lifecycle.ts
|
|
2792
|
+
var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
|
|
2793
|
+
var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect41.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect41.orElseSucceed(() => {
|
|
2794
|
+
return;
|
|
2795
|
+
}));
|
|
2796
|
+
var refuse2 = (props) => {
|
|
2797
|
+
const reasons = refusals(props);
|
|
2798
|
+
return reasons.length === 0 ? Effect41.void : Effect41.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
|
|
2799
|
+
};
|
|
2800
|
+
var toCarry = (live, props, groups, sealed) => {
|
|
2801
|
+
const header = headerState(live, props, groups) === "stale";
|
|
2802
|
+
const sealedStale = sealedState(live, props, groups, sealed) === "stale";
|
|
2803
|
+
return plainMatches(live, props) && !header && !sealedStale ? undefined : { header, sealed: sealedStale };
|
|
2804
|
+
};
|
|
2805
|
+
var requireValues = (props, groups, carry) => {
|
|
2806
|
+
const missing = [
|
|
2807
|
+
...carry.header ? groups.header.missing : [],
|
|
2808
|
+
...carry.sealed ? groups.sealed.missing : []
|
|
2809
|
+
];
|
|
2810
|
+
return missing.length === 0 ? Effect41.void : Effect41.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."));
|
|
2811
|
+
};
|
|
2812
|
+
var handlers17 = {
|
|
2813
|
+
list: () => Effect41.succeed([]),
|
|
2814
|
+
read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect41.void).pipe(Effect41.andThen(readLive2(olds)), Effect41.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
|
|
2815
|
+
diff: ({
|
|
2816
|
+
news,
|
|
2817
|
+
olds,
|
|
2818
|
+
output
|
|
2819
|
+
}) => Effect41.gen(function* () {
|
|
2820
|
+
if (output === undefined || !isResolved9(news))
|
|
2821
|
+
return;
|
|
2822
|
+
if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
|
|
2823
|
+
return { action: "replace", deleteFirst: olds.name === news.name };
|
|
2824
|
+
}
|
|
2825
|
+
yield* refuse2(news);
|
|
2826
|
+
const live = yield* readLive2(news);
|
|
2827
|
+
if (live === undefined)
|
|
2828
|
+
return { action: "update" };
|
|
2829
|
+
return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
|
|
2830
|
+
}),
|
|
2831
|
+
reconcile: ({ news, output }) => Effect41.gen(function* () {
|
|
2832
|
+
yield* refuse2(news);
|
|
2833
|
+
const groups = resolveGroups(news);
|
|
2834
|
+
const live = yield* readLive2(news);
|
|
2835
|
+
let sealed = output?.sealed ?? "";
|
|
2836
|
+
if (live === undefined) {
|
|
2837
|
+
const carry = { header: true, sealed: true };
|
|
2838
|
+
yield* requireValues(news, groups, carry);
|
|
2839
|
+
const collection2 = `config/notifications/endpoints/${news.type}`;
|
|
2840
|
+
yield* pve(news.target, "provision", "POST", collection2, targetForm(news, groups, carry, "create"));
|
|
2841
|
+
sealed = seal(groups.sealed.values);
|
|
2842
|
+
} else {
|
|
2843
|
+
const carry = toCarry(live, news, groups, sealed);
|
|
2844
|
+
if (carry !== undefined) {
|
|
2845
|
+
yield* requireValues(news, groups, carry);
|
|
2846
|
+
yield* pve(news.target, "provision", "PUT", path(news), targetForm(news, groups, carry, "update"));
|
|
2847
|
+
if (carry.sealed)
|
|
2848
|
+
sealed = seal(groups.sealed.values);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
const after = yield* readLive2(news);
|
|
2852
|
+
if (after === undefined) {
|
|
2853
|
+
return yield* Effect41.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
|
|
2854
|
+
}
|
|
2855
|
+
return { ...after, sealed };
|
|
2856
|
+
}),
|
|
2857
|
+
delete: ({ olds }) => pve(olds.target, "provision", "DELETE", path(olds))
|
|
2858
|
+
};
|
|
2859
|
+
|
|
2860
|
+
// src/proxmox/pbs-notification-target.ts
|
|
2861
|
+
var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
|
|
2862
|
+
var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect42.succeed(PbsNotificationTarget.Provider.of(handlers17)));
|
|
2372
2863
|
// src/proxmox/pbs-prune-job.ts
|
|
2373
|
-
import { Resource as
|
|
2374
|
-
import * as
|
|
2375
|
-
import * as
|
|
2864
|
+
import { Resource as Resource22 } from "alchemy";
|
|
2865
|
+
import * as Provider22 from "alchemy/Provider";
|
|
2866
|
+
import * as Effect43 from "effect/Effect";
|
|
2376
2867
|
|
|
2377
2868
|
// src/proxmox/pbs-prune-job-form.ts
|
|
2378
2869
|
var KEEP_KEYS = [
|
|
@@ -2407,14 +2898,14 @@ var requireKeeps = (props) => {
|
|
|
2407
2898
|
return;
|
|
2408
2899
|
throw new Error(`Pbs.PruneJob ${props.id}: declares no keep-* window, which tells PBS to keep NOTHING on ` + `datastore '${props.store}'. Every keep-* is optional on the wire, so an omission and a ` + 'deliberate "retain nothing" are indistinguishable; declare at least one window (keep-last, ' + "keep-hourly, keep-daily, keep-weekly, keep-monthly or keep-yearly) or delete the job.");
|
|
2409
2900
|
};
|
|
2410
|
-
var
|
|
2901
|
+
var field5 = (name, value) => value === undefined ? {} : { [name]: value };
|
|
2411
2902
|
var integer = (value) => value === undefined ? undefined : String(value);
|
|
2412
2903
|
var shape5 = (props) => ({
|
|
2413
2904
|
...keepForm(props),
|
|
2414
|
-
...
|
|
2415
|
-
...
|
|
2416
|
-
...
|
|
2417
|
-
...
|
|
2905
|
+
...field5("comment", props.comment),
|
|
2906
|
+
...field5("disable", flag(props.disable)),
|
|
2907
|
+
...field5("max-depth", integer(props["max-depth"])),
|
|
2908
|
+
...field5("ns", props.ns),
|
|
2418
2909
|
schedule: props.schedule,
|
|
2419
2910
|
store: props.store
|
|
2420
2911
|
});
|
|
@@ -2428,9 +2919,9 @@ var updateBody3 = (props) => {
|
|
|
2428
2919
|
};
|
|
2429
2920
|
|
|
2430
2921
|
// src/proxmox/pbs-prune-job.ts
|
|
2431
|
-
var PbsPruneJob =
|
|
2432
|
-
var
|
|
2433
|
-
var
|
|
2922
|
+
var PbsPruneJob = Resource22("Pbs.PruneJob");
|
|
2923
|
+
var same6 = (declared2, live) => declared2 === undefined || declared2 === live;
|
|
2924
|
+
var handlers18 = pveHandlers({
|
|
2434
2925
|
attributes: (live, props) => ({
|
|
2435
2926
|
comment: text(live["comment"], ""),
|
|
2436
2927
|
disable: bool(live["disable"], false),
|
|
@@ -2443,15 +2934,15 @@ var handlers15 = pveHandlers({
|
|
|
2443
2934
|
}),
|
|
2444
2935
|
collection: () => "config/prune",
|
|
2445
2936
|
createForm: createBody2,
|
|
2446
|
-
matches: (attributes2, props) => attributes2.schedule === props.schedule && attributes2.store === props.store &&
|
|
2937
|
+
matches: (attributes2, props) => attributes2.schedule === props.schedule && attributes2.store === props.store && same6(props.ns, attributes2.ns) && same6(props["max-depth"], attributes2["max-depth"]) && same6(props.disable, attributes2.disable) && same6(props.comment, attributes2.comment) && keepsMatch(attributes2, props),
|
|
2447
2938
|
path: (props) => `config/prune/${props.id}`,
|
|
2448
2939
|
updateForm: updateBody3
|
|
2449
2940
|
});
|
|
2450
|
-
var PbsPruneJobProvider = () =>
|
|
2941
|
+
var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect43.succeed(PbsPruneJob.Provider.of(handlers18)));
|
|
2451
2942
|
// src/proxmox/pbs-sync-job.ts
|
|
2452
|
-
import { Resource as
|
|
2453
|
-
import * as
|
|
2454
|
-
import * as
|
|
2943
|
+
import { Resource as Resource23 } from "alchemy";
|
|
2944
|
+
import * as Provider23 from "alchemy/Provider";
|
|
2945
|
+
import * as Effect44 from "effect/Effect";
|
|
2455
2946
|
|
|
2456
2947
|
// src/proxmox/pbs-sync-job-form.ts
|
|
2457
2948
|
var UNSET4 = -1;
|
|
@@ -2499,7 +2990,7 @@ var createBody3 = (props) => ({
|
|
|
2499
2990
|
...props["sync-direction"] === undefined ? {} : { "sync-direction": props["sync-direction"] }
|
|
2500
2991
|
});
|
|
2501
2992
|
var updateBody4 = (props) => shape6(props);
|
|
2502
|
-
var
|
|
2993
|
+
var handlers19 = pveHandlers({
|
|
2503
2994
|
attributes: (live, props) => ({
|
|
2504
2995
|
comment: text(live["comment"], ""),
|
|
2505
2996
|
"group-filter": filters(live["group-filter"]),
|
|
@@ -2526,12 +3017,12 @@ var handlers16 = pveHandlers({
|
|
|
2526
3017
|
});
|
|
2527
3018
|
|
|
2528
3019
|
// src/proxmox/pbs-sync-job.ts
|
|
2529
|
-
var PbsSyncJob =
|
|
2530
|
-
var PbsSyncJobProvider = () =>
|
|
3020
|
+
var PbsSyncJob = Resource23("Pbs.SyncJob");
|
|
3021
|
+
var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect44.succeed(PbsSyncJob.Provider.of(handlers19)));
|
|
2531
3022
|
// src/proxmox/pbs-verify-job.ts
|
|
2532
|
-
import { Resource as
|
|
2533
|
-
import * as
|
|
2534
|
-
import * as
|
|
3023
|
+
import { Resource as Resource24 } from "alchemy";
|
|
3024
|
+
import * as Provider24 from "alchemy/Provider";
|
|
3025
|
+
import * as Effect45 from "effect/Effect";
|
|
2535
3026
|
|
|
2536
3027
|
// src/proxmox/pbs-verify-job-form.ts
|
|
2537
3028
|
var rechecks = (ignoreVerified, outdatedAfter) => {
|
|
@@ -2552,8 +3043,8 @@ var shape7 = (props) => ({
|
|
|
2552
3043
|
});
|
|
2553
3044
|
|
|
2554
3045
|
// src/proxmox/pbs-verify-job.ts
|
|
2555
|
-
var PbsVerifyJob =
|
|
2556
|
-
var
|
|
3046
|
+
var PbsVerifyJob = Resource24("Pbs.VerifyJob");
|
|
3047
|
+
var handlers20 = pveHandlers({
|
|
2557
3048
|
attributes: (live, props) => {
|
|
2558
3049
|
const ignoreVerified = bool(live["ignore-verified"], true);
|
|
2559
3050
|
const outdatedAfter = int(live["outdated-after"], -1);
|
|
@@ -2575,12 +3066,12 @@ var handlers17 = pveHandlers({
|
|
|
2575
3066
|
path: (props) => `config/verify/${props.id}`,
|
|
2576
3067
|
updateForm: shape7
|
|
2577
3068
|
});
|
|
2578
|
-
var PbsVerifyJobProvider = () =>
|
|
3069
|
+
var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect45.succeed(PbsVerifyJob.Provider.of(handlers20)));
|
|
2579
3070
|
// src/proxmox/pool.ts
|
|
2580
|
-
import { Resource as
|
|
2581
|
-
import * as
|
|
2582
|
-
import * as
|
|
2583
|
-
var ProxmoxPool =
|
|
3071
|
+
import { Resource as Resource25 } from "alchemy";
|
|
3072
|
+
import * as Provider25 from "alchemy/Provider";
|
|
3073
|
+
import * as Effect46 from "effect/Effect";
|
|
3074
|
+
var ProxmoxPool = Resource25("Proxmox.Pool");
|
|
2584
3075
|
var poolCreateForm = (props) => ({
|
|
2585
3076
|
comment: props.comment ?? "",
|
|
2586
3077
|
poolid: props.poolid
|
|
@@ -2588,7 +3079,7 @@ var poolCreateForm = (props) => ({
|
|
|
2588
3079
|
var poolUpdateForm = (props) => ({
|
|
2589
3080
|
comment: props.comment ?? ""
|
|
2590
3081
|
});
|
|
2591
|
-
var
|
|
3082
|
+
var handlers21 = pveHandlers({
|
|
2592
3083
|
attributes: (live, props) => {
|
|
2593
3084
|
const row = live;
|
|
2594
3085
|
return {
|
|
@@ -2603,7 +3094,7 @@ var handlers18 = pveHandlers({
|
|
|
2603
3094
|
path: (props) => `pools/${props.poolid}`,
|
|
2604
3095
|
updateForm: poolUpdateForm
|
|
2605
3096
|
});
|
|
2606
|
-
var ProxmoxPoolProvider = () =>
|
|
3097
|
+
var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect46.succeed(ProxmoxPool.Provider.of(handlers21)));
|
|
2607
3098
|
// src/proxmox/provision-baseline.ts
|
|
2608
3099
|
var PROVISION_PRIVILEGES = Object.freeze([
|
|
2609
3100
|
"Datastore.Allocate",
|
|
@@ -2645,30 +3136,30 @@ var PROVISION_DEFAULTS = Object.freeze({
|
|
|
2645
3136
|
var ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
2646
3137
|
var USERID = /^[A-Za-z0-9][A-Za-z0-9._-]*@[A-Za-z][A-Za-z0-9._-]*$/;
|
|
2647
3138
|
var COMMENT = /^[A-Za-z0-9 ._,()@/+-]*$/;
|
|
2648
|
-
var problems2 = (
|
|
3139
|
+
var problems2 = (names2) => {
|
|
2649
3140
|
const found = [];
|
|
2650
|
-
if (!ID.test(
|
|
2651
|
-
found.push(`role \`${
|
|
2652
|
-
if (!ID.test(
|
|
2653
|
-
found.push(`mintGroup \`${
|
|
2654
|
-
if (!ID.test(
|
|
2655
|
-
found.push(`readRole \`${
|
|
2656
|
-
for (const [
|
|
2657
|
-
["provisionUser",
|
|
2658
|
-
["readUser",
|
|
3141
|
+
if (!ID.test(names2.role))
|
|
3142
|
+
found.push(`role \`${names2.role}\` is not a PVE role id`);
|
|
3143
|
+
if (!ID.test(names2.mintGroup))
|
|
3144
|
+
found.push(`mintGroup \`${names2.mintGroup}\` is not a group id`);
|
|
3145
|
+
if (!ID.test(names2.readRole))
|
|
3146
|
+
found.push(`readRole \`${names2.readRole}\` is not a PVE role id`);
|
|
3147
|
+
for (const [field6, userid] of [
|
|
3148
|
+
["provisionUser", names2.provisionUser],
|
|
3149
|
+
["readUser", names2.readUser]
|
|
2659
3150
|
]) {
|
|
2660
3151
|
if (userid !== null && !USERID.test(userid)) {
|
|
2661
|
-
found.push(`${
|
|
3152
|
+
found.push(`${field6} \`${userid}\` is not a realm-qualified user id (name@realm)`);
|
|
2662
3153
|
}
|
|
2663
3154
|
}
|
|
2664
|
-
if (
|
|
3155
|
+
if (names2.readUser === names2.provisionUser)
|
|
2665
3156
|
found.push("readUser and provisionUser are one user");
|
|
2666
|
-
if (!COMMENT.test(
|
|
3157
|
+
if (!COMMENT.test(names2.comment))
|
|
2667
3158
|
found.push("comment holds a character the bootstrap will not quote");
|
|
2668
3159
|
return found;
|
|
2669
3160
|
};
|
|
2670
|
-
var provisionBaseline = (
|
|
2671
|
-
const given = Object.entries(
|
|
3161
|
+
var provisionBaseline = (names2 = {}) => {
|
|
3162
|
+
const given = Object.entries(names2).filter(([, value]) => value !== undefined);
|
|
2672
3163
|
const resolved = {
|
|
2673
3164
|
...PROVISION_DEFAULTS,
|
|
2674
3165
|
...Object.fromEntries(given)
|
|
@@ -2759,8 +3250,8 @@ else echo 'grant ${grant.userid} ${grant.roleid} /: adding'; pveum acl modify /
|
|
|
2759
3250
|
var requireRole = (roleid) => `
|
|
2760
3251
|
get /access/roles/${roleid} 'print 1' >/dev/null || { echo 'bootstrap: role ${roleid} does not exist; create it, or name another readRole' >&2; exit 1; }
|
|
2761
3252
|
`;
|
|
2762
|
-
var provisionBootstrap = (
|
|
2763
|
-
const baseline = provisionBaseline(
|
|
3253
|
+
var provisionBootstrap = (names2 = {}) => {
|
|
3254
|
+
const baseline = provisionBaseline(names2);
|
|
2764
3255
|
const borrowed = baseline.grants.map((grant) => grant.roleid).filter((roleid) => roleid !== baseline.role.roleid);
|
|
2765
3256
|
return [
|
|
2766
3257
|
HEADER,
|
|
@@ -2777,35 +3268,35 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
|
|
|
2777
3268
|
// src/proxmox/provision-declare.ts
|
|
2778
3269
|
import { adopt } from "alchemy/AdoptPolicy";
|
|
2779
3270
|
import * as RemovalPolicy from "alchemy/RemovalPolicy";
|
|
2780
|
-
import * as
|
|
3271
|
+
import * as Effect49 from "effect/Effect";
|
|
2781
3272
|
|
|
2782
3273
|
// src/proxmox/role.ts
|
|
2783
|
-
import { Resource as
|
|
2784
|
-
import * as
|
|
2785
|
-
import * as
|
|
2786
|
-
var ProxmoxRole =
|
|
2787
|
-
var
|
|
3274
|
+
import { Resource as Resource26 } from "alchemy";
|
|
3275
|
+
import * as Provider26 from "alchemy/Provider";
|
|
3276
|
+
import * as Effect47 from "effect/Effect";
|
|
3277
|
+
var ProxmoxRole = Resource26("Proxmox.Role");
|
|
3278
|
+
var canonical2 = (privs) => [...new Set(privs.map((priv) => priv.trim()).filter((priv) => priv.length > 0))].sort();
|
|
2788
3279
|
var livePrivs = (live) => {
|
|
2789
3280
|
const listed = live["privs"];
|
|
2790
3281
|
if (typeof listed === "string")
|
|
2791
|
-
return
|
|
2792
|
-
return
|
|
3282
|
+
return canonical2(listed.split(","));
|
|
3283
|
+
return canonical2(Object.keys(live).filter((key) => key.includes(".")));
|
|
2793
3284
|
};
|
|
2794
|
-
var
|
|
3285
|
+
var handlers22 = pveHandlers({
|
|
2795
3286
|
attributes: (live, props) => ({ privs: livePrivs(live), roleid: props.roleid }),
|
|
2796
3287
|
collection: () => "access/roles",
|
|
2797
|
-
createForm: (props) => ({ privs:
|
|
2798
|
-
matches: (attributes2, props) =>
|
|
3288
|
+
createForm: (props) => ({ privs: canonical2(props.privs).join(","), roleid: props.roleid }),
|
|
3289
|
+
matches: (attributes2, props) => canonical2(attributes2.privs).join(",") === canonical2(props.privs).join(","),
|
|
2799
3290
|
path: (props) => `access/roles/${props.roleid}`,
|
|
2800
|
-
updateForm: (props) => ({ privs:
|
|
3291
|
+
updateForm: (props) => ({ privs: canonical2(props.privs).join(",") })
|
|
2801
3292
|
});
|
|
2802
|
-
var ProxmoxRoleProvider = () =>
|
|
3293
|
+
var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect47.succeed(ProxmoxRole.Provider.of(handlers22)));
|
|
2803
3294
|
|
|
2804
3295
|
// src/proxmox/user.ts
|
|
2805
|
-
import { Resource as
|
|
2806
|
-
import * as
|
|
2807
|
-
import * as
|
|
2808
|
-
var ProxmoxUser =
|
|
3296
|
+
import { Resource as Resource27 } from "alchemy";
|
|
3297
|
+
import * as Provider27 from "alchemy/Provider";
|
|
3298
|
+
import * as Effect48 from "effect/Effect";
|
|
3299
|
+
var ProxmoxUser = Resource27("Proxmox.User");
|
|
2809
3300
|
var str2 = (value) => typeof value === "string" ? value : "";
|
|
2810
3301
|
var int2 = (value) => {
|
|
2811
3302
|
const parsed = typeof value === "number" ? value : Number(value ?? 0);
|
|
@@ -2813,8 +3304,8 @@ var int2 = (value) => {
|
|
|
2813
3304
|
};
|
|
2814
3305
|
var groupSet = (value) => {
|
|
2815
3306
|
const raw = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
|
|
2816
|
-
const
|
|
2817
|
-
return [...new Set(
|
|
3307
|
+
const names2 = raw.map((group) => str2(group).trim()).filter((group) => group !== "");
|
|
3308
|
+
return [...new Set(names2)].sort();
|
|
2818
3309
|
};
|
|
2819
3310
|
var tokenNames = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? Object.keys(value).sort() : [];
|
|
2820
3311
|
var shape8 = (props) => ({
|
|
@@ -2826,7 +3317,7 @@ var shape8 = (props) => ({
|
|
|
2826
3317
|
groups: groupSet(props.groups).join(","),
|
|
2827
3318
|
lastname: props.lastname ?? ""
|
|
2828
3319
|
});
|
|
2829
|
-
var
|
|
3320
|
+
var handlers23 = pveHandlers({
|
|
2830
3321
|
attributes: (live, props) => ({
|
|
2831
3322
|
comment: str2(live["comment"]),
|
|
2832
3323
|
email: str2(live["email"]),
|
|
@@ -2844,13 +3335,13 @@ var handlers20 = pveHandlers({
|
|
|
2844
3335
|
path: (props) => `access/users/${props.userid}`,
|
|
2845
3336
|
updateForm: shape8
|
|
2846
3337
|
});
|
|
2847
|
-
var ProxmoxUserProvider = () =>
|
|
3338
|
+
var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect48.succeed(ProxmoxUser.Provider.of(handlers23)));
|
|
2848
3339
|
|
|
2849
3340
|
// src/proxmox/provision-declare.ts
|
|
2850
|
-
var declareProvisionBaseline = (id, target,
|
|
2851
|
-
const baseline = yield*
|
|
3341
|
+
var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect49.gen(function* () {
|
|
3342
|
+
const baseline = yield* Effect49.try({
|
|
2852
3343
|
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
|
|
2853
|
-
try: () => provisionBaseline(
|
|
3344
|
+
try: () => provisionBaseline(names2)
|
|
2854
3345
|
});
|
|
2855
3346
|
const owned = (resource) => {
|
|
2856
3347
|
const kept = resource.pipe(RemovalPolicy.retain());
|
|
@@ -2862,13 +3353,13 @@ var declareProvisionBaseline = (id, target, names = {}, options = {}) => Effect4
|
|
|
2862
3353
|
target
|
|
2863
3354
|
}));
|
|
2864
3355
|
const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
|
|
2865
|
-
const users = yield*
|
|
3356
|
+
const users = yield* Effect49.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
|
|
2866
3357
|
comment: user.comment,
|
|
2867
3358
|
groups: [...user.groups],
|
|
2868
3359
|
target,
|
|
2869
3360
|
userid: user.userid
|
|
2870
3361
|
}))));
|
|
2871
|
-
const grants = yield*
|
|
3362
|
+
const grants = yield* Effect49.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
|
|
2872
3363
|
path: "/",
|
|
2873
3364
|
propagate: true,
|
|
2874
3365
|
roleid: grant.roleid,
|
|
@@ -2879,10 +3370,10 @@ var declareProvisionBaseline = (id, target, names = {}, options = {}) => Effect4
|
|
|
2879
3370
|
return { baseline, grants, group, role, users };
|
|
2880
3371
|
});
|
|
2881
3372
|
// src/proxmox/qemu.ts
|
|
2882
|
-
import { Resource as
|
|
2883
|
-
import * as
|
|
2884
|
-
import * as
|
|
2885
|
-
var ProxmoxVm =
|
|
3373
|
+
import { Resource as Resource28 } from "alchemy";
|
|
3374
|
+
import * as Provider28 from "alchemy/Provider";
|
|
3375
|
+
import * as Effect50 from "effect/Effect";
|
|
3376
|
+
var ProxmoxVm = Resource28("Proxmox.Vm");
|
|
2886
3377
|
var shape9 = (props) => ({
|
|
2887
3378
|
cores: String(props.cores ?? 1),
|
|
2888
3379
|
memory: String(props.memory ?? 512),
|
|
@@ -2891,7 +3382,7 @@ var shape9 = (props) => ({
|
|
|
2891
3382
|
sockets: String(props.sockets ?? 1),
|
|
2892
3383
|
...props.net0 === undefined ? {} : { net0: props.net0 }
|
|
2893
3384
|
});
|
|
2894
|
-
var
|
|
3385
|
+
var handlers24 = pveHandlers({
|
|
2895
3386
|
attributes: (live, props) => ({
|
|
2896
3387
|
cores: num(live["cores"], 1),
|
|
2897
3388
|
memory: num(live["memory"], 512),
|
|
@@ -2907,11 +3398,11 @@ var handlers21 = pveHandlers({
|
|
|
2907
3398
|
path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
|
|
2908
3399
|
updateForm: shape9
|
|
2909
3400
|
});
|
|
2910
|
-
var ProxmoxVmProvider = () =>
|
|
3401
|
+
var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect50.succeed(ProxmoxVm.Provider.of(handlers24)));
|
|
2911
3402
|
// src/proxmox/replication-job.ts
|
|
2912
|
-
import { Resource as
|
|
2913
|
-
import * as
|
|
2914
|
-
import * as
|
|
3403
|
+
import { Resource as Resource29 } from "alchemy";
|
|
3404
|
+
import * as Provider29 from "alchemy/Provider";
|
|
3405
|
+
import * as Effect51 from "effect/Effect";
|
|
2915
3406
|
|
|
2916
3407
|
// src/proxmox/replication-job-form.ts
|
|
2917
3408
|
var DEFAULT_SCHEDULE = "*/15";
|
|
@@ -2934,14 +3425,14 @@ var updateBody5 = (props) => ({
|
|
|
2934
3425
|
});
|
|
2935
3426
|
|
|
2936
3427
|
// src/proxmox/replication-job.ts
|
|
2937
|
-
var ProxmoxReplicationJob =
|
|
3428
|
+
var ProxmoxReplicationJob = Resource29("Proxmox.ReplicationJob");
|
|
2938
3429
|
var rateOf = (value) => {
|
|
2939
3430
|
if (typeof value === "number")
|
|
2940
3431
|
return value;
|
|
2941
3432
|
const parsed = Number.parseFloat(text(value));
|
|
2942
3433
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
2943
3434
|
};
|
|
2944
|
-
var
|
|
3435
|
+
var handlers25 = pveHandlers({
|
|
2945
3436
|
attributes: (live, props) => ({
|
|
2946
3437
|
comment: text(live["comment"], ""),
|
|
2947
3438
|
disable: bool(live["disable"], false),
|
|
@@ -2961,15 +3452,15 @@ var handlers22 = pveHandlers({
|
|
|
2961
3452
|
path: (props) => `cluster/replication/${jobId(props)}`,
|
|
2962
3453
|
updateForm: updateBody5
|
|
2963
3454
|
});
|
|
2964
|
-
var ProxmoxReplicationJobProvider = () =>
|
|
3455
|
+
var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect51.succeed(ProxmoxReplicationJob.Provider.of(handlers25)));
|
|
2965
3456
|
// src/proxmox/sdn-apply.ts
|
|
2966
|
-
import { Resource as
|
|
2967
|
-
import { isResolved as
|
|
2968
|
-
import * as
|
|
2969
|
-
import * as
|
|
3457
|
+
import { Resource as Resource30 } from "alchemy";
|
|
3458
|
+
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
3459
|
+
import * as Provider30 from "alchemy/Provider";
|
|
3460
|
+
import * as Effect53 from "effect/Effect";
|
|
2970
3461
|
|
|
2971
3462
|
// src/proxmox/sdn-apply-read.ts
|
|
2972
|
-
import * as
|
|
3463
|
+
import * as Effect52 from "effect/Effect";
|
|
2973
3464
|
var MARKED = [
|
|
2974
3465
|
"cluster/sdn/zones",
|
|
2975
3466
|
"cluster/sdn/vnets",
|
|
@@ -2978,7 +3469,7 @@ var MARKED = [
|
|
|
2978
3469
|
"cluster/sdn/route-maps"
|
|
2979
3470
|
];
|
|
2980
3471
|
var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
|
|
2981
|
-
var markedPending = (target) =>
|
|
3472
|
+
var markedPending = (target) => Effect52.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect52.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect52.catchIf(subsystemAbsent, () => Effect52.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect52.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
|
|
2982
3473
|
var fabricStaged = (staged, running) => {
|
|
2983
3474
|
if (staged === undefined && running === undefined)
|
|
2984
3475
|
return 0;
|
|
@@ -2986,11 +3477,11 @@ var fabricStaged = (staged, running) => {
|
|
|
2986
3477
|
return "inconsistent";
|
|
2987
3478
|
return staged === running ? 0 : 1;
|
|
2988
3479
|
};
|
|
2989
|
-
var fabricPending = (target) =>
|
|
3480
|
+
var fabricPending = (target) => Effect52.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect52.map(canonical3), Effect52.catchIf(subsystemAbsent, () => Effect52.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect52.flatMap(([staged, running]) => {
|
|
2990
3481
|
const verdict = fabricStaged(staged, running);
|
|
2991
|
-
return verdict === "inconsistent" ?
|
|
3482
|
+
return verdict === "inconsistent" ? Effect52.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.")) : Effect52.succeed(verdict);
|
|
2992
3483
|
}));
|
|
2993
|
-
var
|
|
3484
|
+
var canonical3 = (value) => JSON.stringify(sortDeep(value));
|
|
2994
3485
|
var sortDeep = (value) => {
|
|
2995
3486
|
if (Array.isArray(value)) {
|
|
2996
3487
|
return value.map(sortDeep).sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
|
|
@@ -3001,39 +3492,39 @@ var sortDeep = (value) => {
|
|
|
3001
3492
|
}
|
|
3002
3493
|
return value;
|
|
3003
3494
|
};
|
|
3004
|
-
var sdnPendingCount = (target) =>
|
|
3495
|
+
var sdnPendingCount = (target) => Effect52.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect52.map(([marked, fabric]) => marked + fabric));
|
|
3005
3496
|
|
|
3006
3497
|
// src/proxmox/sdn-apply.ts
|
|
3007
|
-
var ProxmoxSdnApply =
|
|
3008
|
-
var read3 = (props) => sdnPendingCount(props.target).pipe(
|
|
3009
|
-
var ProxmoxSdnApplyProvider = () =>
|
|
3010
|
-
list: () =>
|
|
3011
|
-
read:
|
|
3498
|
+
var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
|
|
3499
|
+
var read3 = (props) => sdnPendingCount(props.target).pipe(Effect53.map((pending) => ({ pending })));
|
|
3500
|
+
var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect53.succeed(ProxmoxSdnApply.Provider.of({
|
|
3501
|
+
list: () => Effect53.succeed([]),
|
|
3502
|
+
read: Effect53.fn(function* ({ olds }) {
|
|
3012
3503
|
return yield* read3(olds);
|
|
3013
3504
|
}),
|
|
3014
|
-
diff:
|
|
3015
|
-
if (!
|
|
3505
|
+
diff: Effect53.fn(function* ({ news }) {
|
|
3506
|
+
if (!isResolved10(news))
|
|
3016
3507
|
return;
|
|
3017
3508
|
const { pending } = yield* read3(news);
|
|
3018
3509
|
return pending === 0 ? { action: "noop" } : { action: "update" };
|
|
3019
3510
|
}),
|
|
3020
|
-
reconcile:
|
|
3511
|
+
reconcile: Effect53.fn(function* ({ news }) {
|
|
3021
3512
|
const staged = yield* read3(news);
|
|
3022
3513
|
if (staged.pending === 0)
|
|
3023
3514
|
return staged;
|
|
3024
3515
|
yield* pve(news.target, "provision", "PUT", "cluster/sdn");
|
|
3025
3516
|
const after = yield* read3(news);
|
|
3026
3517
|
if (after.pending !== 0) {
|
|
3027
|
-
return yield*
|
|
3518
|
+
return yield* Effect53.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."));
|
|
3028
3519
|
}
|
|
3029
3520
|
return after;
|
|
3030
3521
|
}),
|
|
3031
|
-
delete: () =>
|
|
3522
|
+
delete: () => Effect53.void
|
|
3032
3523
|
})));
|
|
3033
3524
|
// src/proxmox/sdn-subnet.ts
|
|
3034
|
-
import { Resource as
|
|
3035
|
-
import * as
|
|
3036
|
-
import * as
|
|
3525
|
+
import { Resource as Resource31 } from "alchemy";
|
|
3526
|
+
import * as Provider31 from "alchemy/Provider";
|
|
3527
|
+
import * as Effect54 from "effect/Effect";
|
|
3037
3528
|
|
|
3038
3529
|
// src/proxmox/sdn-subnet-form.ts
|
|
3039
3530
|
var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
|
|
@@ -3063,8 +3554,8 @@ var updateForm2 = (props) => {
|
|
|
3063
3554
|
};
|
|
3064
3555
|
|
|
3065
3556
|
// src/proxmox/sdn-subnet.ts
|
|
3066
|
-
var ProxmoxSdnSubnet =
|
|
3067
|
-
var
|
|
3557
|
+
var ProxmoxSdnSubnet = Resource31("Proxmox.SdnSubnet");
|
|
3558
|
+
var handlers26 = pveHandlers({
|
|
3068
3559
|
attributes: (live, props) => {
|
|
3069
3560
|
const liveVnet = text(live["vnet"]);
|
|
3070
3561
|
if (liveVnet !== "" && liveVnet !== props.vnet)
|
|
@@ -3089,12 +3580,12 @@ var handlers23 = pveHandlers({
|
|
|
3089
3580
|
path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
|
|
3090
3581
|
updateForm: updateForm2
|
|
3091
3582
|
});
|
|
3092
|
-
var ProxmoxSdnSubnetProvider = () =>
|
|
3583
|
+
var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect54.succeed(ProxmoxSdnSubnet.Provider.of(handlers26)));
|
|
3093
3584
|
// src/proxmox/sdn-vnet.ts
|
|
3094
|
-
import { Resource as
|
|
3095
|
-
import * as
|
|
3096
|
-
import * as
|
|
3097
|
-
var ProxmoxSdnVnet =
|
|
3585
|
+
import { Resource as Resource32 } from "alchemy";
|
|
3586
|
+
import * as Provider32 from "alchemy/Provider";
|
|
3587
|
+
import * as Effect55 from "effect/Effect";
|
|
3588
|
+
var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
|
|
3098
3589
|
var tagOf = (value) => typeof value === "number" ? value : undefined;
|
|
3099
3590
|
var shape11 = (props) => {
|
|
3100
3591
|
const alias = props.alias ?? "";
|
|
@@ -3113,7 +3604,7 @@ var updateForm3 = (props) => {
|
|
|
3113
3604
|
];
|
|
3114
3605
|
return withClears(shape11(props), unset2);
|
|
3115
3606
|
};
|
|
3116
|
-
var
|
|
3607
|
+
var handlers27 = pveHandlers({
|
|
3117
3608
|
readRole: "provision",
|
|
3118
3609
|
attributes: (live, props) => ({
|
|
3119
3610
|
alias: typeof live["alias"] === "string" ? live["alias"] : "",
|
|
@@ -3130,13 +3621,13 @@ var handlers24 = pveHandlers({
|
|
|
3130
3621
|
path: (props) => `cluster/sdn/vnets/${props.vnet}`,
|
|
3131
3622
|
updateForm: updateForm3
|
|
3132
3623
|
});
|
|
3133
|
-
var ProxmoxSdnVnetProvider = () =>
|
|
3624
|
+
var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect55.succeed(ProxmoxSdnVnet.Provider.of(handlers27)));
|
|
3134
3625
|
// src/proxmox/sdn-zone.ts
|
|
3135
|
-
import { Resource as
|
|
3136
|
-
import * as
|
|
3137
|
-
import * as
|
|
3138
|
-
var ProxmoxSdnZone =
|
|
3139
|
-
var sameIpam = (live,
|
|
3626
|
+
import { Resource as Resource33 } from "alchemy";
|
|
3627
|
+
import * as Provider33 from "alchemy/Provider";
|
|
3628
|
+
import * as Effect56 from "effect/Effect";
|
|
3629
|
+
var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
|
|
3630
|
+
var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
|
|
3140
3631
|
var body6 = (props) => ({
|
|
3141
3632
|
...props.bridge === undefined ? {} : { bridge: props.bridge },
|
|
3142
3633
|
...props.dns === undefined ? {} : { dns: props.dns },
|
|
@@ -3155,7 +3646,7 @@ var clearable = {
|
|
|
3155
3646
|
vlan: ["dns", "dnszone", "ipam", "mtu", "nodes"],
|
|
3156
3647
|
vxlan: ["dns", "dnszone", "ipam", "mtu", "nodes"]
|
|
3157
3648
|
};
|
|
3158
|
-
var
|
|
3649
|
+
var handlers28 = pveHandlers({
|
|
3159
3650
|
readRole: "provision",
|
|
3160
3651
|
attributes: (live, props) => {
|
|
3161
3652
|
const liveType = text(live["type"]);
|
|
@@ -3186,31 +3677,31 @@ var handlers25 = pveHandlers({
|
|
|
3186
3677
|
return withClears(fields, clear);
|
|
3187
3678
|
}
|
|
3188
3679
|
});
|
|
3189
|
-
var ProxmoxSdnZoneProvider = () =>
|
|
3680
|
+
var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect56.succeed(ProxmoxSdnZone.Provider.of(handlers28)));
|
|
3190
3681
|
// src/proxmox/storage.ts
|
|
3191
|
-
import { Resource as
|
|
3192
|
-
import * as
|
|
3193
|
-
import * as
|
|
3194
|
-
var ProxmoxStorage =
|
|
3682
|
+
import { Resource as Resource34 } from "alchemy";
|
|
3683
|
+
import * as Provider34 from "alchemy/Provider";
|
|
3684
|
+
import * as Effect57 from "effect/Effect";
|
|
3685
|
+
var ProxmoxStorage = Resource34("Proxmox.Storage", {
|
|
3195
3686
|
defaultRemovalPolicy: "retain"
|
|
3196
3687
|
});
|
|
3197
3688
|
var str3 = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
3198
|
-
var
|
|
3689
|
+
var field6 = (name, value) => value === undefined ? {} : { [name]: value };
|
|
3199
3690
|
var locatorForm = (locator) => ({ ...locator });
|
|
3200
3691
|
var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
|
|
3201
|
-
var sameList2 = (
|
|
3202
|
-
var
|
|
3692
|
+
var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
|
|
3693
|
+
var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
|
|
3203
3694
|
var mutable2 = (props) => ({
|
|
3204
|
-
...
|
|
3205
|
-
...
|
|
3206
|
-
...
|
|
3207
|
-
...
|
|
3208
|
-
...
|
|
3209
|
-
...
|
|
3210
|
-
...
|
|
3211
|
-
...
|
|
3212
|
-
});
|
|
3213
|
-
var
|
|
3695
|
+
...field6("comment", props.comment),
|
|
3696
|
+
...field6("content", props.content),
|
|
3697
|
+
...field6("disable", flag(props.disable)),
|
|
3698
|
+
...field6("maxfiles", props.maxfiles === undefined ? undefined : String(props.maxfiles)),
|
|
3699
|
+
...field6("nodes", props.nodes),
|
|
3700
|
+
...field6("preallocation", props.preallocation),
|
|
3701
|
+
...field6("prune-backups", props["prune-backups"]),
|
|
3702
|
+
...field6("shared", flag(props.shared))
|
|
3703
|
+
});
|
|
3704
|
+
var handlers29 = pveHandlers({
|
|
3214
3705
|
readRole: "provision",
|
|
3215
3706
|
attributes: (live, props) => ({
|
|
3216
3707
|
comment: str3(live["comment"]),
|
|
@@ -3231,18 +3722,18 @@ var handlers26 = pveHandlers({
|
|
|
3231
3722
|
storage: props.storage,
|
|
3232
3723
|
type: props.type
|
|
3233
3724
|
}),
|
|
3234
|
-
matches: (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) &&
|
|
3725
|
+
matches: (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) && same7(props.maxfiles, attributes2.maxfiles),
|
|
3235
3726
|
path: (props) => `storage/${props.storage}`,
|
|
3236
3727
|
updateForm: mutable2
|
|
3237
3728
|
});
|
|
3238
|
-
var ProxmoxStorageProvider = () =>
|
|
3729
|
+
var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect57.succeed(ProxmoxStorage.Provider.of(handlers29)));
|
|
3239
3730
|
// src/proxmox/zfs-pool.ts
|
|
3240
|
-
import { Resource as
|
|
3241
|
-
import * as
|
|
3242
|
-
import * as
|
|
3731
|
+
import { Resource as Resource35 } from "alchemy";
|
|
3732
|
+
import * as Provider35 from "alchemy/Provider";
|
|
3733
|
+
import * as Effect59 from "effect/Effect";
|
|
3243
3734
|
|
|
3244
3735
|
// src/proxmox/zfs-pool-write.ts
|
|
3245
|
-
import * as
|
|
3736
|
+
import * as Effect58 from "effect/Effect";
|
|
3246
3737
|
var createForm6 = (props) => ({
|
|
3247
3738
|
devices: props.devices.join(","),
|
|
3248
3739
|
name: props.name,
|
|
@@ -3252,28 +3743,28 @@ var createForm6 = (props) => ({
|
|
|
3252
3743
|
...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
|
|
3253
3744
|
});
|
|
3254
3745
|
var SETTLE_ATTEMPTS = 30;
|
|
3255
|
-
var createPool = (props, collection2,
|
|
3746
|
+
var createPool = (props, collection2, path2, read4) => Effect58.gen(function* () {
|
|
3256
3747
|
const existing = yield* read4(props);
|
|
3257
3748
|
if (existing !== undefined)
|
|
3258
3749
|
return existing;
|
|
3259
3750
|
const upid = yield* pve(props.target, "provision", "POST", collection2, createForm6(props));
|
|
3260
|
-
const settle4 = (attempts) =>
|
|
3751
|
+
const settle4 = (attempts) => Effect58.gen(function* () {
|
|
3261
3752
|
const live = yield* read4(props);
|
|
3262
3753
|
if (live !== undefined || attempts <= 0)
|
|
3263
3754
|
return live;
|
|
3264
|
-
yield*
|
|
3755
|
+
yield* Effect58.sleep("2 seconds");
|
|
3265
3756
|
return yield* settle4(attempts - 1);
|
|
3266
3757
|
});
|
|
3267
3758
|
const after = yield* settle4(SETTLE_ATTEMPTS);
|
|
3268
3759
|
if (after === undefined) {
|
|
3269
|
-
return yield*
|
|
3760
|
+
return yield* Effect58.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."));
|
|
3270
3761
|
}
|
|
3271
3762
|
return after;
|
|
3272
3763
|
});
|
|
3273
|
-
var destroyPool = (olds,
|
|
3764
|
+
var destroyPool = (olds, path2) => pve(olds.target, "provision", "DELETE", path2);
|
|
3274
3765
|
|
|
3275
3766
|
// src/proxmox/zfs-pool.ts
|
|
3276
|
-
var ProxmoxZfsPool =
|
|
3767
|
+
var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
|
|
3277
3768
|
defaultRemovalPolicy: "retain"
|
|
3278
3769
|
});
|
|
3279
3770
|
var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
|
|
@@ -3299,19 +3790,23 @@ var spec2 = {
|
|
|
3299
3790
|
path: (props) => `nodes/${props.node}/disks/zfs/${props.name}`
|
|
3300
3791
|
};
|
|
3301
3792
|
var ops5 = pveOperations(spec2);
|
|
3302
|
-
var
|
|
3793
|
+
var handlers30 = {
|
|
3303
3794
|
...pveHandlers(spec2),
|
|
3304
|
-
delete:
|
|
3795
|
+
delete: Effect59.fn(function* ({ olds }) {
|
|
3305
3796
|
yield* destroyPool(olds, spec2.path(olds));
|
|
3306
3797
|
}),
|
|
3307
3798
|
reconcile: ({ news }) => createPool(news, spec2.collection(news), spec2.path(news), ops5.read)
|
|
3308
3799
|
};
|
|
3309
|
-
var ProxmoxZfsPoolProvider = () =>
|
|
3800
|
+
var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect59.succeed(ProxmoxZfsPool.Provider.of(handlers30)));
|
|
3310
3801
|
export {
|
|
3311
3802
|
PROVISION_DEFAULTS,
|
|
3312
3803
|
PROVISION_PRIVILEGES,
|
|
3313
3804
|
PbsDatastore,
|
|
3314
3805
|
PbsDatastoreProvider,
|
|
3806
|
+
PbsNotificationMatcher,
|
|
3807
|
+
PbsNotificationMatcherProvider,
|
|
3808
|
+
PbsNotificationTarget,
|
|
3809
|
+
PbsNotificationTargetProvider,
|
|
3315
3810
|
PbsPruneJob,
|
|
3316
3811
|
PbsPruneJobProvider,
|
|
3317
3812
|
PbsSyncJob,
|
|
@@ -3342,6 +3837,8 @@ export {
|
|
|
3342
3837
|
ProxmoxMetricServerProvider,
|
|
3343
3838
|
ProxmoxNetworkApplyProvider,
|
|
3344
3839
|
ProxmoxNodeNetworkProvider,
|
|
3840
|
+
ProxmoxNotificationMatcher,
|
|
3841
|
+
ProxmoxNotificationMatcherProvider,
|
|
3345
3842
|
ProxmoxNotificationTarget,
|
|
3346
3843
|
ProxmoxNotificationTargetProvider,
|
|
3347
3844
|
ProxmoxPool,
|
|
@@ -3363,10 +3860,11 @@ export {
|
|
|
3363
3860
|
ProxmoxUserProvider,
|
|
3364
3861
|
ProxmoxVmProvider,
|
|
3365
3862
|
ProxmoxZfsPoolProvider,
|
|
3863
|
+
alertmanagerAlertBody,
|
|
3366
3864
|
declareProvisionBaseline,
|
|
3367
3865
|
provisionBaseline,
|
|
3368
3866
|
provisionBootstrap
|
|
3369
3867
|
};
|
|
3370
3868
|
|
|
3371
|
-
//# debugId=
|
|
3869
|
+
//# debugId=98691C143D2F953764756E2164756E21
|
|
3372
3870
|
//# sourceMappingURL=index.js.map
|