@homeflare/distilled-proxmox 0.3.0 → 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 +37 -10
- package/dist/config-not-found.test.d.ts +2 -0
- package/dist/config-not-found.test.d.ts.map +1 -0
- package/dist/config-not-found.test.js +125 -0
- package/dist/config-not-found.test.js.map +1 -0
- package/dist/errors.d.ts +2 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.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-form.d.ts +18 -0
- package/dist/protocol-form.d.ts.map +1 -0
- package/dist/protocol-form.js +37 -0
- package/dist/protocol-form.js.map +1 -0
- package/dist/protocol-form.test.d.ts +2 -0
- package/dist/protocol-form.test.d.ts.map +1 -0
- package/dist/protocol-form.test.js +68 -0
- package/dist/protocol-form.test.js.map +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +25 -2
- 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 +50 -10
- package/dist/services/cluster.d.ts.map +1 -1
- package/dist/services/cluster.js +50 -10
- 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/dist/services/pools.d.ts +16 -6
- package/dist/services/pools.d.ts.map +1 -1
- package/dist/services/pools.js +18 -6
- package/dist/services/pools.js.map +1 -1
- package/package.json +1 -1
- package/src/config-not-found.test.ts +202 -0
- package/src/errors.ts +4 -12
- package/src/lxc-config-errors.test.ts +100 -0
- package/src/protocol-form.test.ts +102 -0
- package/src/protocol-form.ts +49 -0
- package/src/protocol.ts +30 -2
- package/src/replication-firewall-errors.test.ts +126 -0
- package/src/services/cluster.ts +97 -20
- package/src/services/nodes.ts +39 -10
- package/src/services/pools.ts +27 -12
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PVE's form arrays use repeated keys, never Stripe's indexed fields.
|
|
3
|
+
*
|
|
4
|
+
* PVE 9.2.11 notification schemas declare arrays (mailto, header, target,
|
|
5
|
+
* match-field, delete). The vendor UI submits repeated keys; its Perl
|
|
6
|
+
* URL-encoded decoder joins them with NUL before schema validation. The
|
|
7
|
+
* existing kit notification-target-form.ts records that decoder/UI evidence
|
|
8
|
+
* (2026-09-14); no production multi-header write was made for this fix.
|
|
9
|
+
*
|
|
10
|
+
* Keep core's credentials, labels, schema key mapping, and query encoding.
|
|
11
|
+
* Only top-level scalar list entries in a form body change: header[0]=a
|
|
12
|
+
* becomes header=a. A property-string item's commas remain inside the item.
|
|
13
|
+
* A scalar comma list, an embedded NUL, or a GET/DELETE query is unchanged.
|
|
14
|
+
*/
|
|
15
|
+
import * as API from "@distilled.cloud/core/api";
|
|
16
|
+
import * as Effect from "effect/Effect";
|
|
17
|
+
import * as Layer from "effect/Layer";
|
|
18
|
+
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
19
|
+
|
|
20
|
+
const repeatedFormKeys = (request: HttpClientRequest.HttpClientRequest) => {
|
|
21
|
+
if (
|
|
22
|
+
request.body._tag !== "Uint8Array" ||
|
|
23
|
+
request.body.contentType !== "application/x-www-form-urlencoded"
|
|
24
|
+
)
|
|
25
|
+
return request;
|
|
26
|
+
const fields = new URLSearchParams(
|
|
27
|
+
new TextDecoder().decode(request.body.body),
|
|
28
|
+
);
|
|
29
|
+
const repeated: [string, string][] = [];
|
|
30
|
+
for (const [key, value] of fields) {
|
|
31
|
+
repeated.push([key.replace(/^([^\[\]]+)\[\d+\]$/, "$1"), value]);
|
|
32
|
+
}
|
|
33
|
+
return HttpClientRequest.bodyUrlParams(request, repeated);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const withPveFormArrays = (
|
|
37
|
+
base: Layer.Layer<API.Protocol>,
|
|
38
|
+
): Layer.Layer<API.Protocol> =>
|
|
39
|
+
Layer.effect(
|
|
40
|
+
API.Protocol,
|
|
41
|
+
Effect.gen(function* () {
|
|
42
|
+
const protocol = yield* API.Protocol;
|
|
43
|
+
return API.Protocol.of({
|
|
44
|
+
...protocol,
|
|
45
|
+
encode: (args) =>
|
|
46
|
+
protocol.encode(args).pipe(Effect.map(repeatedFormKeys)),
|
|
47
|
+
});
|
|
48
|
+
}),
|
|
49
|
+
).pipe(Layer.provide(base));
|
package/src/protocol.ts
CHANGED
|
@@ -81,6 +81,7 @@ import {
|
|
|
81
81
|
type RestErrorEnvelope,
|
|
82
82
|
} from "@distilled.cloud/core/protocol-rest";
|
|
83
83
|
import { Credentials, type Config } from "./credentials.ts";
|
|
84
|
+
import { withPveFormArrays } from "./protocol-form.ts";
|
|
84
85
|
import {
|
|
85
86
|
ParameterVerificationFailed,
|
|
86
87
|
UnknownProxmoxError,
|
|
@@ -112,6 +113,32 @@ export type ProxmoxOpContext = Credentials | HttpClient.HttpClient;
|
|
|
112
113
|
const errorEnvelope = (body: unknown): RestErrorEnvelope | undefined => {
|
|
113
114
|
if (body === null || typeof body !== "object") return undefined;
|
|
114
115
|
const b = body as Record<string, unknown>;
|
|
116
|
+
// PVE missing backup/interface/alias exceptions carry the useful message in one
|
|
117
|
+
// field (Backup.pm:406,458; Network.pm:852; Firewall/Aliases.pm:203). Expose
|
|
118
|
+
// ONLY those exact sole-field details to the operation's typed matcher.
|
|
119
|
+
// Multiple errors, other fields, and unrelated validation stay unchanged.
|
|
120
|
+
const errors = b.errors;
|
|
121
|
+
if (
|
|
122
|
+
(b.message === "Parameter verification failed." ||
|
|
123
|
+
b.message === "Parameter verification failed.\n") &&
|
|
124
|
+
errors !== null &&
|
|
125
|
+
typeof errors === "object" &&
|
|
126
|
+
!Array.isArray(errors) &&
|
|
127
|
+
Object.keys(errors).length === 1
|
|
128
|
+
) {
|
|
129
|
+
if (
|
|
130
|
+
"id" in errors &&
|
|
131
|
+
typeof errors.id === "string" &&
|
|
132
|
+
/^No such job '[^']+'$/.test(errors.id)
|
|
133
|
+
)
|
|
134
|
+
return { message: errors.id };
|
|
135
|
+
if ("name" in errors && errors.name === "no such alias") {
|
|
136
|
+
return { message: errors.name };
|
|
137
|
+
}
|
|
138
|
+
if ("iface" in errors && errors.iface === "interface does not exist") {
|
|
139
|
+
return { message: errors.iface };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
115
142
|
return { message: typeof b.message === "string" ? b.message : undefined };
|
|
116
143
|
};
|
|
117
144
|
|
|
@@ -128,7 +155,7 @@ const PROXMOX_STATUS_MAP: Record<number, new (args: any) => unknown> = {
|
|
|
128
155
|
};
|
|
129
156
|
delete (PROXMOX_STATUS_MAP as Record<number, unknown>)[400];
|
|
130
157
|
|
|
131
|
-
export const ProxmoxProtocol: Layer.Layer<API.Protocol> =
|
|
158
|
+
export const ProxmoxProtocol: Layer.Layer<API.Protocol> = withPveFormArrays(
|
|
132
159
|
makeRestProtocol<Config>({
|
|
133
160
|
// Resolved on the CALLING fiber per request (the layer is memoized per
|
|
134
161
|
// process); the Credentials service holds an effect, so a token rotated
|
|
@@ -203,4 +230,5 @@ export const ProxmoxProtocol: Layer.Layer<API.Protocol> =
|
|
|
203
230
|
}
|
|
204
231
|
return new UnknownProxmoxError({ status, message, body });
|
|
205
232
|
},
|
|
206
|
-
})
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
@@ -0,0 +1,126 @@
|
|
|
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.ts";
|
|
7
|
+
import type { ProxmoxOpContext } from "./protocol.ts";
|
|
8
|
+
import * as Retry from "./retry.ts";
|
|
9
|
+
import * as cluster from "./services/cluster.ts";
|
|
10
|
+
|
|
11
|
+
const call = <A, E>(
|
|
12
|
+
op: Effect.Effect<A, E, ProxmoxOpContext>,
|
|
13
|
+
status: number,
|
|
14
|
+
body: unknown,
|
|
15
|
+
) =>
|
|
16
|
+
Effect.runPromise(
|
|
17
|
+
op.pipe(
|
|
18
|
+
Retry.none,
|
|
19
|
+
Effect.provide(
|
|
20
|
+
credentials({
|
|
21
|
+
baseUrl: "https://pve.test:8006",
|
|
22
|
+
tokenId: "test@pve!test",
|
|
23
|
+
secret: "fake",
|
|
24
|
+
}),
|
|
25
|
+
),
|
|
26
|
+
Effect.provideService(
|
|
27
|
+
HttpClient.HttpClient,
|
|
28
|
+
HttpClient.make((request) =>
|
|
29
|
+
Effect.succeed(
|
|
30
|
+
HttpClientResponse.fromWeb(
|
|
31
|
+
request,
|
|
32
|
+
Response.json(body, { status }),
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
Effect.flip,
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
for (const [op, message] of [
|
|
42
|
+
[
|
|
43
|
+
cluster.getClusterReplication({ id: "900-0" }),
|
|
44
|
+
"no such replication job '900-0'\n",
|
|
45
|
+
],
|
|
46
|
+
[cluster.putClusterReplication({ id: "900-0" }), "no such job '900-0'\n"],
|
|
47
|
+
[cluster.deleteClusterReplication({ id: "900-0" }), "no such job '900-0'\n"],
|
|
48
|
+
] as const) {
|
|
49
|
+
test(`replication ${message.trim()} is typed only on its vendor status`, async () => {
|
|
50
|
+
expect(await call(op, 500, { data: null, message })).toMatchObject({
|
|
51
|
+
_tag: "ReplicationJobNotFound",
|
|
52
|
+
});
|
|
53
|
+
expect(await call(op, 403, { data: null, message })).toMatchObject({
|
|
54
|
+
_tag: "Forbidden",
|
|
55
|
+
});
|
|
56
|
+
for (const other of [
|
|
57
|
+
undefined,
|
|
58
|
+
"no such job 'unrelated'\n",
|
|
59
|
+
message + "other failure",
|
|
60
|
+
"got timeout\n",
|
|
61
|
+
]) {
|
|
62
|
+
expect(await call(op, 500, { data: null, message: other })).toMatchObject(
|
|
63
|
+
{ _tag: "InternalServerError" },
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const missingAlias = {
|
|
70
|
+
data: null,
|
|
71
|
+
message: "Parameter verification failed.\n",
|
|
72
|
+
errors: { name: "no such alias" },
|
|
73
|
+
};
|
|
74
|
+
for (const op of [
|
|
75
|
+
cluster.getClusterFirewallAlias({ name: "test" }),
|
|
76
|
+
cluster.putClusterFirewallAlias({ name: "test", cidr: "192.0.2.1" }),
|
|
77
|
+
]) {
|
|
78
|
+
test("alias requires the sole exact errors.name detail", async () => {
|
|
79
|
+
expect(await call(op, 400, missingAlias)).toMatchObject({
|
|
80
|
+
_tag: "FirewallAliasNotFound",
|
|
81
|
+
});
|
|
82
|
+
expect(await call(op, 403, missingAlias)).toMatchObject({
|
|
83
|
+
_tag: "Forbidden",
|
|
84
|
+
});
|
|
85
|
+
for (const errors of [
|
|
86
|
+
{ name: "no such alias", cidr: "invalid" },
|
|
87
|
+
{ other: "no such alias" },
|
|
88
|
+
{ name: "invalid alias" },
|
|
89
|
+
]) {
|
|
90
|
+
expect(await call(op, 400, { ...missingAlias, errors })).toMatchObject({
|
|
91
|
+
_tag: "ParameterVerificationFailed",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
expect(
|
|
95
|
+
await call(op, 400, { ...missingAlias, message: "unrelated validation" }),
|
|
96
|
+
).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
test("absence patches do not classify unrelated operations", async () => {
|
|
101
|
+
expect(
|
|
102
|
+
await call(
|
|
103
|
+
cluster.createClusterFirewallAlias({ name: "test", cidr: "192.0.2.1" }),
|
|
104
|
+
400,
|
|
105
|
+
missingAlias,
|
|
106
|
+
),
|
|
107
|
+
).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
108
|
+
expect(
|
|
109
|
+
await call(
|
|
110
|
+
cluster.deleteClusterFirewallAlias({ name: "test" }),
|
|
111
|
+
400,
|
|
112
|
+
missingAlias,
|
|
113
|
+
),
|
|
114
|
+
).toMatchObject({ _tag: "ParameterVerificationFailed" });
|
|
115
|
+
expect(
|
|
116
|
+
await call(
|
|
117
|
+
cluster.createClusterReplication({
|
|
118
|
+
id: "900-0",
|
|
119
|
+
target: "pve-b",
|
|
120
|
+
type: "local",
|
|
121
|
+
}),
|
|
122
|
+
500,
|
|
123
|
+
{ message: "no such job '900-0'\n" },
|
|
124
|
+
),
|
|
125
|
+
).toMatchObject({ _tag: "InternalServerError" });
|
|
126
|
+
});
|
package/src/services/cluster.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// AUTO-GENERATED by scripts/generate.ts from .generated-specs (apidata.js, via scripts/apidoc.ts — see its header). Do not edit.
|
|
2
2
|
import * as S from "@distilled.cloud/core/schema";
|
|
3
3
|
import * as API from "@distilled.cloud/core/api";
|
|
4
|
+
import * as C from "@distilled.cloud/core/category";
|
|
4
5
|
import * as T from "../traits.ts";
|
|
5
6
|
import {
|
|
6
7
|
ProxmoxProtocol,
|
|
@@ -11,6 +12,66 @@ import * as Retry from "../retry.ts";
|
|
|
11
12
|
|
|
12
13
|
export type { ProxmoxOpError, ProxmoxOpContext };
|
|
13
14
|
|
|
15
|
+
/** 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. */
|
|
16
|
+
export class BackupJobNotFound
|
|
17
|
+
extends /*@__PURE__*/ T.applyErrorMatchers(
|
|
18
|
+
/*@__PURE__*/ S.TaggedError<BackupJobNotFound>()("BackupJobNotFound", {
|
|
19
|
+
message: S.String,
|
|
20
|
+
}).pipe(C.withBadRequestError),
|
|
21
|
+
[{ status: 400, message: { matches: "^No such job '[^']+'$" } }],
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
/** 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. */
|
|
25
|
+
export class FirewallAliasNotFound
|
|
26
|
+
extends /*@__PURE__*/ T.applyErrorMatchers(
|
|
27
|
+
/*@__PURE__*/ S.TaggedError<FirewallAliasNotFound>()(
|
|
28
|
+
"FirewallAliasNotFound",
|
|
29
|
+
{
|
|
30
|
+
message: S.String,
|
|
31
|
+
},
|
|
32
|
+
).pipe(C.withBadRequestError),
|
|
33
|
+
[{ status: 400, message: { matches: "^no such alias$" } }],
|
|
34
|
+
) {}
|
|
35
|
+
|
|
36
|
+
/** 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. */
|
|
37
|
+
export class MetricServerNotFound
|
|
38
|
+
extends /*@__PURE__*/ T.applyErrorMatchers(
|
|
39
|
+
/*@__PURE__*/ S.TaggedError<MetricServerNotFound>()(
|
|
40
|
+
"MetricServerNotFound",
|
|
41
|
+
{
|
|
42
|
+
message: S.String,
|
|
43
|
+
},
|
|
44
|
+
).pipe(C.withBadRequestError),
|
|
45
|
+
[
|
|
46
|
+
{
|
|
47
|
+
status: 500,
|
|
48
|
+
message: {
|
|
49
|
+
matches: "^status server entry '[^']+' does not exist\\n?$",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{ status: 500, message: { matches: "^no such server '[^']+'\\n?$" } },
|
|
53
|
+
],
|
|
54
|
+
) {}
|
|
55
|
+
|
|
56
|
+
/** 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. */
|
|
57
|
+
export class ReplicationJobNotFound
|
|
58
|
+
extends /*@__PURE__*/ T.applyErrorMatchers(
|
|
59
|
+
/*@__PURE__*/ S.TaggedError<ReplicationJobNotFound>()(
|
|
60
|
+
"ReplicationJobNotFound",
|
|
61
|
+
{
|
|
62
|
+
message: S.String,
|
|
63
|
+
},
|
|
64
|
+
).pipe(C.withBadRequestError),
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
status: 500,
|
|
68
|
+
message: {
|
|
69
|
+
matches: "^no such (replication )?job '[0-9]+-[0-9]+'\\n?$",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
) {}
|
|
74
|
+
|
|
14
75
|
export interface CreateClusterAcmeAccountRequest {
|
|
15
76
|
/** Contact email addresses. */
|
|
16
77
|
contact: string;
|
|
@@ -15170,7 +15231,7 @@ export const deleteClusterAcmePlugin: API.OperationMethod<
|
|
|
15170
15231
|
retry: Retry.Retry,
|
|
15171
15232
|
}));
|
|
15172
15233
|
|
|
15173
|
-
export type DeleteClusterBackupError = ProxmoxOpError;
|
|
15234
|
+
export type DeleteClusterBackupError = BackupJobNotFound | ProxmoxOpError;
|
|
15174
15235
|
/** Delete vzdump backup job definition. (root-privileged endpoint) */
|
|
15175
15236
|
export const deleteClusterBackup: API.OperationMethod<
|
|
15176
15237
|
DeleteClusterBackupRequest,
|
|
@@ -15180,7 +15241,7 @@ export const deleteClusterBackup: API.OperationMethod<
|
|
|
15180
15241
|
> = /*@__PURE__*/ API.make(() => ({
|
|
15181
15242
|
input: DeleteClusterBackupRequest,
|
|
15182
15243
|
output: DeleteClusterBackupResponse,
|
|
15183
|
-
errors: [],
|
|
15244
|
+
errors: [BackupJobNotFound],
|
|
15184
15245
|
protocol: ProxmoxProtocol,
|
|
15185
15246
|
retry: Retry.Retry,
|
|
15186
15247
|
}));
|
|
@@ -15500,7 +15561,9 @@ export const deleteClusterQemuCustomCpuModel: API.OperationMethod<
|
|
|
15500
15561
|
retry: Retry.Retry,
|
|
15501
15562
|
}));
|
|
15502
15563
|
|
|
15503
|
-
export type DeleteClusterReplicationError =
|
|
15564
|
+
export type DeleteClusterReplicationError =
|
|
15565
|
+
| ReplicationJobNotFound
|
|
15566
|
+
| ProxmoxOpError;
|
|
15504
15567
|
/** Mark replication job for removal. (root-privileged endpoint) */
|
|
15505
15568
|
export const deleteClusterReplication: API.OperationMethod<
|
|
15506
15569
|
DeleteClusterReplicationRequest,
|
|
@@ -15510,7 +15573,7 @@ export const deleteClusterReplication: API.OperationMethod<
|
|
|
15510
15573
|
> = /*@__PURE__*/ API.make(() => ({
|
|
15511
15574
|
input: DeleteClusterReplicationRequest,
|
|
15512
15575
|
output: DeleteClusterReplicationResponse,
|
|
15513
|
-
errors: [],
|
|
15576
|
+
errors: [ReplicationJobNotFound],
|
|
15514
15577
|
protocol: ProxmoxProtocol,
|
|
15515
15578
|
retry: Retry.Retry,
|
|
15516
15579
|
}));
|
|
@@ -15785,7 +15848,7 @@ export const getClusterAcmeTos: API.OperationMethod<
|
|
|
15785
15848
|
retry: Retry.Retry,
|
|
15786
15849
|
}));
|
|
15787
15850
|
|
|
15788
|
-
export type GetClusterBackupError = ProxmoxOpError;
|
|
15851
|
+
export type GetClusterBackupError = BackupJobNotFound | ProxmoxOpError;
|
|
15789
15852
|
/** Read vzdump backup job definition. */
|
|
15790
15853
|
export const getClusterBackup: API.OperationMethod<
|
|
15791
15854
|
GetClusterBackupRequest,
|
|
@@ -15795,12 +15858,14 @@ export const getClusterBackup: API.OperationMethod<
|
|
|
15795
15858
|
> = /*@__PURE__*/ API.make(() => ({
|
|
15796
15859
|
input: GetClusterBackupRequest,
|
|
15797
15860
|
output: GetClusterBackupResponse,
|
|
15798
|
-
errors: [],
|
|
15861
|
+
errors: [BackupJobNotFound],
|
|
15799
15862
|
protocol: ProxmoxProtocol,
|
|
15800
15863
|
retry: Retry.Retry,
|
|
15801
15864
|
}));
|
|
15802
15865
|
|
|
15803
|
-
export type GetClusterBackupIncludedVolumesError =
|
|
15866
|
+
export type GetClusterBackupIncludedVolumesError =
|
|
15867
|
+
| BackupJobNotFound
|
|
15868
|
+
| ProxmoxOpError;
|
|
15804
15869
|
/** Returns included guests and the backup status of their disks. Optimized to be used in ExtJS tree views. (root-privileged endpoint) */
|
|
15805
15870
|
export const getClusterBackupIncludedVolumes: API.OperationMethod<
|
|
15806
15871
|
GetClusterBackupIncludedVolumesRequest,
|
|
@@ -15810,7 +15875,7 @@ export const getClusterBackupIncludedVolumes: API.OperationMethod<
|
|
|
15810
15875
|
> = /*@__PURE__*/ API.make(() => ({
|
|
15811
15876
|
input: GetClusterBackupIncludedVolumesRequest,
|
|
15812
15877
|
output: GetClusterBackupIncludedVolumesResponse,
|
|
15813
|
-
errors: [],
|
|
15878
|
+
errors: [BackupJobNotFound],
|
|
15814
15879
|
protocol: ProxmoxProtocol,
|
|
15815
15880
|
retry: Retry.Retry,
|
|
15816
15881
|
}));
|
|
@@ -15920,7 +15985,9 @@ export const getClusterConfigTotem: API.OperationMethod<
|
|
|
15920
15985
|
retry: Retry.Retry,
|
|
15921
15986
|
}));
|
|
15922
15987
|
|
|
15923
|
-
export type GetClusterFirewallAliasError =
|
|
15988
|
+
export type GetClusterFirewallAliasError =
|
|
15989
|
+
| FirewallAliasNotFound
|
|
15990
|
+
| ProxmoxOpError;
|
|
15924
15991
|
/** Read alias. */
|
|
15925
15992
|
export const getClusterFirewallAlias: API.OperationMethod<
|
|
15926
15993
|
GetClusterFirewallAliasRequest,
|
|
@@ -15930,7 +15997,7 @@ export const getClusterFirewallAlias: API.OperationMethod<
|
|
|
15930
15997
|
> = /*@__PURE__*/ API.make(() => ({
|
|
15931
15998
|
input: GetClusterFirewallAliasRequest,
|
|
15932
15999
|
output: GetClusterFirewallAliasResponse,
|
|
15933
|
-
errors: [],
|
|
16000
|
+
errors: [FirewallAliasNotFound],
|
|
15934
16001
|
protocol: ProxmoxProtocol,
|
|
15935
16002
|
retry: Retry.Retry,
|
|
15936
16003
|
}));
|
|
@@ -16160,7 +16227,9 @@ export const getClusterMetricsExport: API.OperationMethod<
|
|
|
16160
16227
|
retry: Retry.Retry,
|
|
16161
16228
|
}));
|
|
16162
16229
|
|
|
16163
|
-
export type GetClusterMetricsServerError =
|
|
16230
|
+
export type GetClusterMetricsServerError =
|
|
16231
|
+
| MetricServerNotFound
|
|
16232
|
+
| ProxmoxOpError;
|
|
16164
16233
|
/** Read metric server configuration. */
|
|
16165
16234
|
export const getClusterMetricsServer: API.OperationMethod<
|
|
16166
16235
|
GetClusterMetricsServerRequest,
|
|
@@ -16170,7 +16239,7 @@ export const getClusterMetricsServer: API.OperationMethod<
|
|
|
16170
16239
|
> = /*@__PURE__*/ API.make(() => ({
|
|
16171
16240
|
input: GetClusterMetricsServerRequest,
|
|
16172
16241
|
output: GetClusterMetricsServerResponse,
|
|
16173
|
-
errors: [],
|
|
16242
|
+
errors: [MetricServerNotFound],
|
|
16174
16243
|
protocol: ProxmoxProtocol,
|
|
16175
16244
|
retry: Retry.Retry,
|
|
16176
16245
|
}));
|
|
@@ -16295,7 +16364,9 @@ export const getClusterQemuCustomCpuModel: API.OperationMethod<
|
|
|
16295
16364
|
retry: Retry.Retry,
|
|
16296
16365
|
}));
|
|
16297
16366
|
|
|
16298
|
-
export type GetClusterReplicationError =
|
|
16367
|
+
export type GetClusterReplicationError =
|
|
16368
|
+
| ReplicationJobNotFound
|
|
16369
|
+
| ProxmoxOpError;
|
|
16299
16370
|
/** Read replication job configuration. */
|
|
16300
16371
|
export const getClusterReplication: API.OperationMethod<
|
|
16301
16372
|
GetClusterReplicationRequest,
|
|
@@ -16305,7 +16376,7 @@ export const getClusterReplication: API.OperationMethod<
|
|
|
16305
16376
|
> = /*@__PURE__*/ API.make(() => ({
|
|
16306
16377
|
input: GetClusterReplicationRequest,
|
|
16307
16378
|
output: GetClusterReplicationResponse,
|
|
16308
|
-
errors: [],
|
|
16379
|
+
errors: [ReplicationJobNotFound],
|
|
16309
16380
|
protocol: ProxmoxProtocol,
|
|
16310
16381
|
retry: Retry.Retry,
|
|
16311
16382
|
}));
|
|
@@ -17810,7 +17881,9 @@ export const putClusterCephHealthMute: API.OperationMethod<
|
|
|
17810
17881
|
retry: Retry.Retry,
|
|
17811
17882
|
}));
|
|
17812
17883
|
|
|
17813
|
-
export type PutClusterFirewallAliasError =
|
|
17884
|
+
export type PutClusterFirewallAliasError =
|
|
17885
|
+
| FirewallAliasNotFound
|
|
17886
|
+
| ProxmoxOpError;
|
|
17814
17887
|
/** Update IP or Network alias. (root-privileged endpoint) */
|
|
17815
17888
|
export const putClusterFirewallAlias: API.OperationMethod<
|
|
17816
17889
|
PutClusterFirewallAliasRequest,
|
|
@@ -17820,7 +17893,7 @@ export const putClusterFirewallAlias: API.OperationMethod<
|
|
|
17820
17893
|
> = /*@__PURE__*/ API.make(() => ({
|
|
17821
17894
|
input: PutClusterFirewallAliasRequest,
|
|
17822
17895
|
output: PutClusterFirewallAliasResponse,
|
|
17823
|
-
errors: [],
|
|
17896
|
+
errors: [FirewallAliasNotFound],
|
|
17824
17897
|
protocol: ProxmoxProtocol,
|
|
17825
17898
|
retry: Retry.Retry,
|
|
17826
17899
|
}));
|
|
@@ -17990,7 +18063,9 @@ export const putClusterMappingUsb: API.OperationMethod<
|
|
|
17990
18063
|
retry: Retry.Retry,
|
|
17991
18064
|
}));
|
|
17992
18065
|
|
|
17993
|
-
export type PutClusterMetricsServerError =
|
|
18066
|
+
export type PutClusterMetricsServerError =
|
|
18067
|
+
| MetricServerNotFound
|
|
18068
|
+
| ProxmoxOpError;
|
|
17994
18069
|
/** Update metric server configuration. (root-privileged endpoint) */
|
|
17995
18070
|
export const putClusterMetricsServer: API.OperationMethod<
|
|
17996
18071
|
PutClusterMetricsServerRequest,
|
|
@@ -18000,7 +18075,7 @@ export const putClusterMetricsServer: API.OperationMethod<
|
|
|
18000
18075
|
> = /*@__PURE__*/ API.make(() => ({
|
|
18001
18076
|
input: PutClusterMetricsServerRequest,
|
|
18002
18077
|
output: PutClusterMetricsServerResponse,
|
|
18003
|
-
errors: [],
|
|
18078
|
+
errors: [MetricServerNotFound],
|
|
18004
18079
|
protocol: ProxmoxProtocol,
|
|
18005
18080
|
retry: Retry.Retry,
|
|
18006
18081
|
}));
|
|
@@ -18110,7 +18185,9 @@ export const putClusterQemuCustomCpuModel: API.OperationMethod<
|
|
|
18110
18185
|
retry: Retry.Retry,
|
|
18111
18186
|
}));
|
|
18112
18187
|
|
|
18113
|
-
export type PutClusterReplicationError =
|
|
18188
|
+
export type PutClusterReplicationError =
|
|
18189
|
+
| ReplicationJobNotFound
|
|
18190
|
+
| ProxmoxOpError;
|
|
18114
18191
|
/** Update replication job configuration. (root-privileged endpoint) */
|
|
18115
18192
|
export const putClusterReplication: API.OperationMethod<
|
|
18116
18193
|
PutClusterReplicationRequest,
|
|
@@ -18120,7 +18197,7 @@ export const putClusterReplication: API.OperationMethod<
|
|
|
18120
18197
|
> = /*@__PURE__*/ API.make(() => ({
|
|
18121
18198
|
input: PutClusterReplicationRequest,
|
|
18122
18199
|
output: PutClusterReplicationResponse,
|
|
18123
|
-
errors: [],
|
|
18200
|
+
errors: [ReplicationJobNotFound],
|
|
18124
18201
|
protocol: ProxmoxProtocol,
|
|
18125
18202
|
retry: Retry.Retry,
|
|
18126
18203
|
}));
|
package/src/services/nodes.ts
CHANGED
|
@@ -50,6 +50,35 @@ export class ClusterNodeUnreachable
|
|
|
50
50
|
[{ status: 595 }],
|
|
51
51
|
) {}
|
|
52
52
|
|
|
53
|
+
/** The requested container config is absent on this node. VM IDs are cluster-wide: callers must still check whether another node or QEMU guest holds the ID before creating. Also raised by PUT (update_vm) and DELETE (destroy_vm), which both call the same load_config first. This GET requires VM.Audit on /vms/{vmid}; retain its credential for any permission-filtered cluster index read. */
|
|
54
|
+
export class LxcConfigNotFound
|
|
55
|
+
extends /*@__PURE__*/ T.applyErrorMatchers(
|
|
56
|
+
/*@__PURE__*/ S.TaggedError<LxcConfigNotFound>()("LxcConfigNotFound", {
|
|
57
|
+
message: S.String,
|
|
58
|
+
}).pipe(C.withBadRequestError),
|
|
59
|
+
[
|
|
60
|
+
{
|
|
61
|
+
status: 500,
|
|
62
|
+
message: {
|
|
63
|
+
matches:
|
|
64
|
+
"^Configuration file 'nodes/[^/']+/lxc/[0-9]+\\.conf' does not exist\\n?$",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
) {}
|
|
69
|
+
|
|
70
|
+
/** pve-manager 9.2.11, PVE/API2/Network.pm. GET (network_config) and PUT (update_network) both raise HTTP 400 with exactly errors.iface = interface does not exist -- verified against the live n2 source on 2026-09-25. DELETE (delete_network) raises it too but is left untyped: no generated deleteNodeNetwork2 caller exists yet. Only the exact sole-field detail is normalized for operation matching; all other validation errors remain ParameterVerificationFailed. Attached to GET and PUT. */
|
|
71
|
+
export class NetworkInterfaceNotFound
|
|
72
|
+
extends /*@__PURE__*/ T.applyErrorMatchers(
|
|
73
|
+
/*@__PURE__*/ S.TaggedError<NetworkInterfaceNotFound>()(
|
|
74
|
+
"NetworkInterfaceNotFound",
|
|
75
|
+
{
|
|
76
|
+
message: S.String,
|
|
77
|
+
},
|
|
78
|
+
).pipe(C.withBadRequestError),
|
|
79
|
+
[{ status: 400, message: { matches: "^interface does not exist$" } }],
|
|
80
|
+
) {}
|
|
81
|
+
|
|
53
82
|
export interface CloneNodesLxcRequest {
|
|
54
83
|
node: string;
|
|
55
84
|
vmid: string;
|
|
@@ -21398,7 +21427,7 @@ export const deleteNodeFirewallRule: API.OperationMethod<
|
|
|
21398
21427
|
retry: Retry.Retry,
|
|
21399
21428
|
}));
|
|
21400
21429
|
|
|
21401
|
-
export type DeleteNodeLxcError = ProxmoxOpError;
|
|
21430
|
+
export type DeleteNodeLxcError = LxcConfigNotFound | ProxmoxOpError;
|
|
21402
21431
|
/** Destroy the container (also delete all uses files). (root-privileged endpoint) */
|
|
21403
21432
|
export const deleteNodeLxc: API.OperationMethod<
|
|
21404
21433
|
DeleteNodeLxcRequest,
|
|
@@ -21408,7 +21437,7 @@ export const deleteNodeLxc: API.OperationMethod<
|
|
|
21408
21437
|
> = /*@__PURE__*/ API.make(() => ({
|
|
21409
21438
|
input: DeleteNodeLxcRequest,
|
|
21410
21439
|
output: DeleteNodeLxcResponse,
|
|
21411
|
-
errors: [],
|
|
21440
|
+
errors: [LxcConfigNotFound],
|
|
21412
21441
|
protocol: ProxmoxProtocol,
|
|
21413
21442
|
retry: Retry.Retry,
|
|
21414
21443
|
}));
|
|
@@ -22088,7 +22117,7 @@ export const getNodeLxc: API.OperationMethod<
|
|
|
22088
22117
|
retry: Retry.Retry,
|
|
22089
22118
|
}));
|
|
22090
22119
|
|
|
22091
|
-
export type GetNodeLxcConfigError = ProxmoxOpError;
|
|
22120
|
+
export type GetNodeLxcConfigError = LxcConfigNotFound | ProxmoxOpError;
|
|
22092
22121
|
/** Get container configuration. */
|
|
22093
22122
|
export const getNodeLxcConfig: API.OperationMethod<
|
|
22094
22123
|
GetNodeLxcConfigRequest,
|
|
@@ -22098,7 +22127,7 @@ export const getNodeLxcConfig: API.OperationMethod<
|
|
|
22098
22127
|
> = /*@__PURE__*/ API.make(() => ({
|
|
22099
22128
|
input: GetNodeLxcConfigRequest,
|
|
22100
22129
|
output: GetNodeLxcConfigResponse,
|
|
22101
|
-
errors: [],
|
|
22130
|
+
errors: [LxcConfigNotFound],
|
|
22102
22131
|
protocol: ProxmoxProtocol,
|
|
22103
22132
|
retry: Retry.Retry,
|
|
22104
22133
|
}));
|
|
@@ -22297,7 +22326,7 @@ export const getNodeLxcVncwebsocket: API.OperationMethod<
|
|
|
22297
22326
|
retry: Retry.Retry,
|
|
22298
22327
|
}));
|
|
22299
22328
|
|
|
22300
|
-
export type GetNodeNetworkError = ProxmoxOpError;
|
|
22329
|
+
export type GetNodeNetworkError = NetworkInterfaceNotFound | ProxmoxOpError;
|
|
22301
22330
|
/** Read network device configuration */
|
|
22302
22331
|
export const getNodeNetwork: API.OperationMethod<
|
|
22303
22332
|
GetNodeNetworkRequest,
|
|
@@ -22307,7 +22336,7 @@ export const getNodeNetwork: API.OperationMethod<
|
|
|
22307
22336
|
> = /*@__PURE__*/ API.make(() => ({
|
|
22308
22337
|
input: GetNodeNetworkRequest,
|
|
22309
22338
|
output: GetNodeNetworkResponse,
|
|
22310
|
-
errors: [],
|
|
22339
|
+
errors: [NetworkInterfaceNotFound],
|
|
22311
22340
|
protocol: ProxmoxProtocol,
|
|
22312
22341
|
retry: Retry.Retry,
|
|
22313
22342
|
}));
|
|
@@ -24738,7 +24767,7 @@ export const putNodeFirewallRule: API.OperationMethod<
|
|
|
24738
24767
|
retry: Retry.Retry,
|
|
24739
24768
|
}));
|
|
24740
24769
|
|
|
24741
|
-
export type PutNodeLxcConfigError = ProxmoxOpError;
|
|
24770
|
+
export type PutNodeLxcConfigError = LxcConfigNotFound | ProxmoxOpError;
|
|
24742
24771
|
/** Set container options. (root-privileged endpoint) */
|
|
24743
24772
|
export const putNodeLxcConfig: API.OperationMethod<
|
|
24744
24773
|
PutNodeLxcConfigRequest,
|
|
@@ -24748,7 +24777,7 @@ export const putNodeLxcConfig: API.OperationMethod<
|
|
|
24748
24777
|
> = /*@__PURE__*/ API.make(() => ({
|
|
24749
24778
|
input: PutNodeLxcConfigRequest,
|
|
24750
24779
|
output: PutNodeLxcConfigResponse,
|
|
24751
|
-
errors: [],
|
|
24780
|
+
errors: [LxcConfigNotFound],
|
|
24752
24781
|
protocol: ProxmoxProtocol,
|
|
24753
24782
|
retry: Retry.Retry,
|
|
24754
24783
|
}));
|
|
@@ -24858,7 +24887,7 @@ export const putNodeNetwork: API.OperationMethod<
|
|
|
24858
24887
|
retry: Retry.Retry,
|
|
24859
24888
|
}));
|
|
24860
24889
|
|
|
24861
|
-
export type PutNodeNetwork2Error = ProxmoxOpError;
|
|
24890
|
+
export type PutNodeNetwork2Error = NetworkInterfaceNotFound | ProxmoxOpError;
|
|
24862
24891
|
/** Update network device configuration (root-privileged endpoint) */
|
|
24863
24892
|
export const putNodeNetwork2: API.OperationMethod<
|
|
24864
24893
|
PutNodeNetwork2Request,
|
|
@@ -24868,7 +24897,7 @@ export const putNodeNetwork2: API.OperationMethod<
|
|
|
24868
24897
|
> = /*@__PURE__*/ API.make(() => ({
|
|
24869
24898
|
input: PutNodeNetwork2Request,
|
|
24870
24899
|
output: PutNodeNetwork2Response,
|
|
24871
|
-
errors: [],
|
|
24900
|
+
errors: [NetworkInterfaceNotFound],
|
|
24872
24901
|
protocol: ProxmoxProtocol,
|
|
24873
24902
|
retry: Retry.Retry,
|
|
24874
24903
|
}));
|