@gazzehamine/armada-watch-agent 1.3.2 → 1.4.0

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/collector.js CHANGED
@@ -7,8 +7,13 @@ exports.getSystemInfo = getSystemInfo;
7
7
  exports.collectMetrics = collectMetrics;
8
8
  exports.collectProcesses = collectProcesses;
9
9
  exports.collectDockerContainers = collectDockerContainers;
10
+ exports.collectSSLCertificates = collectSSLCertificates;
10
11
  const systeminformation_1 = __importDefault(require("systeminformation"));
11
12
  const os_1 = __importDefault(require("os"));
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const child_process_1 = require("child_process");
15
+ const util_1 = require("util");
16
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
12
17
  let lastNetworkStats = null;
13
18
  let lastDiskStats = null;
14
19
  async function getSystemInfo() {
@@ -136,9 +141,16 @@ async function collectMetrics() {
136
141
  }
137
142
  async function collectProcesses() {
138
143
  const processes = await systeminformation_1.default.processes();
144
+ // Sort by CPU first, then by memory as tiebreaker
145
+ // Don't filter by cpu > 0 since CPU usage fluctuates rapidly
139
146
  return processes.list
140
- .filter((p) => p.cpu > 0 || p.mem > 0)
141
- .sort((a, b) => b.cpu - a.cpu)
147
+ .sort((a, b) => {
148
+ // Sort by CPU descending, then by memory descending
149
+ if (b.cpu !== a.cpu) {
150
+ return b.cpu - a.cpu;
151
+ }
152
+ return b.mem - a.mem;
153
+ })
142
154
  .slice(0, 20)
143
155
  .map((p) => ({
144
156
  pid: p.pid,
@@ -207,3 +219,82 @@ async function collectDockerContainers() {
207
219
  return [];
208
220
  }
209
221
  }
222
+ /**
223
+ * Get SSL certificate information from a PEM file
224
+ */
225
+ async function getCertificateInfo(certPath, domain) {
226
+ try {
227
+ // Read the certificate file
228
+ const certPem = await fs_1.default.promises.readFile(certPath, 'utf8');
229
+ // Use openssl command to parse the certificate
230
+ const { stdout } = await execAsync(`openssl x509 -in "${certPath}" -noout -dates -issuer -serial -text`);
231
+ // Parse the output
232
+ const notBeforeMatch = stdout.match(/notBefore=(.+)/);
233
+ const notAfterMatch = stdout.match(/notAfter=(.+)/);
234
+ const issuerMatch = stdout.match(/issuer=(.+)/);
235
+ const serialMatch = stdout.match(/serial=(.+)/);
236
+ const algMatch = stdout.match(/Signature Algorithm: (.+)/);
237
+ if (!notBeforeMatch || !notAfterMatch) {
238
+ return null;
239
+ }
240
+ const validFrom = new Date(notBeforeMatch[1]);
241
+ const validTo = new Date(notAfterMatch[1]);
242
+ const now = new Date();
243
+ const daysUntilExpiry = Math.floor((validTo.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
244
+ const isExpired = daysUntilExpiry < 0;
245
+ const isExpiringSoon = daysUntilExpiry <= 30 && daysUntilExpiry >= 0;
246
+ const isValid = !isExpired && validFrom <= now;
247
+ return {
248
+ domain,
249
+ issuer: issuerMatch ? issuerMatch[1].trim() : 'Unknown',
250
+ validFrom,
251
+ validTo,
252
+ daysUntilExpiry,
253
+ isValid,
254
+ isExpired,
255
+ isExpiringSoon,
256
+ serialNumber: serialMatch ? serialMatch[1].trim() : 'Unknown',
257
+ algorithm: algMatch ? algMatch[1].trim() : 'Unknown',
258
+ };
259
+ }
260
+ catch (error) {
261
+ console.error(`Error reading certificate for ${domain}:`, error);
262
+ return null;
263
+ }
264
+ }
265
+ /**
266
+ * Collect SSL certificate information from Certbot certificates
267
+ */
268
+ async function collectSSLCertificates() {
269
+ const certificates = [];
270
+ const certbotLivePath = '/etc/letsencrypt/live';
271
+ try {
272
+ // Check if certbot directory exists
273
+ if (!fs_1.default.existsSync(certbotLivePath)) {
274
+ return certificates;
275
+ }
276
+ // Read all domain directories
277
+ const domains = await fs_1.default.promises.readdir(certbotLivePath);
278
+ for (const domain of domains) {
279
+ // Skip README file
280
+ if (domain === 'README')
281
+ continue;
282
+ const certPath = `${certbotLivePath}/${domain}/fullchain.pem`;
283
+ // Check if certificate file exists
284
+ if (!fs_1.default.existsSync(certPath)) {
285
+ continue;
286
+ }
287
+ const certInfo = await getCertificateInfo(certPath, domain);
288
+ if (certInfo) {
289
+ certificates.push(certInfo);
290
+ }
291
+ }
292
+ // Sort by days until expiry (most urgent first)
293
+ return certificates.sort((a, b) => a.daysUntilExpiry - b.daysUntilExpiry);
294
+ }
295
+ catch (error) {
296
+ // Permission error or certbot not installed
297
+ console.error('Error collecting SSL certificates:', error);
298
+ return certificates;
299
+ }
300
+ }
package/dist/index.js CHANGED
@@ -8,14 +8,27 @@ const dotenv_1 = __importDefault(require("dotenv"));
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const os_1 = __importDefault(require("os"));
10
10
  const collector_1 = require("./collector");
11
+ const fs_1 = require("fs");
12
+ const path_1 = require("path");
11
13
  // Load environment variables
12
14
  dotenv_1.default.config();
15
+ // Get agent version from package.json
16
+ let AGENT_VERSION = "unknown";
17
+ try {
18
+ const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, "..", "package.json"), "utf-8"));
19
+ AGENT_VERSION = packageJson.version;
20
+ }
21
+ catch (error) {
22
+ console.warn("Could not read agent version from package.json");
23
+ }
13
24
  const SERVER_URL = process.env.SERVER_URL || "http://localhost:4000";
14
25
  const INSTANCE_NAME = process.env.INSTANCE_NAME || os_1.default.hostname();
15
26
  const REGION = process.env.REGION || "unknown";
16
27
  const INSTANCE_ID = process.env.INSTANCE_ID || os_1.default.hostname();
17
28
  const COLLECTION_INTERVAL = parseInt(process.env.COLLECTION_INTERVAL || "10") * 1000;
18
29
  let instanceInfo = null;
30
+ let sslCheckCounter = 0;
31
+ const SSL_CHECK_FREQUENCY = 30; // Check SSL every 30 metric collections (e.g., every 5 minutes if collection is 10s)
19
32
  async function initializeAgent() {
20
33
  try {
21
34
  console.log("🔄 Initializing Armada Watch Agent...");
@@ -35,8 +48,10 @@ async function initializeAgent() {
35
48
  hostname: sysInfo.hostname,
36
49
  cpuModel: sysInfo.cpuModel,
37
50
  cpuCores: sysInfo.cpuCores,
51
+ agentVersion: AGENT_VERSION,
38
52
  };
39
53
  console.log("✅ Agent initialized successfully");
54
+ console.log(`📦 Agent version: ${AGENT_VERSION}`);
40
55
  console.log(`🔁 Collection interval: ${COLLECTION_INTERVAL / 1000}s`);
41
56
  }
42
57
  catch (error) {
@@ -49,6 +64,16 @@ async function sendMetrics() {
49
64
  const metrics = await (0, collector_1.collectMetrics)();
50
65
  const processes = await (0, collector_1.collectProcesses)();
51
66
  const dockerContainers = await (0, collector_1.collectDockerContainers)();
67
+ // Check SSL certificates less frequently (every 5 minutes by default)
68
+ let sslCertificates = [];
69
+ sslCheckCounter++;
70
+ if (sslCheckCounter >= SSL_CHECK_FREQUENCY) {
71
+ sslCertificates = await (0, collector_1.collectSSLCertificates)();
72
+ sslCheckCounter = 0;
73
+ if (sslCertificates.length > 0) {
74
+ console.log(`🔐 SSL Certificates checked: ${sslCertificates.length} domain(s)`);
75
+ }
76
+ }
52
77
  const payload = {
53
78
  instanceInfo,
54
79
  metrics: {
@@ -57,6 +82,7 @@ async function sendMetrics() {
57
82
  },
58
83
  processes,
59
84
  dockerContainers,
85
+ sslCertificates: sslCertificates.length > 0 ? sslCertificates : undefined,
60
86
  };
61
87
  await axios_1.default.post(`${SERVER_URL}/api/metrics`, payload, {
62
88
  timeout: 5000,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gazzehamine/armada-watch-agent",
3
- "version": "1.3.2",
4
- "description": "Monitoring agent for Armada Watch - EC2 instance monitoring",
3
+ "version": "1.4.0",
4
+ "description": "Monitoring agent for Armada Watch - EC2 instance monitoring with SSL certificate tracking",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "armada-watch-agent": "dist/index.js"