@homeflare/distilled-proxmox 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -5
- package/dist/config-not-found.test.js +29 -0
- package/dist/config-not-found.test.js.map +1 -1
- package/dist/lxc-config-errors.test.d.ts +2 -0
- package/dist/lxc-config-errors.test.d.ts.map +1 -0
- package/dist/lxc-config-errors.test.js +48 -0
- package/dist/lxc-config-errors.test.js.map +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +14 -8
- package/dist/protocol.js.map +1 -1
- package/dist/replication-firewall-errors.test.d.ts +2 -0
- package/dist/replication-firewall-errors.test.d.ts.map +1 -0
- package/dist/replication-firewall-errors.test.js +76 -0
- package/dist/replication-firewall-errors.test.js.map +1 -0
- package/dist/services/cluster.d.ts +25 -5
- package/dist/services/cluster.d.ts.map +1 -1
- package/dist/services/cluster.js +24 -5
- package/dist/services/cluster.js.map +1 -1
- package/dist/services/nodes.d.ts +25 -5
- package/dist/services/nodes.d.ts.map +1 -1
- package/dist/services/nodes.js +24 -5
- package/dist/services/nodes.js.map +1 -1
- package/package.json +1 -1
- package/src/config-not-found.test.ts +49 -0
- package/src/lxc-config-errors.test.ts +100 -0
- package/src/protocol.ts +16 -8
- package/src/replication-firewall-errors.test.ts +126 -0
- package/src/services/cluster.ts +51 -10
- package/src/services/nodes.ts +39 -10
package/README.md
CHANGED
|
@@ -37,16 +37,25 @@ operations the vendor schema itself marks `proxyto: "node"`.
|
|
|
37
37
|
Task polling belongs in the Alchemy provider: the SDK exports the generated
|
|
38
38
|
`getNodeTaskStatus` operation, and the caller owns its bound and failure policy.
|
|
39
39
|
|
|
40
|
-
Pool, backup-job
|
|
40
|
+
Pool, backup-job, metric-server and network-interface missing reads expose precise typed tags
|
|
41
41
|
from vendor source at pve-manager 9.2.11. Backup-job absence uses a sole nested
|
|
42
|
-
`errors.id
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
`errors.id`; network-interface absence uses the exact sole `errors.iface` — on both its
|
|
43
|
+
detail GET and its PUT (both call the same vendor check; DELETE raises it too but is
|
|
44
|
+
deliberately left untyped, tracked separately). Both use the parameter-verification
|
|
45
|
+
envelope; other validation errors retain their structured failure. PVE form arrays use
|
|
46
|
+
repeated keys, preserving commas within a rule/property value. Scalar comma lists and
|
|
47
|
+
query binding are unchanged. Protocol fixtures exercise both the accepted and rejected
|
|
48
|
+
shapes.
|
|
46
49
|
|
|
47
50
|
`PoolNotFound` keeps a non-retryable client-error category despite PVE's wire
|
|
48
51
|
status 500; the patch matcher records the actual status independently.
|
|
49
52
|
|
|
53
|
+
Container config GET, PUT and DELETE also expose `LxcConfigNotFound`, backed by
|
|
54
|
+
installed pve-container 6.1.13 and libpve-guest-common-perl 6.0.5 source — all three
|
|
55
|
+
call the same `load_config` and raise byte-identical text. This proves only the
|
|
56
|
+
node-local config is missing: providers must still check the cluster-wide vmid
|
|
57
|
+
with the same credential before considering creation.
|
|
58
|
+
|
|
50
59
|
```ts
|
|
51
60
|
import * as Proxmox from '@distilled.cloud/proxmox'; // aliased onto this package — see docs/distilled-interim.md
|
|
52
61
|
import * as Effect from 'effect/Effect';
|
|
@@ -69,6 +78,19 @@ Kit code never imports `@homeflare/distilled-proxmox` directly — always
|
|
|
69
78
|
so the eventual cutover to the real published package is a one-line alias
|
|
70
79
|
swap with no import changes anywhere in the kit.
|
|
71
80
|
|
|
81
|
+
## Source provenance
|
|
82
|
+
|
|
83
|
+
This SDK source matches local distilled commit
|
|
84
|
+
`07d587885b198e85bdd5b37ce3c7406c7b29c0ba` byte for byte. Its patch chain adds
|
|
85
|
+
precise interface, container-config, replication-job and firewall-alias absence
|
|
86
|
+
without treating unrelated validation or server failures as missing resources.
|
|
87
|
+
The patch files record pinned PVE 9.2.11 and installed package versions/hashes.
|
|
88
|
+
|
|
89
|
+
`ReplicationJobNotFound` covers the vendor's read/update/delete exceptions;
|
|
90
|
+
ordinary DELETE still marks asynchronous cleanup without force or keep.
|
|
91
|
+
`FirewallAliasNotFound` covers only the exact sole-field validation error on
|
|
92
|
+
GET/PUT. Alias DELETE is already idempotent, so other failures propagate.
|
|
93
|
+
|
|
72
94
|
## Updating it
|
|
73
95
|
|
|
74
96
|
From the distilled clone's `homeflare/proxmox` worktree:
|
|
@@ -8,6 +8,7 @@ import { credentials } from "./credentials.js";
|
|
|
8
8
|
import * as Retry from "./retry.js";
|
|
9
9
|
import * as pools from "./services/pools.js";
|
|
10
10
|
import * as cluster from "./services/cluster.js";
|
|
11
|
+
import * as nodes from "./services/nodes.js";
|
|
11
12
|
const call = (op, status, body) => Effect.runPromise(op.pipe(Retry.none, Effect.provide(credentials({
|
|
12
13
|
baseUrl: "https://pve.test:8006",
|
|
13
14
|
tokenId: "test@pve!test",
|
|
@@ -92,5 +93,33 @@ describe("precise config absence tags", () => {
|
|
|
92
93
|
errors: { id: "No such job 'absent'" },
|
|
93
94
|
})).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
94
95
|
});
|
|
96
|
+
test("network absence is the exact sole iface error on GET and PUT", async () => {
|
|
97
|
+
const body = {
|
|
98
|
+
data: null,
|
|
99
|
+
message: "Parameter verification failed.\n",
|
|
100
|
+
errors: { iface: "interface does not exist" },
|
|
101
|
+
};
|
|
102
|
+
expect(await call(nodes.getNodeNetwork({ node: "n2", iface: "vmbr9" }), 400, body)).toMatchObject({ _tag: "NetworkInterfaceNotFound" });
|
|
103
|
+
// ⛔ RETAG REGRESSION'S OWN CASE — PVE's `update_network` (PUT) raises the byte-identical
|
|
104
|
+
// 400 (Network.pm:750) that `network_config` (GET) raises (:852); a consumer's catchTag
|
|
105
|
+
// keyed on this tag must see the same absence signal from either operation.
|
|
106
|
+
expect(await call(nodes.putNodeNetwork2({ node: "n2", iface: "vmbr9", type: "bridge" }), 400, body)).toMatchObject({ _tag: "NetworkInterfaceNotFound" });
|
|
107
|
+
for (const errors of [
|
|
108
|
+
{ iface: "invalid interface name" },
|
|
109
|
+
{ iface: "interface does not exist", type: "invalid type" },
|
|
110
|
+
{ other: "interface does not exist" },
|
|
111
|
+
]) {
|
|
112
|
+
expect(await call(nodes.getNodeNetwork({ node: "n2", iface: "vmbr9" }), 400, {
|
|
113
|
+
...body,
|
|
114
|
+
errors,
|
|
115
|
+
})).toMatchObject({ _tag: "ParameterVerificationFailed", errors });
|
|
116
|
+
}
|
|
117
|
+
for (const [status, tag] of [
|
|
118
|
+
[403, "Forbidden"],
|
|
119
|
+
[500, "InternalServerError"],
|
|
120
|
+
]) {
|
|
121
|
+
expect(await call(nodes.getNodeNetwork({ node: "n2", iface: "vmbr9" }), status, body)).toMatchObject({ _tag: tag });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
95
124
|
});
|
|
96
125
|
//# sourceMappingURL=config-not-found.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-not-found.test.js","sourceRoot":"","sources":["../src/config-not-found.test.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAC9D,OAAO,KAAK,kBAAkB,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"config-not-found.test.js","sourceRoot":"","sources":["../src/config-not-found.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lxc-config-errors.test.d.ts","sourceRoot":"","sources":["../src/lxc-config-errors.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exact installed pve-container6.1.13/libpve-guest-common-perl6.0.5 absence; never generic500.
|
|
3
|
+
* ⛔ ATTACHED TO GET, PUT AND DELETE — all three call `AbstractConfig::load_config` first
|
|
4
|
+
* (patches/nodes/lxc-config-errors.json's own provenance) and raise byte-identical text; a
|
|
5
|
+
* PUT/DELETE against a container config a caller believes exists gets the same typed absence
|
|
6
|
+
* a GET would, not a generic 500 a retry policy or catchTag could mistake for transient.
|
|
7
|
+
*/
|
|
8
|
+
import { expect, test } from "bun:test";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
11
|
+
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
12
|
+
import { credentials } from "./credentials.js";
|
|
13
|
+
import * as Retry from "./retry.js";
|
|
14
|
+
import * as nodes from "./services/nodes.js";
|
|
15
|
+
const missing = "Configuration file 'nodes/pve-test/lxc/900.conf' does not exist\n";
|
|
16
|
+
const call = (op, status, message) => Effect.runPromise(op.pipe(Retry.none, Effect.provide(credentials({
|
|
17
|
+
baseUrl: "https://pve.test:8006",
|
|
18
|
+
tokenId: "test@pve!test",
|
|
19
|
+
secret: "fake",
|
|
20
|
+
})), Effect.provideService(HttpClient.HttpClient, HttpClient.make((request) => Effect.succeed(HttpClientResponse.fromWeb(request, Response.json({ data: null, message }, { status }))))), Effect.flip));
|
|
21
|
+
test("only exact container-config absence on GET becomes LxcConfigNotFound", async () => {
|
|
22
|
+
const get = () => nodes.getNodeLxcConfig({ node: "pve-test", vmid: "900" });
|
|
23
|
+
expect(await call(get(), 500, missing)).toMatchObject({
|
|
24
|
+
_tag: "LxcConfigNotFound",
|
|
25
|
+
});
|
|
26
|
+
for (const message of [
|
|
27
|
+
undefined,
|
|
28
|
+
"got timeout\n",
|
|
29
|
+
missing.replace("lxc", "qemu-server"),
|
|
30
|
+
missing + "other error",
|
|
31
|
+
]) {
|
|
32
|
+
expect(await call(get(), 500, message)).toMatchObject({
|
|
33
|
+
_tag: "InternalServerError",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
expect(await call(get(), 403, missing)).toMatchObject({ _tag: "Forbidden" });
|
|
37
|
+
});
|
|
38
|
+
test("the same exact absence on PUT and DELETE also becomes LxcConfigNotFound", async () => {
|
|
39
|
+
expect(await call(nodes.putNodeLxcConfig({ node: "pve-test", vmid: "900" }), 500, missing)).toMatchObject({ _tag: "LxcConfigNotFound" });
|
|
40
|
+
expect(await call(nodes.deleteNodeLxc({ node: "pve-test", vmid: "900" }), 500, missing)).toMatchObject({ _tag: "LxcConfigNotFound" });
|
|
41
|
+
// ⛔ STILL NOT ABSENCE ON PUT/DELETE EITHER — a generic failure on the write paths must stay
|
|
42
|
+
// generic, exactly like the GET-only assertions above.
|
|
43
|
+
for (const message of ["got timeout\n", missing + "other error"]) {
|
|
44
|
+
expect(await call(nodes.putNodeLxcConfig({ node: "pve-test", vmid: "900" }), 500, message)).toMatchObject({ _tag: "InternalServerError" });
|
|
45
|
+
expect(await call(nodes.deleteNodeLxc({ node: "pve-test", vmid: "900" }), 500, message)).toMatchObject({ _tag: "InternalServerError" });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=lxc-config-errors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lxc-config-errors.test.js","sourceRoot":"","sources":["../src/lxc-config-errors.test.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAoEA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,KAAK,eAAe,MAAM,sCAAsC,CAAC;AAC7E,OAAO,KAAK,KAAK,GAAG,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EAAE,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GACtB,aAAa,GACb,WAAW,GACX,eAAe,CAAC,eAAe,CAAC;AAEpC,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAoEA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,KAAK,eAAe,MAAM,sCAAsC,CAAC;AAC7E,OAAO,KAAK,KAAK,GAAG,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EAAE,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GACtB,aAAa,GACb,WAAW,GACX,eAAe,CAAC,eAAe,CAAC;AAEpC,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;AAuDnE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CA4ErD,CAAC"}
|
package/dist/protocol.js
CHANGED
|
@@ -84,9 +84,9 @@ const errorEnvelope = (body) => {
|
|
|
84
84
|
if (body === null || typeof body !== "object")
|
|
85
85
|
return undefined;
|
|
86
86
|
const b = body;
|
|
87
|
-
// PVE
|
|
88
|
-
//
|
|
89
|
-
// ONLY
|
|
87
|
+
// PVE missing backup/interface/alias exceptions carry the useful message in one
|
|
88
|
+
// field (Backup.pm:406,458; Network.pm:852; Firewall/Aliases.pm:203). Expose
|
|
89
|
+
// ONLY those exact sole-field details to the operation's typed matcher.
|
|
90
90
|
// Multiple errors, other fields, and unrelated validation stay unchanged.
|
|
91
91
|
const errors = b.errors;
|
|
92
92
|
if ((b.message === "Parameter verification failed." ||
|
|
@@ -94,11 +94,17 @@ const errorEnvelope = (body) => {
|
|
|
94
94
|
errors !== null &&
|
|
95
95
|
typeof errors === "object" &&
|
|
96
96
|
!Array.isArray(errors) &&
|
|
97
|
-
Object.keys(errors).length === 1
|
|
98
|
-
"id" in errors &&
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
Object.keys(errors).length === 1) {
|
|
98
|
+
if ("id" in errors &&
|
|
99
|
+
typeof errors.id === "string" &&
|
|
100
|
+
/^No such job '[^']+'$/.test(errors.id))
|
|
101
|
+
return { message: errors.id };
|
|
102
|
+
if ("name" in errors && errors.name === "no such alias") {
|
|
103
|
+
return { message: errors.name };
|
|
104
|
+
}
|
|
105
|
+
if ("iface" in errors && errors.iface === "interface does not exist") {
|
|
106
|
+
return { message: errors.iface };
|
|
107
|
+
}
|
|
102
108
|
}
|
|
103
109
|
return { message: typeof b.message === "string" ? b.message : undefined };
|
|
104
110
|
};
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAI5C,OAAO,EACL,UAAU,EACV,eAAe,GAEhB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,gBAAgB,GAEjB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AAgBrB;;;;;;;GAOG;AACH,MAAM,aAAa,GAAG,CAAC,IAAa,EAAiC,EAAE;IACrE,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChE,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replication-firewall-errors.test.d.ts","sourceRoot":"","sources":["../src/replication-firewall-errors.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** Exact vendor exceptions at the real protocol boundary; source provenance is in patches. */
|
|
2
|
+
import { expect, test } from "bun:test";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
5
|
+
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
6
|
+
import { credentials } from "./credentials.js";
|
|
7
|
+
import * as Retry from "./retry.js";
|
|
8
|
+
import * as cluster from "./services/cluster.js";
|
|
9
|
+
const call = (op, status, body) => Effect.runPromise(op.pipe(Retry.none, Effect.provide(credentials({
|
|
10
|
+
baseUrl: "https://pve.test:8006",
|
|
11
|
+
tokenId: "test@pve!test",
|
|
12
|
+
secret: "fake",
|
|
13
|
+
})), Effect.provideService(HttpClient.HttpClient, HttpClient.make((request) => Effect.succeed(HttpClientResponse.fromWeb(request, Response.json(body, { status }))))), Effect.flip));
|
|
14
|
+
for (const [op, message] of [
|
|
15
|
+
[
|
|
16
|
+
cluster.getClusterReplication({ id: "900-0" }),
|
|
17
|
+
"no such replication job '900-0'\n",
|
|
18
|
+
],
|
|
19
|
+
[cluster.putClusterReplication({ id: "900-0" }), "no such job '900-0'\n"],
|
|
20
|
+
[cluster.deleteClusterReplication({ id: "900-0" }), "no such job '900-0'\n"],
|
|
21
|
+
]) {
|
|
22
|
+
test(`replication ${message.trim()} is typed only on its vendor status`, async () => {
|
|
23
|
+
expect(await call(op, 500, { data: null, message })).toMatchObject({
|
|
24
|
+
_tag: "ReplicationJobNotFound",
|
|
25
|
+
});
|
|
26
|
+
expect(await call(op, 403, { data: null, message })).toMatchObject({
|
|
27
|
+
_tag: "Forbidden",
|
|
28
|
+
});
|
|
29
|
+
for (const other of [
|
|
30
|
+
undefined,
|
|
31
|
+
"no such job 'unrelated'\n",
|
|
32
|
+
message + "other failure",
|
|
33
|
+
"got timeout\n",
|
|
34
|
+
]) {
|
|
35
|
+
expect(await call(op, 500, { data: null, message: other })).toMatchObject({ _tag: "InternalServerError" });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const missingAlias = {
|
|
40
|
+
data: null,
|
|
41
|
+
message: "Parameter verification failed.\n",
|
|
42
|
+
errors: { name: "no such alias" },
|
|
43
|
+
};
|
|
44
|
+
for (const op of [
|
|
45
|
+
cluster.getClusterFirewallAlias({ name: "test" }),
|
|
46
|
+
cluster.putClusterFirewallAlias({ name: "test", cidr: "192.0.2.1" }),
|
|
47
|
+
]) {
|
|
48
|
+
test("alias requires the sole exact errors.name detail", async () => {
|
|
49
|
+
expect(await call(op, 400, missingAlias)).toMatchObject({
|
|
50
|
+
_tag: "FirewallAliasNotFound",
|
|
51
|
+
});
|
|
52
|
+
expect(await call(op, 403, missingAlias)).toMatchObject({
|
|
53
|
+
_tag: "Forbidden",
|
|
54
|
+
});
|
|
55
|
+
for (const errors of [
|
|
56
|
+
{ name: "no such alias", cidr: "invalid" },
|
|
57
|
+
{ other: "no such alias" },
|
|
58
|
+
{ name: "invalid alias" },
|
|
59
|
+
]) {
|
|
60
|
+
expect(await call(op, 400, { ...missingAlias, errors })).toMatchObject({
|
|
61
|
+
_tag: "ParameterVerificationFailed",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
expect(await call(op, 400, { ...missingAlias, message: "unrelated validation" })).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
test("absence patches do not classify unrelated operations", async () => {
|
|
68
|
+
expect(await call(cluster.createClusterFirewallAlias({ name: "test", cidr: "192.0.2.1" }), 400, missingAlias)).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
69
|
+
expect(await call(cluster.deleteClusterFirewallAlias({ name: "test" }), 400, missingAlias)).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
70
|
+
expect(await call(cluster.createClusterReplication({
|
|
71
|
+
id: "900-0",
|
|
72
|
+
target: "pve-b",
|
|
73
|
+
type: "local",
|
|
74
|
+
}), 500, { message: "no such job '900-0'\n" })).toMatchObject({ _tag: "InternalServerError" });
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=replication-firewall-errors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replication-firewall-errors.test.js","sourceRoot":"","sources":["../src/replication-firewall-errors.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,16 @@ declare const BackupJobNotFound_base: S.Class<BackupJobNotFound, S.TaggedStruct<
|
|
|
12
12
|
/** The backup job does not exist. pve-manager 9.2.11, f6997e698c7933ea8e62319e2bf1bf7262daa56a, PVE/API2/Backup.pm:406,458,755 raises a 400 parameter exception with exactly errors.id = No such job '<id>'. The Proxmox protocol extracts that sole precise detail for matching; unrelated or multi-field validation errors never become absence. Update uses a different exception and is deliberately not attached. */
|
|
13
13
|
export declare class BackupJobNotFound extends /*@__PURE__*/ BackupJobNotFound_base {
|
|
14
14
|
}
|
|
15
|
+
declare const FirewallAliasNotFound_base: S.Class<FirewallAliasNotFound, S.TaggedStruct<"FirewallAliasNotFound", {
|
|
16
|
+
readonly message: any;
|
|
17
|
+
}>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
|
|
18
|
+
"@distilled.cloud/error/categories": {
|
|
19
|
+
BadRequestError: true;
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
/** Installed pve-firewall 6.0.5 PVE/API2/Firewall/Aliases.pm:203-204,252, read-only 2026-09-24; SHA256 aa4d71ea897515ca71caa8e04abd142aedf8077058649f793605f014be84db0e. GET and PUT raise HTTP400 Parameter verification failed with the sole field errors.name = no such alias. DELETE is intrinsically idempotent and has no missing-alias exception. Other validation failures remain ParameterVerificationFailed. */
|
|
23
|
+
export declare class FirewallAliasNotFound extends /*@__PURE__*/ FirewallAliasNotFound_base {
|
|
24
|
+
}
|
|
15
25
|
declare const MetricServerNotFound_base: S.Class<MetricServerNotFound, S.TaggedStruct<"MetricServerNotFound", {
|
|
16
26
|
readonly message: any;
|
|
17
27
|
}>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
|
|
@@ -22,6 +32,16 @@ declare const MetricServerNotFound_base: S.Class<MetricServerNotFound, S.TaggedS
|
|
|
22
32
|
/** The metrics server does not exist. pve-manager 9.2.11, f6997e698c7933ea8e62319e2bf1bf7262daa56a, PVE/API2/Cluster/MetricServer.pm:136 throws status server entry '<id>' does not exist on GET, and line 228 throws no such server '<id>' on PUT. Both are wire 500. DELETE dereferences the plugin config without an explicit absence check and is not declared to return this tag. */
|
|
23
33
|
export declare class MetricServerNotFound extends /*@__PURE__*/ MetricServerNotFound_base {
|
|
24
34
|
}
|
|
35
|
+
declare const ReplicationJobNotFound_base: S.Class<ReplicationJobNotFound, S.TaggedStruct<"ReplicationJobNotFound", {
|
|
36
|
+
readonly message: any;
|
|
37
|
+
}>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
|
|
38
|
+
"@distilled.cloud/error/categories": {
|
|
39
|
+
BadRequestError: true;
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
/** pve-manager 9.2.11 f6997e698c7933ea8e62319e2bf1bf7262daa56a PVE/API2/ReplicationConfig.pm:107,226,305. GET raises no such replication job; PUT and non-force DELETE raise no such job. Exact structured job IDs only. DELETE normally marks remove_job=full for background cleanup; an absent job is already removed. */
|
|
43
|
+
export declare class ReplicationJobNotFound extends /*@__PURE__*/ ReplicationJobNotFound_base {
|
|
44
|
+
}
|
|
25
45
|
export interface CreateClusterAcmeAccountRequest {
|
|
26
46
|
/** Contact email addresses. */
|
|
27
47
|
contact: string;
|
|
@@ -5357,7 +5377,7 @@ export declare const deleteClusterNotificationMatcher: API.OperationMethod<Delet
|
|
|
5357
5377
|
export type DeleteClusterQemuCustomCpuModelError = ProxmoxOpError;
|
|
5358
5378
|
/** Delete a custom CPU model definition. (root-privileged endpoint) */
|
|
5359
5379
|
export declare const deleteClusterQemuCustomCpuModel: API.OperationMethod<DeleteClusterQemuCustomCpuModelRequest, DeleteClusterQemuCustomCpuModelResponse, DeleteClusterQemuCustomCpuModelError, ProxmoxOpContext>;
|
|
5360
|
-
export type DeleteClusterReplicationError = ProxmoxOpError;
|
|
5380
|
+
export type DeleteClusterReplicationError = ReplicationJobNotFound | ProxmoxOpError;
|
|
5361
5381
|
/** Mark replication job for removal. (root-privileged endpoint) */
|
|
5362
5382
|
export declare const deleteClusterReplication: API.OperationMethod<DeleteClusterReplicationRequest, DeleteClusterReplicationResponse, DeleteClusterReplicationError, ProxmoxOpContext>;
|
|
5363
5383
|
export type DeleteClusterSdnControllerError = ProxmoxOpError;
|
|
@@ -5441,7 +5461,7 @@ export declare const getClusterConfigQdevice: API.OperationMethod<GetClusterConf
|
|
|
5441
5461
|
export type GetClusterConfigTotemError = ProxmoxOpError;
|
|
5442
5462
|
/** Get corosync totem protocol settings. */
|
|
5443
5463
|
export declare const getClusterConfigTotem: API.OperationMethod<GetClusterConfigTotemRequest, GetClusterConfigTotemResponse, GetClusterConfigTotemError, ProxmoxOpContext>;
|
|
5444
|
-
export type GetClusterFirewallAliasError = ProxmoxOpError;
|
|
5464
|
+
export type GetClusterFirewallAliasError = FirewallAliasNotFound | ProxmoxOpError;
|
|
5445
5465
|
/** Read alias. */
|
|
5446
5466
|
export declare const getClusterFirewallAlias: API.OperationMethod<GetClusterFirewallAliasRequest, GetClusterFirewallAliasResponse, GetClusterFirewallAliasError, ProxmoxOpContext>;
|
|
5447
5467
|
export type GetClusterFirewallGroupError = ProxmoxOpError;
|
|
@@ -5516,7 +5536,7 @@ export declare const getClusterOptions: API.OperationMethod<GetClusterOptionsReq
|
|
|
5516
5536
|
export type GetClusterQemuCustomCpuModelError = ProxmoxOpError;
|
|
5517
5537
|
/** Retrieve details about a specific custom CPU model. */
|
|
5518
5538
|
export declare const getClusterQemuCustomCpuModel: API.OperationMethod<GetClusterQemuCustomCpuModelRequest, GetClusterQemuCustomCpuModelResponse, GetClusterQemuCustomCpuModelError, ProxmoxOpContext>;
|
|
5519
|
-
export type GetClusterReplicationError = ProxmoxOpError;
|
|
5539
|
+
export type GetClusterReplicationError = ReplicationJobNotFound | ProxmoxOpError;
|
|
5520
5540
|
/** Read replication job configuration. */
|
|
5521
5541
|
export declare const getClusterReplication: API.OperationMethod<GetClusterReplicationRequest, GetClusterReplicationResponse, GetClusterReplicationError, ProxmoxOpContext>;
|
|
5522
5542
|
export type GetClusterSdnControllerError = ProxmoxOpError;
|
|
@@ -5819,7 +5839,7 @@ export declare const putClusterCephFlags: API.OperationMethod<PutClusterCephFlag
|
|
|
5819
5839
|
export type PutClusterCephHealthMuteError = ProxmoxOpError;
|
|
5820
5840
|
/** Mute or unmute a Ceph health check. A muted check no longer counts towards the cluster status, but stays visible and keeps being evaluated. (root-privileged endpoint) */
|
|
5821
5841
|
export declare const putClusterCephHealthMute: API.OperationMethod<PutClusterCephHealthMuteRequest, PutClusterCephHealthMuteResponse, PutClusterCephHealthMuteError, ProxmoxOpContext>;
|
|
5822
|
-
export type PutClusterFirewallAliasError = ProxmoxOpError;
|
|
5842
|
+
export type PutClusterFirewallAliasError = FirewallAliasNotFound | ProxmoxOpError;
|
|
5823
5843
|
/** Update IP or Network alias. (root-privileged endpoint) */
|
|
5824
5844
|
export declare const putClusterFirewallAlias: API.OperationMethod<PutClusterFirewallAliasRequest, PutClusterFirewallAliasResponse, PutClusterFirewallAliasError, ProxmoxOpContext>;
|
|
5825
5845
|
export type PutClusterFirewallGroupError = ProxmoxOpError;
|
|
@@ -5879,7 +5899,7 @@ export declare const putClusterOptions: API.OperationMethod<PutClusterOptionsReq
|
|
|
5879
5899
|
export type PutClusterQemuCustomCpuModelError = ProxmoxOpError;
|
|
5880
5900
|
/** Update a custom CPU model definition. (root-privileged endpoint) */
|
|
5881
5901
|
export declare const putClusterQemuCustomCpuModel: API.OperationMethod<PutClusterQemuCustomCpuModelRequest, PutClusterQemuCustomCpuModelResponse, PutClusterQemuCustomCpuModelError, ProxmoxOpContext>;
|
|
5882
|
-
export type PutClusterReplicationError = ProxmoxOpError;
|
|
5902
|
+
export type PutClusterReplicationError = ReplicationJobNotFound | ProxmoxOpError;
|
|
5883
5903
|
/** Update replication job configuration. (root-privileged endpoint) */
|
|
5884
5904
|
export declare const putClusterReplication: API.OperationMethod<PutClusterReplicationRequest, PutClusterReplicationResponse, PutClusterReplicationError, ProxmoxOpContext>;
|
|
5885
5905
|
export type PutClusterSdnError = ProxmoxOpError;
|