@tyevco/homelab-lxc-agent 1.9.1 → 1.9.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/lxc.js CHANGED
@@ -114,6 +114,7 @@ async function getContainerList(endpoint) {
114
114
  isManagedByHomelab: true,
115
115
  };
116
116
  }
117
+ console.log(`[lxc] Found ${Object.keys(result).length} container(s)`);
117
118
  }
118
119
  catch (e) {
119
120
  console.error("[lxc] Failed to get container list:", e instanceof Error ? e.message : e);
@@ -125,6 +126,7 @@ async function getContainer(name, endpoint) {
125
126
  if (!/^[a-z0-9_.-]+$/.test(name)) {
126
127
  throw new Error("Invalid LXC container name");
127
128
  }
129
+ console.log(`[lxc] Getting info for: ${name}`);
128
130
  const res = await (0, promisify_child_process_1.spawn)("lxc-info", ["-n", name], { encoding: "utf-8" });
129
131
  if (!res.stdout) {
130
132
  throw new Error("LXC container not found");
@@ -166,20 +168,25 @@ async function getContainer(name, endpoint) {
166
168
  }
167
169
  exports.getContainer = getContainer;
168
170
  async function startContainer(socket, endpoint, name) {
171
+ console.log(`[lxc] Starting container: ${name}`);
169
172
  const code = await terminal_1.AgentTerminal.exec(socket, getLxcTerminalName(endpoint, name), "lxc-start", ["-n", name], LXC_PATH);
170
173
  if (code !== 0) {
171
174
  throw new Error("Failed to start LXC container");
172
175
  }
176
+ console.log(`[lxc] Started: ${name}`);
173
177
  }
174
178
  exports.startContainer = startContainer;
175
179
  async function stopContainer(socket, endpoint, name) {
180
+ console.log(`[lxc] Stopping container: ${name}`);
176
181
  const code = await terminal_1.AgentTerminal.exec(socket, getLxcTerminalName(endpoint, name), "lxc-stop", ["-n", name], LXC_PATH);
177
182
  if (code !== 0) {
178
183
  throw new Error("Failed to stop LXC container");
179
184
  }
185
+ console.log(`[lxc] Stopped: ${name}`);
180
186
  }
181
187
  exports.stopContainer = stopContainer;
182
188
  async function restartContainer(socket, endpoint, name) {
189
+ console.log(`[lxc] Restarting container: ${name}`);
183
190
  const termName = getLxcTerminalName(endpoint, name);
184
191
  const stopCode = await terminal_1.AgentTerminal.exec(socket, termName, "lxc-stop", ["-n", name], LXC_PATH);
185
192
  if (stopCode !== 0) {
@@ -189,39 +196,49 @@ async function restartContainer(socket, endpoint, name) {
189
196
  if (startCode !== 0) {
190
197
  throw new Error("Failed to start LXC container for restart");
191
198
  }
199
+ console.log(`[lxc] Restarted: ${name}`);
192
200
  }
193
201
  exports.restartContainer = restartContainer;
194
202
  async function freezeContainer(socket, endpoint, name) {
203
+ console.log(`[lxc] Freezing container: ${name}`);
195
204
  const code = await terminal_1.AgentTerminal.exec(socket, getLxcTerminalName(endpoint, name), "lxc-freeze", ["-n", name], LXC_PATH);
196
205
  if (code !== 0) {
197
206
  throw new Error("Failed to freeze LXC container");
198
207
  }
208
+ console.log(`[lxc] Frozen: ${name}`);
199
209
  }
200
210
  exports.freezeContainer = freezeContainer;
201
211
  async function unfreezeContainer(socket, endpoint, name) {
212
+ console.log(`[lxc] Unfreezing container: ${name}`);
202
213
  const code = await terminal_1.AgentTerminal.exec(socket, getLxcTerminalName(endpoint, name), "lxc-unfreeze", ["-n", name], LXC_PATH);
203
214
  if (code !== 0) {
204
215
  throw new Error("Failed to unfreeze LXC container");
205
216
  }
217
+ console.log(`[lxc] Unfrozen: ${name}`);
206
218
  }
207
219
  exports.unfreezeContainer = unfreezeContainer;
208
220
  async function deleteContainer(socket, endpoint, name, status) {
221
+ console.log(`[lxc] Deleting container: ${name}`);
209
222
  const termName = getLxcTerminalName(endpoint, name);
210
223
  if (status === exports.RUNNING || status === exports.FROZEN) {
224
+ console.log(`[lxc] Stopping ${name} before delete`);
211
225
  await terminal_1.AgentTerminal.exec(socket, termName, "lxc-stop", ["-n", name], LXC_PATH);
212
226
  }
213
227
  const code = await terminal_1.AgentTerminal.exec(socket, termName, "lxc-destroy", ["-n", name], LXC_PATH);
214
228
  if (code !== 0) {
215
229
  throw new Error("Failed to destroy LXC container");
216
230
  }
231
+ console.log(`[lxc] Deleted: ${name}`);
217
232
  }
218
233
  exports.deleteContainer = deleteContainer;
219
234
  async function saveConfig(name, config) {
235
+ console.log(`[lxc] Saving config for: ${name}`);
220
236
  const containerPath = path.join(LXC_PATH, name);
221
237
  if (!fs.existsSync(containerPath)) {
222
238
  throw new Error("LXC container not found");
223
239
  }
224
240
  await fs.promises.writeFile(path.join(containerPath, "config"), config);
241
+ console.log(`[lxc] Config saved for: ${name}`);
225
242
  }
226
243
  exports.saveConfig = saveConfig;
227
244
  async function createContainer(socket, endpoint, name, dist, release, arch) {
@@ -237,10 +254,12 @@ async function createContainer(socket, endpoint, name, dist, release, arch) {
237
254
  if (!/^[a-zA-Z0-9_]+$/.test(arch)) {
238
255
  throw new Error("Invalid architecture");
239
256
  }
257
+ console.log(`[lxc] Creating container: ${name} (${dist} ${release} ${arch})`);
240
258
  const code = await terminal_1.AgentTerminal.exec(socket, getLxcTerminalName(endpoint, name), "lxc-create", ["-n", name, "-t", "download", "--", "--dist", dist, "--release", release, "--arch", arch], LXC_PATH);
241
259
  if (code !== 0) {
242
260
  throw new Error("Failed to create LXC container");
243
261
  }
262
+ console.log(`[lxc] Created: ${name}`);
244
263
  }
245
264
  exports.createContainer = createContainer;
246
265
  async function getDistributions() {
package/dist/server.js CHANGED
@@ -54,19 +54,32 @@ function createAgentServer(config) {
54
54
  const httpServer = (0, http_1.createServer)();
55
55
  const io = new socket_io_1.Server(httpServer);
56
56
  let capabilities = { lxcAvailable: false };
57
- const authenticatedSockets = new Set();
57
+ // Maps socket endpoint so rescan can push per-connection data
58
+ const authenticatedSockets = new Map();
58
59
  const emitInfo = (socket) => {
59
60
  socket.emit("info", {
60
61
  version: config.version,
61
62
  ...capabilities,
62
63
  });
63
64
  };
65
+ const pushContainerList = async (socket, endpoint) => {
66
+ const list = await lxc.getContainerList(endpoint);
67
+ console.log(`[lxc] Pushing container list to main server (${Object.keys(list).length} container(s))`);
68
+ socket.emit("agent", "lxcContainerList", { ok: true,
69
+ lxcContainerList: list,
70
+ endpoint });
71
+ };
64
72
  const rescan = async () => {
65
73
  console.log("[agent] Scanning capabilities...");
66
74
  capabilities = await detectCapabilities();
67
- for (const socket of authenticatedSockets) {
75
+ for (const [socket] of authenticatedSockets) {
68
76
  emitInfo(socket);
69
77
  }
78
+ if (capabilities.lxcAvailable) {
79
+ for (const [socket, endpoint] of authenticatedSockets) {
80
+ pushContainerList(socket, endpoint).catch((e) => console.error("[lxc] Failed to push container list during rescan:", e instanceof Error ? e.message : e));
81
+ }
82
+ }
70
83
  };
71
84
  // Initial scan, then periodic rescan
72
85
  rescan().then(() => {
@@ -97,9 +110,13 @@ function createAgentServer(config) {
97
110
  const { username, password } = data;
98
111
  if (username === config.username && password === config.password) {
99
112
  loggedIn = true;
100
- authenticatedSockets.add(socket);
113
+ authenticatedSockets.set(socket, endpoint);
101
114
  console.log(`[agent] Authenticated as ${username}`);
102
115
  cb?.({ ok: true });
116
+ // Immediately push the container list so the main server doesn't have to ask
117
+ if (capabilities.lxcAvailable) {
118
+ pushContainerList(socket, endpoint).catch((e) => console.error("[lxc] Failed to push initial container list:", e instanceof Error ? e.message : e));
119
+ }
103
120
  }
104
121
  else {
105
122
  console.warn(`[agent] Login failed for ${username}`);
@@ -120,6 +137,7 @@ function createAgentServer(config) {
120
137
  if (targetEndpoint !== endpoint && targetEndpoint !== "") {
121
138
  return;
122
139
  }
140
+ console.log(`[agent] Event: ${eventName}`);
123
141
  await dispatch(socket, endpoint, eventName, args);
124
142
  });
125
143
  });
@@ -136,8 +154,11 @@ async function dispatch(socket, endpoint, eventName, args) {
136
154
  ...(msg ? { msg,
137
155
  msgi18n: true } : {}),
138
156
  ...extra });
139
- const fail = (e) => callback?.({ ok: false,
140
- msg: e instanceof Error ? e.message : String(e) });
157
+ const fail = (e) => {
158
+ console.error(`[agent] Error handling ${eventName}:`, e instanceof Error ? e.message : String(e));
159
+ callback?.({ ok: false,
160
+ msg: e instanceof Error ? e.message : String(e) });
161
+ };
141
162
  const pushList = async () => {
142
163
  const list = await lxc.getContainerList(endpoint);
143
164
  socket.emit("agent", "lxcContainerList", { ok: true,
package/dist/terminal.js CHANGED
@@ -74,6 +74,7 @@ class AgentTerminal {
74
74
  if (this._ptyProcess) {
75
75
  return;
76
76
  }
77
+ console.log(`[terminal] Starting: ${this.name} (${this.file} ${this.args.join(" ")})`);
77
78
  try {
78
79
  this._ptyProcess = pty.spawn(this.file, this.args, {
79
80
  name: this.name,
@@ -89,6 +90,7 @@ class AgentTerminal {
89
90
  this.socket.emit("agent", "terminalWrite", this.name, data);
90
91
  });
91
92
  this._ptyProcess.onExit(({ exitCode }) => {
93
+ console.log(`[terminal] Exited: ${this.name} (code ${exitCode})`);
92
94
  this.socket.emit("agent", "terminalExit", this.name, exitCode);
93
95
  AgentTerminal.terminalMap.delete(this.name);
94
96
  this.exitCallback?.(exitCode);
@@ -97,6 +99,7 @@ class AgentTerminal {
97
99
  catch (error) {
98
100
  const msg = error instanceof Error ? error.message : String(error);
99
101
  const exitCode = Number(msg.split(" ").pop()) || 1;
102
+ console.error(`[terminal] Failed to start: ${this.name}: ${msg}`);
100
103
  this.socket.emit("agent", "terminalExit", this.name, exitCode);
101
104
  AgentTerminal.terminalMap.delete(this.name);
102
105
  this.exitCallback?.(exitCode);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tyevco/homelab-lxc-agent",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
4
4
  "description": "Lightweight LXC agent for Homelab",
5
5
  "bin": {
6
6
  "homelab-lxc-agent": "bin/homelab-lxc-agent.js"