@homeflare/distilled-proxmox 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/network-changes.test.d.ts +2 -0
- package/dist/network-changes.test.d.ts.map +1 -0
- package/dist/network-changes.test.js +42 -0
- package/dist/network-changes.test.js.map +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +10 -1
- package/dist/protocol.js.map +1 -1
- package/dist/qemu-config-absence.test.d.ts +2 -0
- package/dist/qemu-config-absence.test.d.ts.map +1 -0
- package/dist/qemu-config-absence.test.js +41 -0
- package/dist/qemu-config-absence.test.js.map +1 -0
- package/dist/services/nodes.d.ts +19 -3
- package/dist/services/nodes.d.ts.map +1 -1
- package/dist/services/nodes.js +25 -3
- package/dist/services/nodes.js.map +1 -1
- package/package.json +1 -1
- package/src/network-changes.test.ts +60 -0
- package/src/protocol.ts +10 -1
- package/src/qemu-config-absence.test.ts +75 -0
- package/src/services/nodes.ts +42 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-changes.test.d.ts","sourceRoot":"","sources":["../src/network-changes.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The interfaces diff is a sibling of `data`. Generic unwrapping must not drop it,
|
|
3
|
+
* and a response without that sibling must still unwrap.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
8
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
9
|
+
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
10
|
+
import { credentials } from "./credentials.js";
|
|
11
|
+
import * as Retry from "./retry.js";
|
|
12
|
+
import { getNodeTime, listNodeNetwork } from "./services/nodes.js";
|
|
13
|
+
const creds = credentials({
|
|
14
|
+
tokenId: "root@pam!test",
|
|
15
|
+
secret: "test-secret",
|
|
16
|
+
baseUrl: "https://pve.test:8006",
|
|
17
|
+
});
|
|
18
|
+
const http = (body) => Layer.succeed(HttpClient.HttpClient, HttpClient.make((request) => Effect.succeed(HttpClientResponse.fromWeb(request, Response.json(body, { status: 200 })))));
|
|
19
|
+
const run = (op, body) => Effect.runPromise(op.pipe(Retry.none, Effect.provide(Layer.mergeAll(http(body), creds))));
|
|
20
|
+
describe("network changes sibling", () => {
|
|
21
|
+
test("a staged interfaces diff survives beside data", async () => {
|
|
22
|
+
const changes = "--- a\n+++ b\n+wpa-psk secret-value\n";
|
|
23
|
+
const live = await run(listNodeNetwork({ node: "pve1" }), { data: [{ iface: "vmbr0", type: "bridge" }], changes });
|
|
24
|
+
expect(live).toEqual({
|
|
25
|
+
data: [{ iface: "vmbr0", type: "bridge" }],
|
|
26
|
+
changes,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
test("no changes sibling still unwraps to the interface list", async () => {
|
|
30
|
+
const live = await run(listNodeNetwork({ node: "pve1" }), {
|
|
31
|
+
data: [{ iface: "vmbr0", type: "bridge" }],
|
|
32
|
+
});
|
|
33
|
+
expect(live).toEqual([{ iface: "vmbr0", type: "bridge" }]);
|
|
34
|
+
});
|
|
35
|
+
test("another operation still unwraps data and ignores no sibling", async () => {
|
|
36
|
+
const live = await run(getNodeTime({ node: "pve1" }), {
|
|
37
|
+
data: { time: 1_700_000_000 },
|
|
38
|
+
});
|
|
39
|
+
expect(live).toMatchObject({ time: 1_700_000_000 });
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=network-changes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-changes.test.js","sourceRoot":"","sources":["../src/network-changes.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,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,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEnE,MAAM,KAAK,GAAG,WAAW,CAAC;IACxB,OAAO,EAAE,eAAe;IACxB,MAAM,EAAE,aAAa;IACrB,OAAO,EAAE,uBAAuB;CACjC,CAAC,CAAC;AAEH,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,EAAE,CAC7B,KAAK,CAAC,OAAO,CACX,UAAU,CAAC,UAAU,EACrB,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1B,MAAM,CAAC,OAAO,CACZ,kBAAkB,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAC1E,CACF,CACF,CAAC;AAEJ,MAAM,GAAG,GAAG,CAAO,EAAyC,EAAE,IAAa,EAAE,EAAE,CAC7E,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAE5F,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,OAAO,GAAG,uCAAuC,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,GAAG,CACpB,eAAe,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EACjC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CACxD,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;YACnB,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC1C,OAAO;SACR,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;YACxD,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;SAC3C,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;YACpD,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;SAC9B,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
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;AAuDnE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,
|
|
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,CAqFrD,CAAC"}
|
package/dist/protocol.js
CHANGED
|
@@ -138,11 +138,20 @@ export const ProxmoxProtocol = withPveFormArrays(makeRestProtocol({
|
|
|
138
138
|
// Unwrap PVE's `{"data": …}` envelope BEFORE the schema-driven decode —
|
|
139
139
|
// see the module header. `data` is `null`/absent for a Unit-output
|
|
140
140
|
// operation; `?? {}` is core's own convention for "no body".
|
|
141
|
+
// ⛔ `changes` is a sibling, not a field of `data`. PVE/HTTPServer.pm copies
|
|
142
|
+
// `$rpcenv->get_result_attrib('changes')` beside `data`. Network.pm sets
|
|
143
|
+
// that attrib to the interfaces diff. Dropping it makes a pending reload
|
|
144
|
+
// invisible. Only a string sibling is preserved; every other envelope
|
|
145
|
+
// still unwraps. The network list schema is the union that can decode it.
|
|
141
146
|
transformResponse: (body) => {
|
|
142
147
|
if (body !== null &&
|
|
143
148
|
typeof body === "object" &&
|
|
144
149
|
"data" in body) {
|
|
145
|
-
|
|
150
|
+
const record = body;
|
|
151
|
+
if (typeof record.changes === "string") {
|
|
152
|
+
return { changes: record.changes, data: record.data ?? [] };
|
|
153
|
+
}
|
|
154
|
+
return record.data ?? {};
|
|
146
155
|
}
|
|
147
156
|
return body;
|
|
148
157
|
},
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qemu-config-absence.test.d.ts","sourceRoot":"","sources":["../src/qemu-config-absence.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QEMU absence is the config-file sentence from AbstractConfig, not every 500.
|
|
3
|
+
* qemu-server Qemu.pm routes GET/PUT through `{vmid}/config` and DELETE through `{vmid}`.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
8
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
9
|
+
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
10
|
+
import { credentials } from "./credentials.js";
|
|
11
|
+
import * as Retry from "./retry.js";
|
|
12
|
+
import { deleteNodeQemu, getNodeQemuConfig } from "./services/nodes.js";
|
|
13
|
+
const call = (op, status, body) => Effect.runPromise(op.pipe(Retry.none, Effect.provide(credentials({
|
|
14
|
+
baseUrl: "https://pve.test:8006",
|
|
15
|
+
tokenId: "test@pve!test",
|
|
16
|
+
secret: "fake",
|
|
17
|
+
})), Effect.provide(Layer.succeed(HttpClient.HttpClient, HttpClient.make((request) => Effect.succeed(HttpClientResponse.fromWeb(request, Response.json(body, { status })))))), Effect.flip));
|
|
18
|
+
const missing = {
|
|
19
|
+
data: null,
|
|
20
|
+
message: "Configuration file 'nodes/pve1/qemu-server/150.conf' does not exist\n",
|
|
21
|
+
};
|
|
22
|
+
describe("QEMU config absence", () => {
|
|
23
|
+
test("config GET and guest DELETE share the missing-file tag", async () => {
|
|
24
|
+
expect(await call(getNodeQemuConfig({ node: "pve1", vmid: "150" }), 500, missing)).toMatchObject({ _tag: "QemuConfigNotFound" });
|
|
25
|
+
expect(await call(deleteNodeQemu({ node: "pve1", vmid: "150" }), 500, missing)).toMatchObject({ _tag: "QemuConfigNotFound" });
|
|
26
|
+
});
|
|
27
|
+
test("a container path, a running guest, and a bare 500 stay unrelated", async () => {
|
|
28
|
+
for (const message of [
|
|
29
|
+
"Configuration file 'nodes/pve1/lxc/150.conf' does not exist\n",
|
|
30
|
+
"VM 150 is running - destroy failed\n",
|
|
31
|
+
"unrelated failure",
|
|
32
|
+
]) {
|
|
33
|
+
const error = await call(getNodeQemuConfig({ node: "pve1", vmid: "150" }), 500, {
|
|
34
|
+
data: null,
|
|
35
|
+
message,
|
|
36
|
+
});
|
|
37
|
+
expect(error).toMatchObject({ _tag: "InternalServerError" });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=qemu-config-absence.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qemu-config-absence.test.js","sourceRoot":"","sources":["../src/qemu-config-absence.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,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,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExE,MAAM,IAAI,GAAG,CACX,EAAyC,EACzC,MAAc,EACd,IAAa,EACb,EAAE,CACF,MAAM,CAAC,UAAU,CACf,EAAE,CAAC,IAAI,CACL,KAAK,CAAC,IAAI,EACV,MAAM,CAAC,OAAO,CACZ,WAAW,CAAC;IACV,OAAO,EAAE,uBAAuB;IAChC,OAAO,EAAE,eAAe;IACxB,MAAM,EAAE,MAAM;CACf,CAAC,CACH,EACD,MAAM,CAAC,OAAO,CACZ,KAAK,CAAC,OAAO,CACX,UAAU,CAAC,UAAU,EACrB,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1B,MAAM,CAAC,OAAO,CACZ,kBAAkB,CAAC,OAAO,CACxB,OAAO,EACP,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAChC,CACF,CACF,CACF,CACF,EACD,MAAM,CAAC,IAAI,CACZ,CACF,CAAC;AAEJ,MAAM,OAAO,GAAG;IACd,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,uEAAuE;CACjF,CAAC;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,IAAI,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,CACJ,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAC3E,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;QAChD,MAAM,CACJ,MAAM,IAAI,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CACxE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAClF,KAAK,MAAM,OAAO,IAAI;YACpB,+DAA+D;YAC/D,sCAAsC;YACtC,mBAAmB;SACpB,EAAE,CAAC;YACF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE;gBAC9E,IAAI,EAAE,IAAI;gBACV,OAAO;aACR,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/services/nodes.d.ts
CHANGED
|
@@ -42,6 +42,16 @@ declare const LxcConfigNotFound_base: S.Class<LxcConfigNotFound, S.TaggedStruct<
|
|
|
42
42
|
/** 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. */
|
|
43
43
|
export declare class LxcConfigNotFound extends /*@__PURE__*/ LxcConfigNotFound_base {
|
|
44
44
|
}
|
|
45
|
+
declare const QemuConfigNotFound_base: S.Class<QemuConfigNotFound, S.TaggedStruct<"QemuConfigNotFound", {
|
|
46
|
+
readonly message: any;
|
|
47
|
+
}>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
|
|
48
|
+
"@distilled.cloud/error/categories": {
|
|
49
|
+
BadRequestError: true;
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
/** qemu-server PVE/API2/Qemu.pm vm_config GET and destroy_vm both call QemuConfig->load_config. pve-guest-common AbstractConfig.pm load_config dies when the cfs file is missing: Configuration file '$cfspath' does not exist. QemuConfig's path is nodes/$node/qemu-server/$vmid.conf, HTTP 500. A missing file on this node is not a free cluster-wide vmid. */
|
|
53
|
+
export declare class QemuConfigNotFound extends /*@__PURE__*/ QemuConfigNotFound_base {
|
|
54
|
+
}
|
|
45
55
|
declare const NetworkInterfaceNotFound_base: S.Class<NetworkInterfaceNotFound, S.TaggedStruct<"NetworkInterfaceNotFound", {
|
|
46
56
|
readonly message: any;
|
|
47
57
|
}>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
|
|
@@ -4689,7 +4699,13 @@ export interface ListNodeNetworkResponseBodyItem {
|
|
|
4689
4699
|
export declare const ListNodeNetworkResponseBodyItem: S.Schema<ListNodeNetworkResponseBodyItem>;
|
|
4690
4700
|
export type ListNodeNetworkResponseBodyList = Array<ListNodeNetworkResponseBodyItem>;
|
|
4691
4701
|
export declare const ListNodeNetworkResponseBodyList: S.Schema<ListNodeNetworkResponseBodyList>;
|
|
4692
|
-
|
|
4702
|
+
/** Present only when PVE staged an interfaces diff. The string can contain secrets. */
|
|
4703
|
+
export interface ListNodeNetworkPendingResponse {
|
|
4704
|
+
data: ListNodeNetworkResponseBodyList;
|
|
4705
|
+
changes: string;
|
|
4706
|
+
}
|
|
4707
|
+
export declare const ListNodeNetworkPendingResponse: S.Schema<ListNodeNetworkPendingResponse>;
|
|
4708
|
+
export type ListNodeNetworkResponse = ListNodeNetworkResponseBodyList | ListNodeNetworkPendingResponse;
|
|
4693
4709
|
export declare const ListNodeNetworkResponse: S.Schema<ListNodeNetworkResponse>;
|
|
4694
4710
|
export interface ListNodeQemuRequest {
|
|
4695
4711
|
node: string;
|
|
@@ -7125,7 +7141,7 @@ export declare const deleteNodeNetwork: API.OperationMethod<DeleteNodeNetworkReq
|
|
|
7125
7141
|
export type DeleteNodeNetwork2Error = ProxmoxOpError;
|
|
7126
7142
|
/** Delete network device configuration (root-privileged endpoint) */
|
|
7127
7143
|
export declare const deleteNodeNetwork2: API.OperationMethod<DeleteNodeNetwork2Request, DeleteNodeNetwork2Response, DeleteNodeNetwork2Error, ProxmoxOpContext>;
|
|
7128
|
-
export type DeleteNodeQemuError = ProxmoxOpError;
|
|
7144
|
+
export type DeleteNodeQemuError = QemuConfigNotFound | ProxmoxOpError;
|
|
7129
7145
|
/** Destroy the VM and all used/owned volumes. Removes any VM specific permissions and firewall rules (root-privileged endpoint) */
|
|
7130
7146
|
export declare const deleteNodeQemu: API.OperationMethod<DeleteNodeQemuRequest, DeleteNodeQemuResponse, DeleteNodeQemuError, ProxmoxOpContext>;
|
|
7131
7147
|
export type DeleteNodeQemuFirewallAliasError = ProxmoxOpError;
|
|
@@ -7328,7 +7344,7 @@ export declare const getNodeQemuAgentNetworkGetInterfaces: API.OperationMethod<G
|
|
|
7328
7344
|
export type GetNodeQemuCloudinitDumpError = ProxmoxOpError;
|
|
7329
7345
|
/** Get automatically generated cloudinit config. */
|
|
7330
7346
|
export declare const getNodeQemuCloudinitDump: API.OperationMethod<GetNodeQemuCloudinitDumpRequest, GetNodeQemuCloudinitDumpResponse, GetNodeQemuCloudinitDumpError, ProxmoxOpContext>;
|
|
7331
|
-
export type GetNodeQemuConfigError = ProxmoxOpError;
|
|
7347
|
+
export type GetNodeQemuConfigError = QemuConfigNotFound | ProxmoxOpError;
|
|
7332
7348
|
/** Get the virtual machine configuration with pending configuration changes applied. Set the 'current' parameter to get the current configuration instead. */
|
|
7333
7349
|
export declare const getNodeQemuConfig: API.OperationMethod<GetNodeQemuConfigRequest, GetNodeQemuConfigResponse, GetNodeQemuConfigError, ProxmoxOpContext>;
|
|
7334
7350
|
export type GetNodeQemuFeatureError = ProxmoxOpError;
|