@tyevco/homelab-lxc-agent 1.9.14 → 1.9.16

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/lxc.js CHANGED
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.joinExecTerminal = exports.getDistributions = exports.listSnapshots = exports.cloneContainer = exports.createContainer = exports.saveConfig = exports.deleteContainer = exports.unfreezeContainer = exports.freezeContainer = exports.restartContainer = exports.stopContainer = exports.startContainer = exports.getContainer = exports.getContainerList = exports.STACK_TYPE_LXC = exports.FROZEN = exports.EXITED = exports.RUNNING = exports.UNKNOWN = void 0;
26
+ exports.joinExecTerminal = exports.getDistributions = exports.deleteSnapshot = exports.createSnapshot = exports.listSnapshots = exports.cloneContainer = exports.createContainer = exports.saveConfig = exports.deleteContainer = exports.unfreezeContainer = exports.freezeContainer = exports.restartContainer = exports.stopContainer = exports.startContainer = exports.getContainer = exports.getContainerList = exports.STACK_TYPE_LXC = exports.FROZEN = exports.EXITED = exports.RUNNING = exports.UNKNOWN = void 0;
27
27
  const promisify_child_process_1 = require("promisify-child-process");
28
28
  const fs = __importStar(require("fs"));
29
29
  const path = __importStar(require("path"));
@@ -224,7 +224,7 @@ async function deleteContainer(socket, endpoint, name, status) {
224
224
  console.log(`[lxc] Stopping ${name} before delete`);
225
225
  await terminal_1.AgentTerminal.exec(socket, termName, "lxc-stop", ["-n", name], LXC_PATH);
226
226
  }
227
- const code = await terminal_1.AgentTerminal.exec(socket, termName, "lxc-destroy", ["-n", name], LXC_PATH);
227
+ const code = await terminal_1.AgentTerminal.exec(socket, termName, "lxc-destroy", ["-n", name, "--snapshots"], LXC_PATH);
228
228
  if (code !== 0) {
229
229
  throw new Error("Failed to destroy LXC container");
230
230
  }
@@ -309,6 +309,27 @@ async function listSnapshots(containerName) {
309
309
  }
310
310
  }
311
311
  exports.listSnapshots = listSnapshots;
312
+ async function createSnapshot(containerName) {
313
+ if (!/^[a-z0-9_.-]+$/.test(containerName)) {
314
+ throw new Error("Invalid container name");
315
+ }
316
+ const before = await listSnapshots(containerName);
317
+ await (0, promisify_child_process_1.spawn)("lxc-snapshot", ["-n", containerName], { encoding: "utf-8" });
318
+ const after = await listSnapshots(containerName);
319
+ const newSnap = after.find(s => !before.includes(s));
320
+ return newSnap || after[after.length - 1] || "";
321
+ }
322
+ exports.createSnapshot = createSnapshot;
323
+ async function deleteSnapshot(containerName, snapshotName) {
324
+ if (!/^[a-z0-9_.-]+$/.test(containerName)) {
325
+ throw new Error("Invalid container name");
326
+ }
327
+ if (!/^[a-z0-9_.-]+$/.test(snapshotName)) {
328
+ throw new Error("Invalid snapshot name");
329
+ }
330
+ await (0, promisify_child_process_1.spawn)("lxc-snapshot", ["-n", containerName, "-d", snapshotName], { encoding: "utf-8" });
331
+ }
332
+ exports.deleteSnapshot = deleteSnapshot;
312
333
  async function appendConfig(name, extra) {
313
334
  const configPath = path.join(LXC_PATH, name, "config");
314
335
  const existing = await fs.promises.readFile(configPath, "utf-8").catch(() => "");
package/dist/server.js CHANGED
@@ -84,6 +84,10 @@ function createAgentServer(config) {
84
84
  // Initial scan, then periodic rescan
85
85
  rescan().then(() => {
86
86
  setInterval(rescan, config.scanInterval * 1000);
87
+ }).catch((e) => {
88
+ console.error("[agent] Initial scan failed:", e instanceof Error ? e.message : e);
89
+ // Still set up periodic rescans so recovery is possible
90
+ setInterval(rescan, config.scanInterval * 1000);
87
91
  });
88
92
  io.on("connection", (socket) => {
89
93
  // The main server sends its own endpoint string in the header so we can
@@ -237,8 +241,19 @@ async function dispatch(socket, endpoint, eventName, args) {
237
241
  if (typeof name !== "string") {
238
242
  throw new Error("Name must be a string");
239
243
  }
240
- const container = await lxc.getContainer(name, endpoint);
241
- await lxc.deleteContainer(socket, endpoint, name, container.status);
244
+ try {
245
+ const container = await lxc.getContainer(name, endpoint);
246
+ await lxc.deleteContainer(socket, endpoint, name, container.status);
247
+ }
248
+ catch (e) {
249
+ // If the container is already gone, treat as success
250
+ if (e instanceof Error && e.message.includes("not found")) {
251
+ console.log(`[lxc] Container ${name} already removed, nothing to delete`);
252
+ }
253
+ else {
254
+ throw e;
255
+ }
256
+ }
242
257
  await pushList();
243
258
  ok("Destroyed");
244
259
  break;
@@ -285,6 +300,30 @@ async function dispatch(socket, endpoint, eventName, args) {
285
300
  snapshots });
286
301
  break;
287
302
  }
303
+ case "createLxcSnapshot": {
304
+ const [containerName] = args;
305
+ if (typeof containerName !== "string") {
306
+ throw new Error("Container name must be a string");
307
+ }
308
+ const snapshotName = await lxc.createSnapshot(containerName);
309
+ callback?.({ ok: true,
310
+ msg: "Snapshot created",
311
+ snapshotName });
312
+ break;
313
+ }
314
+ case "deleteLxcSnapshot": {
315
+ const [containerName, snapshotName] = args;
316
+ if (typeof containerName !== "string") {
317
+ throw new Error("Container name must be a string");
318
+ }
319
+ if (typeof snapshotName !== "string") {
320
+ throw new Error("Snapshot name must be a string");
321
+ }
322
+ await lxc.deleteSnapshot(containerName, snapshotName);
323
+ callback?.({ ok: true,
324
+ msg: "Snapshot deleted" });
325
+ break;
326
+ }
288
327
  case "getLxcDistributions": {
289
328
  const distributions = await lxc.getDistributions();
290
329
  callback?.({ ok: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tyevco/homelab-lxc-agent",
3
- "version": "1.9.14",
3
+ "version": "1.9.16",
4
4
  "description": "Lightweight LXC agent for Homelab",
5
5
  "bin": {
6
6
  "homelab-lxc-agent": "bin/homelab-lxc-agent.js"