@glassmkr/crucible 0.3.2 → 0.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/collect/io-errors.d.ts +4 -0
- package/dist/collect/io-errors.js +24 -0
- package/dist/collect/io-errors.js.map +1 -0
- package/dist/collect/security.js +39 -16
- package/dist/collect/security.js.map +1 -1
- package/dist/collect/zfs.d.ts +2 -0
- package/dist/collect/zfs.js +57 -0
- package/dist/collect/zfs.js.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/types.d.ts +17 -0
- package/package.json +1 -1
- package/src/collect/io-errors.ts +23 -0
- package/src/collect/security.ts +43 -16
- package/src/collect/zfs.ts +61 -0
- package/src/index.ts +6 -0
- package/src/lib/types.ts +16 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { run } from "../lib/exec.js";
|
|
2
|
+
export async function collectIoErrors() {
|
|
3
|
+
// Parse dmesg for recent I/O errors (last 10 minutes covers the 5-min collection interval)
|
|
4
|
+
const output = await run("bash", ["-c", 'dmesg -T --since "10 minutes ago" 2>/dev/null | grep -i "I/O error\\|Buffer I/O error\\|blk_update_request.*error"'], 5000);
|
|
5
|
+
if (!output || !output.trim())
|
|
6
|
+
return null;
|
|
7
|
+
const lines = output.trim().split("\n").filter((l) => l.trim());
|
|
8
|
+
if (lines.length === 0)
|
|
9
|
+
return null;
|
|
10
|
+
// Extract device names from error messages
|
|
11
|
+
const deviceSet = new Set();
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
// "blk_update_request: I/O error, dev sda, sector 12345"
|
|
14
|
+
const devMatch = line.match(/dev\s+(\w+)/);
|
|
15
|
+
if (devMatch)
|
|
16
|
+
deviceSet.add(devMatch[1]);
|
|
17
|
+
// "Buffer I/O error on device sda1"
|
|
18
|
+
const bufMatch = line.match(/on device\s+(\w+)/);
|
|
19
|
+
if (bufMatch)
|
|
20
|
+
deviceSet.add(bufMatch[1]);
|
|
21
|
+
}
|
|
22
|
+
return { count: lines.length, devices: Array.from(deviceSet) };
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=io-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io-errors.js","sourceRoot":"","sources":["../../src/collect/io-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,2FAA2F;IAC3F,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,oHAAoH,CAAC,EAAE,IAAI,CAAC,CAAC;IACrK,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAE3C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAChE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,2CAA2C;IAC3C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,yDAAyD;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC3C,IAAI,QAAQ;YAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,oCAAoC;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACjD,IAAI,QAAQ;YAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;AACjE,CAAC"}
|
package/dist/collect/security.js
CHANGED
|
@@ -44,17 +44,23 @@ async function checkSshConfig() {
|
|
|
44
44
|
}
|
|
45
45
|
// === Firewall ===
|
|
46
46
|
async function checkFirewall() {
|
|
47
|
-
// UFW
|
|
47
|
+
// UFW: if installed, its status is authoritative (ignores Docker iptables chains)
|
|
48
48
|
const ufw = await run("ufw", ["status"], 5000);
|
|
49
|
-
if (ufw && ufw.includes("Status:
|
|
50
|
-
|
|
49
|
+
if (ufw && ufw.includes("Status:")) {
|
|
50
|
+
const active = ufw.includes("Status: active");
|
|
51
|
+
return { active, source: "ufw", details: active ? "UFW is active" : "UFW is inactive" };
|
|
51
52
|
}
|
|
52
|
-
// firewalld
|
|
53
|
+
// firewalld: if installed, its status is authoritative
|
|
53
54
|
const fwd = await run("firewall-cmd", ["--state"], 5000);
|
|
54
|
-
if (fwd
|
|
55
|
-
|
|
55
|
+
if (fwd) {
|
|
56
|
+
if (fwd.trim() === "running") {
|
|
57
|
+
return { active: true, source: "firewalld", details: "firewalld is running" };
|
|
58
|
+
}
|
|
59
|
+
if (fwd.includes("not running") || fwd.includes("dead")) {
|
|
60
|
+
return { active: false, source: "firewalld", details: "firewalld is not running" };
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
|
-
// nftables
|
|
63
|
+
// nftables (only if no managed firewall found)
|
|
58
64
|
const nft = await run("nft", ["list", "ruleset"], 5000);
|
|
59
65
|
if (nft) {
|
|
60
66
|
const ruleLines = nft.split("\n").filter((l) => l.trim().match(/^\s*(meta|ip |ip6 |tcp |udp |ct |drop|reject|accept)/));
|
|
@@ -62,17 +68,23 @@ async function checkFirewall() {
|
|
|
62
68
|
return { active: true, source: "nftables", details: `${ruleLines.length} nftables rules` };
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
|
-
// iptables
|
|
71
|
+
// iptables fallback: filter out Docker/container chains to avoid false positives
|
|
66
72
|
const ipt = await run("iptables", ["-L", "-n"], 5000);
|
|
67
73
|
if (ipt) {
|
|
68
|
-
const lines = ipt.split("\n").filter((l) => l.trim() &&
|
|
74
|
+
const lines = ipt.split("\n").filter((l) => l.trim() &&
|
|
75
|
+
!l.startsWith("Chain ") &&
|
|
76
|
+
!l.startsWith("target ") &&
|
|
77
|
+
!l.includes("DOCKER") &&
|
|
78
|
+
!l.includes("docker") &&
|
|
79
|
+
!l.includes("br-") &&
|
|
80
|
+
!l.includes("f2b-"));
|
|
69
81
|
if (lines.length > 0)
|
|
70
|
-
return { active: true, source: "iptables", details: `${lines.length} iptables rules` };
|
|
82
|
+
return { active: true, source: "iptables", details: `${lines.length} user iptables rules` };
|
|
71
83
|
if (ipt.includes("policy DROP") || ipt.includes("policy REJECT")) {
|
|
72
84
|
return { active: true, source: "iptables", details: "Default policy is DROP/REJECT" };
|
|
73
85
|
}
|
|
74
86
|
}
|
|
75
|
-
return { active: false, source: "none", details: "No firewall detected" };
|
|
87
|
+
return { active: false, source: "none", details: "No firewall detected (checked ufw, firewalld, nftables, iptables)" };
|
|
76
88
|
}
|
|
77
89
|
// === Pending Security Updates ===
|
|
78
90
|
async function checkSecurityUpdates() {
|
|
@@ -152,15 +164,26 @@ async function checkAutoUpdates() {
|
|
|
152
164
|
// Debian/Ubuntu: unattended-upgrades
|
|
153
165
|
const uuInstalled = await run("bash", ["-c", 'dpkg -l unattended-upgrades 2>/dev/null | grep "^ii"'], 5000);
|
|
154
166
|
if (uuInstalled) {
|
|
167
|
+
// Check config file
|
|
155
168
|
const autoConf = "/etc/apt/apt.conf.d/20auto-upgrades";
|
|
169
|
+
let configEnabled = false;
|
|
156
170
|
if (existsSync(autoConf)) {
|
|
157
171
|
const content = readFileSync(autoConf, "utf-8");
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
172
|
+
configEnabled = content.includes('Update-Package-Lists "1"') && content.includes('Unattended-Upgrade "1"');
|
|
173
|
+
}
|
|
174
|
+
// Check systemd service state
|
|
175
|
+
const serviceEnabled = (await run("bash", ["-c", "systemctl is-enabled unattended-upgrades 2>/dev/null"], 5000))?.trim() === "enabled";
|
|
176
|
+
const serviceActive = (await run("bash", ["-c", "systemctl is-active unattended-upgrades 2>/dev/null"], 5000))?.trim() === "active";
|
|
177
|
+
if (configEnabled && serviceEnabled) {
|
|
178
|
+
return { configured: true, mechanism: "unattended-upgrades", details: serviceActive ? "Installed, enabled, and running" : "Installed and enabled (service not active)" };
|
|
179
|
+
}
|
|
180
|
+
if (!configEnabled && !serviceEnabled) {
|
|
181
|
+
return { configured: false, mechanism: "unattended-upgrades", details: "Installed but not configured and service disabled" };
|
|
182
|
+
}
|
|
183
|
+
if (!serviceEnabled) {
|
|
184
|
+
return { configured: false, mechanism: "unattended-upgrades", details: "Installed and configured but service disabled" };
|
|
162
185
|
}
|
|
163
|
-
return { configured: false, mechanism: "unattended-upgrades", details: "Installed but
|
|
186
|
+
return { configured: false, mechanism: "unattended-upgrades", details: "Installed but not enabled in 20auto-upgrades" };
|
|
164
187
|
}
|
|
165
188
|
// RHEL/Rocky/Alma: dnf-automatic
|
|
166
189
|
const dnfAuto = await run("bash", ["-c", "rpm -q dnf-automatic 2>/dev/null"], 5000);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/collect/security.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/collect/security.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AA+C3D,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAChG,cAAc,EAAE;QAChB,aAAa,EAAE;QACf,oBAAoB,EAAE;QACtB,0BAA0B,EAAE;QAC5B,iBAAiB,EAAE;QACnB,gBAAgB,EAAE;KACnB,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;AAC/I,CAAC;AAED,cAAc;AAEd,KAAK,UAAU,cAAc;IAC3B,sDAAsD;IACtD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/C,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE;YACrC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;YACrE,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,CAAC,CAAC;QACF,MAAM,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAClD,MAAM,YAAY,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;QACtD,MAAM,mBAAmB,GAAG,eAAe,KAAK,KAAK,IAAI,YAAY,KAAK,IAAI,CAAC;QAC/E,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACxF,CAAC;IAED,uCAAuC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7F,MAAM,IAAI,GAAG,CAAC,GAAW,EAAiB,EAAE;YAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YAC9E,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5C,CAAC,CAAC;QACF,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,mBAAmB,CAAC;QACvE,MAAM,YAAY,GAAG,IAAI,CAAC,wBAAwB,CAAC,IAAI,KAAK,CAAC;QAC7D,MAAM,mBAAmB,GAAG,eAAe,CAAC,WAAW,EAAE,KAAK,KAAK,IAAI,YAAY,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC;QAC3G,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,mBAAmB;AAEnB,KAAK,UAAU,aAAa;IAC1B,kFAAkF;IAClF,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/C,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;IAC1F,CAAC;IAED,uDAAuD;IACvD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,cAAc,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC;QAChF,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACxD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;QACrF,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;IACxD,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC,CAAC;QACxH,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,MAAM,iBAAiB,EAAE,CAAC;QAC7F,CAAC;IACH,CAAC;IAED,iFAAiF;IACjF,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACtD,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACzC,CAAC,CAAC,IAAI,EAAE;YACR,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;YACvB,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;YACxB,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACrB,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACrB,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;YAClB,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACpB,CAAC;QACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,sBAAsB,EAAE,CAAC;QAClH,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACjE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;QACxF,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,mEAAmE,EAAE,CAAC;AACzH,CAAC;AAED,mCAAmC;AAEnC,KAAK,UAAU,oBAAoB;IACjC,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,CAAC;QAAC,SAAS,GAAG,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IAElG,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/F,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,gEAAgE,CAAC,EAAE,KAAK,CAAC,CAAC;QAClH,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3C,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC9G,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACjE,CAAC;IAED,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5J,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QACvD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,GAAG,iEAAiE,CAAC,EAAE,KAAK,CAAC,CAAC;QACzH,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;YAC9I,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC1D,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC/D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iCAAiC;AAEjC,SAAS,0BAA0B;IACjC,MAAM,OAAO,GAAG,yCAAyC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClE,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;gBACpF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;YAC5D,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,wBAAwB;AAExB,KAAK,UAAU,iBAAiB;IAC9B,MAAM,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACrD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,iDAAiD;IACjD,IAAI,UAAU,CAAC,0BAA0B,CAAC,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,oHAAoH,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QACzL,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,6CAA6C;IAC7C,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,oJAAoJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACzM,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,EAAE,CAAC;IACzE,CAAC;IAED,sBAAsB;IACtB,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,gGAAgG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACrJ,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,EAAE,CAAC;IACzE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uBAAuB;AAEvB,KAAK,UAAU,gBAAgB;IAC7B,qCAAqC;IACrC,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,sDAAsD,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5G,IAAI,WAAW,EAAE,CAAC;QAChB,oBAAoB;QACpB,MAAM,QAAQ,GAAG,qCAAqC,CAAC;QACvD,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAChD,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;QAC7G,CAAC;QAED,8BAA8B;QAC9B,MAAM,cAAc,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,sDAAsD,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,SAAS,CAAC;QACvI,MAAM,aAAa,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,qDAAqD,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,QAAQ,CAAC;QAEpI,IAAI,aAAa,IAAI,cAAc,EAAE,CAAC;YACpC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,4CAA4C,EAAE,CAAC;QAC3K,CAAC;QACD,IAAI,CAAC,aAAa,IAAI,CAAC,cAAc,EAAE,CAAC;YACtC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,mDAAmD,EAAE,CAAC;QAC/H,CAAC;QACD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,+CAA+C,EAAE,CAAC;QAC3H,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,8CAA8C,EAAE,CAAC;IAC1H,CAAC;IAED,iCAAiC;IACjC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,kCAAkC,CAAC,EAAE,IAAI,CAAC,CAAC;IACpF,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;QAClD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,sHAAsH,CAAC,EAAE,IAAI,CAAC,CAAC;QAC5K,IAAI,WAAW,IAAI,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACnD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC;QAClG,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC;IACvG,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,iDAAiD,EAAE,CAAC;AAC9G,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { run } from "../lib/exec.js";
|
|
2
|
+
export async function collectZfs() {
|
|
3
|
+
// Check if zpool is installed
|
|
4
|
+
const zpoolPath = await run("which", ["zpool"], 3000);
|
|
5
|
+
if (!zpoolPath || !zpoolPath.trim())
|
|
6
|
+
return null;
|
|
7
|
+
const zpoolStatus = await run("zpool", ["status"], 10000);
|
|
8
|
+
if (!zpoolStatus || !zpoolStatus.trim())
|
|
9
|
+
return null;
|
|
10
|
+
const pools = [];
|
|
11
|
+
let current = null;
|
|
12
|
+
for (const line of zpoolStatus.split("\n")) {
|
|
13
|
+
const poolMatch = line.match(/^\s*pool:\s*(.+)/);
|
|
14
|
+
if (poolMatch) {
|
|
15
|
+
current = {
|
|
16
|
+
name: poolMatch[1].trim(),
|
|
17
|
+
state: "UNKNOWN",
|
|
18
|
+
errors_text: "",
|
|
19
|
+
};
|
|
20
|
+
pools.push(current);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (!current)
|
|
24
|
+
continue;
|
|
25
|
+
const stateMatch = line.match(/^\s*state:\s*(.+)/);
|
|
26
|
+
if (stateMatch) {
|
|
27
|
+
current.state = stateMatch[1].trim();
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const errorsMatch = line.match(/^\s*errors:\s*(.+)/);
|
|
31
|
+
if (errorsMatch) {
|
|
32
|
+
current.errors_text = errorsMatch[1].trim();
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
// Parse scrub info
|
|
36
|
+
if (line.includes("scan:")) {
|
|
37
|
+
if (line.includes("none requested")) {
|
|
38
|
+
current.scrub_never_run = true;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const repairMatch = line.match(/scrub repaired (\S+) in .* with (\d+) errors/);
|
|
42
|
+
if (repairMatch) {
|
|
43
|
+
current.scrub_repaired = repairMatch[1];
|
|
44
|
+
current.scrub_errors = parseInt(repairMatch[2]) || 0;
|
|
45
|
+
}
|
|
46
|
+
const dateMatch = line.match(/on (.+)$/);
|
|
47
|
+
if (dateMatch) {
|
|
48
|
+
current.last_scrub_date = dateMatch[1].trim();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (pools.length === 0)
|
|
54
|
+
return null;
|
|
55
|
+
return { pools };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=zfs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zfs.js","sourceRoot":"","sources":["../../src/collect/zfs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAGrC,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,8BAA8B;IAC9B,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;IACtD,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAEjD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAC1D,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAErD,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,IAAI,OAAO,GAAmB,IAAI,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACjD,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,GAAG;gBACR,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBACzB,KAAK,EAAE,SAAS;gBAChB,WAAW,EAAE,EAAE;aAChB,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACnD,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACrD,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,mBAAmB;QACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;gBAC/E,IAAI,WAAW,EAAE,CAAC;oBAChB,OAAO,CAAC,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;oBACxC,OAAO,CAAC,YAAY,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACvD,CAAC;gBACD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBACzC,IAAI,SAAS,EAAE,CAAC;oBACd,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAChD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,8 @@ import { sendSlack } from "./notify/slack.js";
|
|
|
31
31
|
import { sendEmail } from "./notify/email.js";
|
|
32
32
|
import { pushToForge, initForgeAgent } from "./push/forge.js";
|
|
33
33
|
import { collectSecurity } from "./collect/security.js";
|
|
34
|
+
import { collectZfs } from "./collect/zfs.js";
|
|
35
|
+
import { collectIoErrors } from "./collect/io-errors.js";
|
|
34
36
|
const configPath = process.argv[2] || "/etc/glassmkr/collector.yaml";
|
|
35
37
|
const config = loadConfig(configPath);
|
|
36
38
|
console.log(`[collector] Starting. Server: ${config.server_name}. Interval: ${config.collection.interval_seconds}s`);
|
|
@@ -81,6 +83,15 @@ async function collect() {
|
|
|
81
83
|
system, cpu, memory, disks, smart, network, raid, ipmi, os_alerts: osAlerts,
|
|
82
84
|
security: cachedSecurity,
|
|
83
85
|
};
|
|
86
|
+
// ZFS and I/O errors: collect every cycle (lightweight checks)
|
|
87
|
+
try {
|
|
88
|
+
snapshot.zfs = await collectZfs() ?? undefined;
|
|
89
|
+
}
|
|
90
|
+
catch { /* skip if ZFS not available */ }
|
|
91
|
+
try {
|
|
92
|
+
snapshot.io_errors = await collectIoErrors() ?? undefined;
|
|
93
|
+
}
|
|
94
|
+
catch { /* skip on error */ }
|
|
84
95
|
// Update Prometheus metrics
|
|
85
96
|
updateMetrics(snapshot);
|
|
86
97
|
// Evaluate alerts
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACpF,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AACL,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAqB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -11,6 +11,23 @@ export interface Snapshot {
|
|
|
11
11
|
ipmi: IpmiInfo;
|
|
12
12
|
os_alerts: OsAlerts;
|
|
13
13
|
security?: SecurityData;
|
|
14
|
+
zfs?: ZfsData;
|
|
15
|
+
io_errors?: {
|
|
16
|
+
count: number;
|
|
17
|
+
devices: string[];
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface ZfsPool {
|
|
21
|
+
name: string;
|
|
22
|
+
state: string;
|
|
23
|
+
errors_text: string;
|
|
24
|
+
scrub_errors?: number;
|
|
25
|
+
scrub_repaired?: string;
|
|
26
|
+
last_scrub_date?: string;
|
|
27
|
+
scrub_never_run?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ZfsData {
|
|
30
|
+
pools: ZfsPool[];
|
|
14
31
|
}
|
|
15
32
|
export interface SecurityData {
|
|
16
33
|
ssh: {
|
package/package.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { run } from "../lib/exec.js";
|
|
2
|
+
|
|
3
|
+
export async function collectIoErrors(): Promise<{ count: number; devices: string[] } | null> {
|
|
4
|
+
// Parse dmesg for recent I/O errors (last 10 minutes covers the 5-min collection interval)
|
|
5
|
+
const output = await run("bash", ["-c", 'dmesg -T --since "10 minutes ago" 2>/dev/null | grep -i "I/O error\\|Buffer I/O error\\|blk_update_request.*error"'], 5000);
|
|
6
|
+
if (!output || !output.trim()) return null;
|
|
7
|
+
|
|
8
|
+
const lines = output.trim().split("\n").filter((l) => l.trim());
|
|
9
|
+
if (lines.length === 0) return null;
|
|
10
|
+
|
|
11
|
+
// Extract device names from error messages
|
|
12
|
+
const deviceSet = new Set<string>();
|
|
13
|
+
for (const line of lines) {
|
|
14
|
+
// "blk_update_request: I/O error, dev sda, sector 12345"
|
|
15
|
+
const devMatch = line.match(/dev\s+(\w+)/);
|
|
16
|
+
if (devMatch) deviceSet.add(devMatch[1]);
|
|
17
|
+
// "Buffer I/O error on device sda1"
|
|
18
|
+
const bufMatch = line.match(/on device\s+(\w+)/);
|
|
19
|
+
if (bufMatch) deviceSet.add(bufMatch[1]);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { count: lines.length, devices: Array.from(deviceSet) };
|
|
23
|
+
}
|
package/src/collect/security.ts
CHANGED
|
@@ -95,19 +95,25 @@ async function checkSshConfig(): Promise<SshSecurityStatus | null> {
|
|
|
95
95
|
// === Firewall ===
|
|
96
96
|
|
|
97
97
|
async function checkFirewall(): Promise<FirewallStatus> {
|
|
98
|
-
// UFW
|
|
98
|
+
// UFW: if installed, its status is authoritative (ignores Docker iptables chains)
|
|
99
99
|
const ufw = await run("ufw", ["status"], 5000);
|
|
100
|
-
if (ufw && ufw.includes("Status:
|
|
101
|
-
|
|
100
|
+
if (ufw && ufw.includes("Status:")) {
|
|
101
|
+
const active = ufw.includes("Status: active");
|
|
102
|
+
return { active, source: "ufw", details: active ? "UFW is active" : "UFW is inactive" };
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
// firewalld
|
|
105
|
+
// firewalld: if installed, its status is authoritative
|
|
105
106
|
const fwd = await run("firewall-cmd", ["--state"], 5000);
|
|
106
|
-
if (fwd
|
|
107
|
-
|
|
107
|
+
if (fwd) {
|
|
108
|
+
if (fwd.trim() === "running") {
|
|
109
|
+
return { active: true, source: "firewalld", details: "firewalld is running" };
|
|
110
|
+
}
|
|
111
|
+
if (fwd.includes("not running") || fwd.includes("dead")) {
|
|
112
|
+
return { active: false, source: "firewalld", details: "firewalld is not running" };
|
|
113
|
+
}
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
// nftables
|
|
116
|
+
// nftables (only if no managed firewall found)
|
|
111
117
|
const nft = await run("nft", ["list", "ruleset"], 5000);
|
|
112
118
|
if (nft) {
|
|
113
119
|
const ruleLines = nft.split("\n").filter((l) => l.trim().match(/^\s*(meta|ip |ip6 |tcp |udp |ct |drop|reject|accept)/));
|
|
@@ -116,17 +122,25 @@ async function checkFirewall(): Promise<FirewallStatus> {
|
|
|
116
122
|
}
|
|
117
123
|
}
|
|
118
124
|
|
|
119
|
-
// iptables
|
|
125
|
+
// iptables fallback: filter out Docker/container chains to avoid false positives
|
|
120
126
|
const ipt = await run("iptables", ["-L", "-n"], 5000);
|
|
121
127
|
if (ipt) {
|
|
122
|
-
const lines = ipt.split("\n").filter((l) =>
|
|
123
|
-
|
|
128
|
+
const lines = ipt.split("\n").filter((l) =>
|
|
129
|
+
l.trim() &&
|
|
130
|
+
!l.startsWith("Chain ") &&
|
|
131
|
+
!l.startsWith("target ") &&
|
|
132
|
+
!l.includes("DOCKER") &&
|
|
133
|
+
!l.includes("docker") &&
|
|
134
|
+
!l.includes("br-") &&
|
|
135
|
+
!l.includes("f2b-")
|
|
136
|
+
);
|
|
137
|
+
if (lines.length > 0) return { active: true, source: "iptables", details: `${lines.length} user iptables rules` };
|
|
124
138
|
if (ipt.includes("policy DROP") || ipt.includes("policy REJECT")) {
|
|
125
139
|
return { active: true, source: "iptables", details: "Default policy is DROP/REJECT" };
|
|
126
140
|
}
|
|
127
141
|
}
|
|
128
142
|
|
|
129
|
-
return { active: false, source: "none", details: "No firewall detected" };
|
|
143
|
+
return { active: false, source: "none", details: "No firewall detected (checked ufw, firewalld, nftables, iptables)" };
|
|
130
144
|
}
|
|
131
145
|
|
|
132
146
|
// === Pending Security Updates ===
|
|
@@ -213,15 +227,28 @@ async function checkAutoUpdates(): Promise<AutoUpdateStatus> {
|
|
|
213
227
|
// Debian/Ubuntu: unattended-upgrades
|
|
214
228
|
const uuInstalled = await run("bash", ["-c", 'dpkg -l unattended-upgrades 2>/dev/null | grep "^ii"'], 5000);
|
|
215
229
|
if (uuInstalled) {
|
|
230
|
+
// Check config file
|
|
216
231
|
const autoConf = "/etc/apt/apt.conf.d/20auto-upgrades";
|
|
232
|
+
let configEnabled = false;
|
|
217
233
|
if (existsSync(autoConf)) {
|
|
218
234
|
const content = readFileSync(autoConf, "utf-8");
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
235
|
+
configEnabled = content.includes('Update-Package-Lists "1"') && content.includes('Unattended-Upgrade "1"');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Check systemd service state
|
|
239
|
+
const serviceEnabled = (await run("bash", ["-c", "systemctl is-enabled unattended-upgrades 2>/dev/null"], 5000))?.trim() === "enabled";
|
|
240
|
+
const serviceActive = (await run("bash", ["-c", "systemctl is-active unattended-upgrades 2>/dev/null"], 5000))?.trim() === "active";
|
|
241
|
+
|
|
242
|
+
if (configEnabled && serviceEnabled) {
|
|
243
|
+
return { configured: true, mechanism: "unattended-upgrades", details: serviceActive ? "Installed, enabled, and running" : "Installed and enabled (service not active)" };
|
|
244
|
+
}
|
|
245
|
+
if (!configEnabled && !serviceEnabled) {
|
|
246
|
+
return { configured: false, mechanism: "unattended-upgrades", details: "Installed but not configured and service disabled" };
|
|
247
|
+
}
|
|
248
|
+
if (!serviceEnabled) {
|
|
249
|
+
return { configured: false, mechanism: "unattended-upgrades", details: "Installed and configured but service disabled" };
|
|
223
250
|
}
|
|
224
|
-
return { configured: false, mechanism: "unattended-upgrades", details: "Installed but
|
|
251
|
+
return { configured: false, mechanism: "unattended-upgrades", details: "Installed but not enabled in 20auto-upgrades" };
|
|
225
252
|
}
|
|
226
253
|
|
|
227
254
|
// RHEL/Rocky/Alma: dnf-automatic
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { run } from "../lib/exec.js";
|
|
2
|
+
import type { ZfsData, ZfsPool } from "../lib/types.js";
|
|
3
|
+
|
|
4
|
+
export async function collectZfs(): Promise<ZfsData | null> {
|
|
5
|
+
// Check if zpool is installed
|
|
6
|
+
const zpoolPath = await run("which", ["zpool"], 3000);
|
|
7
|
+
if (!zpoolPath || !zpoolPath.trim()) return null;
|
|
8
|
+
|
|
9
|
+
const zpoolStatus = await run("zpool", ["status"], 10000);
|
|
10
|
+
if (!zpoolStatus || !zpoolStatus.trim()) return null;
|
|
11
|
+
|
|
12
|
+
const pools: ZfsPool[] = [];
|
|
13
|
+
let current: ZfsPool | null = null;
|
|
14
|
+
|
|
15
|
+
for (const line of zpoolStatus.split("\n")) {
|
|
16
|
+
const poolMatch = line.match(/^\s*pool:\s*(.+)/);
|
|
17
|
+
if (poolMatch) {
|
|
18
|
+
current = {
|
|
19
|
+
name: poolMatch[1].trim(),
|
|
20
|
+
state: "UNKNOWN",
|
|
21
|
+
errors_text: "",
|
|
22
|
+
};
|
|
23
|
+
pools.push(current);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!current) continue;
|
|
28
|
+
|
|
29
|
+
const stateMatch = line.match(/^\s*state:\s*(.+)/);
|
|
30
|
+
if (stateMatch) {
|
|
31
|
+
current.state = stateMatch[1].trim();
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const errorsMatch = line.match(/^\s*errors:\s*(.+)/);
|
|
36
|
+
if (errorsMatch) {
|
|
37
|
+
current.errors_text = errorsMatch[1].trim();
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Parse scrub info
|
|
42
|
+
if (line.includes("scan:")) {
|
|
43
|
+
if (line.includes("none requested")) {
|
|
44
|
+
current.scrub_never_run = true;
|
|
45
|
+
} else {
|
|
46
|
+
const repairMatch = line.match(/scrub repaired (\S+) in .* with (\d+) errors/);
|
|
47
|
+
if (repairMatch) {
|
|
48
|
+
current.scrub_repaired = repairMatch[1];
|
|
49
|
+
current.scrub_errors = parseInt(repairMatch[2]) || 0;
|
|
50
|
+
}
|
|
51
|
+
const dateMatch = line.match(/on (.+)$/);
|
|
52
|
+
if (dateMatch) {
|
|
53
|
+
current.last_scrub_date = dateMatch[1].trim();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (pools.length === 0) return null;
|
|
60
|
+
return { pools };
|
|
61
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -32,6 +32,8 @@ import { sendSlack } from "./notify/slack.js";
|
|
|
32
32
|
import { sendEmail } from "./notify/email.js";
|
|
33
33
|
import { pushToForge, initForgeAgent } from "./push/forge.js";
|
|
34
34
|
import { collectSecurity, type SecurityData } from "./collect/security.js";
|
|
35
|
+
import { collectZfs } from "./collect/zfs.js";
|
|
36
|
+
import { collectIoErrors } from "./collect/io-errors.js";
|
|
35
37
|
import type { Snapshot, IpmiInfo } from "./lib/types.js";
|
|
36
38
|
|
|
37
39
|
const configPath = process.argv[2] || "/etc/glassmkr/collector.yaml";
|
|
@@ -89,6 +91,10 @@ async function collect() {
|
|
|
89
91
|
security: cachedSecurity,
|
|
90
92
|
};
|
|
91
93
|
|
|
94
|
+
// ZFS and I/O errors: collect every cycle (lightweight checks)
|
|
95
|
+
try { snapshot.zfs = await collectZfs() ?? undefined; } catch { /* skip if ZFS not available */ }
|
|
96
|
+
try { snapshot.io_errors = await collectIoErrors() ?? undefined; } catch { /* skip on error */ }
|
|
97
|
+
|
|
92
98
|
// Update Prometheus metrics
|
|
93
99
|
updateMetrics(snapshot);
|
|
94
100
|
|
package/src/lib/types.ts
CHANGED
|
@@ -11,6 +11,22 @@ export interface Snapshot {
|
|
|
11
11
|
ipmi: IpmiInfo;
|
|
12
12
|
os_alerts: OsAlerts;
|
|
13
13
|
security?: SecurityData;
|
|
14
|
+
zfs?: ZfsData;
|
|
15
|
+
io_errors?: { count: number; devices: string[] };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ZfsPool {
|
|
19
|
+
name: string;
|
|
20
|
+
state: string;
|
|
21
|
+
errors_text: string;
|
|
22
|
+
scrub_errors?: number;
|
|
23
|
+
scrub_repaired?: string;
|
|
24
|
+
last_scrub_date?: string;
|
|
25
|
+
scrub_never_run?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ZfsData {
|
|
29
|
+
pools: ZfsPool[];
|
|
14
30
|
}
|
|
15
31
|
|
|
16
32
|
export interface SecurityData {
|