@glassmkr/crucible 0.6.5 → 0.7.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/.dockerignore +13 -0
- package/.github/workflows/docker.yml +53 -0
- package/Dockerfile +59 -0
- package/README.md +71 -2
- package/dist/__tests__/reboot-marker.test.d.ts +1 -0
- package/dist/__tests__/reboot-marker.test.js +110 -0
- package/dist/__tests__/reboot-marker.test.js.map +1 -0
- package/dist/cli.d.ts +4 -1
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -1
- package/dist/collect/__tests__/system.test.d.ts +1 -0
- package/dist/collect/__tests__/system.test.js +25 -0
- package/dist/collect/__tests__/system.test.js.map +1 -0
- package/dist/collect/network.js +60 -0
- package/dist/collect/network.js.map +1 -1
- package/dist/collect/system.d.ts +1 -0
- package/dist/collect/system.js +10 -0
- package/dist/collect/system.js.map +1 -1
- package/dist/index.js +54 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/reboot-marker.d.ts +35 -0
- package/dist/lib/reboot-marker.js +95 -0
- package/dist/lib/reboot-marker.js.map +1 -0
- package/dist/lib/types.d.ts +19 -0
- package/docker-compose.yml +26 -0
- package/package.json +1 -1
- package/src/__tests__/reboot-marker.test.ts +122 -0
- package/src/cli.ts +51 -1
- package/src/collect/__tests__/system.test.ts +29 -0
- package/src/collect/network.ts +58 -0
- package/src/collect/system.ts +11 -0
- package/src/index.ts +53 -4
- package/src/lib/reboot-marker.ts +88 -0
- package/src/lib/types.ts +23 -0
package/.dockerignore
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Build and publish Docker image
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ['v*']
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
packages: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
docker:
|
|
14
|
+
name: Build and push to ghcr.io and docker.io
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: docker/setup-buildx-action@v3
|
|
20
|
+
|
|
21
|
+
- uses: docker/login-action@v3
|
|
22
|
+
with:
|
|
23
|
+
registry: ghcr.io
|
|
24
|
+
username: ${{ github.actor }}
|
|
25
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
26
|
+
|
|
27
|
+
- uses: docker/login-action@v3
|
|
28
|
+
with:
|
|
29
|
+
registry: docker.io
|
|
30
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
31
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
32
|
+
|
|
33
|
+
- uses: docker/metadata-action@v5
|
|
34
|
+
id: meta
|
|
35
|
+
with:
|
|
36
|
+
images: |
|
|
37
|
+
ghcr.io/glassmkr/crucible
|
|
38
|
+
docker.io/glassmkr/crucible
|
|
39
|
+
tags: |
|
|
40
|
+
type=semver,pattern={{version}}
|
|
41
|
+
type=semver,pattern={{major}}.{{minor}}
|
|
42
|
+
type=raw,value=latest,enable={{is_default_branch}}
|
|
43
|
+
type=sha,prefix=sha-,format=short
|
|
44
|
+
|
|
45
|
+
- uses: docker/build-push-action@v6
|
|
46
|
+
with:
|
|
47
|
+
context: .
|
|
48
|
+
platforms: linux/amd64
|
|
49
|
+
push: true
|
|
50
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
51
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
52
|
+
cache-from: type=gha
|
|
53
|
+
cache-to: type=gha,mode=max
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.7
|
|
2
|
+
# Multi-stage build for Glassmkr Crucible monitoring agent.
|
|
3
|
+
|
|
4
|
+
# ---------- Stage 1: build TypeScript to dist/ ----------
|
|
5
|
+
FROM node:24-slim AS builder
|
|
6
|
+
WORKDIR /build
|
|
7
|
+
COPY package.json package-lock.json* ./
|
|
8
|
+
RUN npm install --include=dev --no-audit --no-fund
|
|
9
|
+
COPY tsconfig.json ./
|
|
10
|
+
COPY src ./src
|
|
11
|
+
RUN npm run build
|
|
12
|
+
|
|
13
|
+
# ---------- Stage 2: production runtime ----------
|
|
14
|
+
FROM node:24-slim AS runtime
|
|
15
|
+
|
|
16
|
+
# Hardware monitoring tools. Crucible shells out to these; they must be on PATH.
|
|
17
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
18
|
+
smartmontools \
|
|
19
|
+
ipmitool \
|
|
20
|
+
dmidecode \
|
|
21
|
+
lm-sensors \
|
|
22
|
+
ethtool \
|
|
23
|
+
util-linux \
|
|
24
|
+
procps \
|
|
25
|
+
net-tools \
|
|
26
|
+
iproute2 \
|
|
27
|
+
ca-certificates \
|
|
28
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
29
|
+
|
|
30
|
+
WORKDIR /app
|
|
31
|
+
|
|
32
|
+
# Production node_modules only.
|
|
33
|
+
COPY package.json package-lock.json* ./
|
|
34
|
+
RUN npm ci --omit=dev --no-audit --no-fund && npm cache clean --force
|
|
35
|
+
|
|
36
|
+
# Built code.
|
|
37
|
+
COPY --from=builder /build/dist ./dist
|
|
38
|
+
|
|
39
|
+
# Create a non-root user for future use. IPMI and SMART typically require root,
|
|
40
|
+
# so the container is expected to run with --privileged or cap_add DAC_READ_SEARCH etc.
|
|
41
|
+
# Keeping the user available lets operators drop privileges when hardware access is not needed.
|
|
42
|
+
RUN useradd --system --no-create-home --shell /usr/sbin/nologin glassmkr
|
|
43
|
+
|
|
44
|
+
# Crucible reads /etc/glassmkr/collector.yaml by default.
|
|
45
|
+
# Mount the host config directory at this path.
|
|
46
|
+
RUN mkdir -p /etc/glassmkr
|
|
47
|
+
|
|
48
|
+
# Container health: verify the Node process is actually running and hasn't crashed.
|
|
49
|
+
HEALTHCHECK --interval=60s --timeout=10s --start-period=30s --retries=3 \
|
|
50
|
+
CMD pgrep -f "node /app/dist/index.js" > /dev/null || exit 1
|
|
51
|
+
|
|
52
|
+
LABEL org.opencontainers.image.source="https://github.com/glassmkr/crucible" \
|
|
53
|
+
org.opencontainers.image.description="Glassmkr Crucible - bare metal server monitoring agent" \
|
|
54
|
+
org.opencontainers.image.licenses="MIT" \
|
|
55
|
+
org.opencontainers.image.title="Crucible" \
|
|
56
|
+
org.opencontainers.image.vendor="Glassmkr"
|
|
57
|
+
|
|
58
|
+
# Crucible does not listen on any port; data flows outbound to Forge.
|
|
59
|
+
ENTRYPOINT ["node", "/app/dist/index.js"]
|
package/README.md
CHANGED
|
@@ -3,10 +3,25 @@
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|
[](https://www.npmjs.com/package/@glassmkr/crucible)
|
|
5
5
|
|
|
6
|
-
Lightweight bare metal server monitoring agent. Collects hardware and OS health every 5 minutes and pushes snapshots to a [Forge](https://forge.glassmkr.com) dashboard, which evaluates
|
|
6
|
+
Lightweight bare metal server monitoring agent. Collects hardware and OS health every 5 minutes and pushes snapshots to a [Forge](https://forge.glassmkr.com) dashboard, which evaluates 38 alert rules and sends notifications.
|
|
7
7
|
|
|
8
8
|
Open source. MIT licensed. Built by [Glassmkr](https://glassmkr.com). See also [Bench](https://github.com/glassmkr/bench), the MCP server collection.
|
|
9
9
|
|
|
10
|
+
**Resource usage:** ~90MB RSS memory (varies by hardware: servers with more IPMI sensors use more), <0.1% CPU at 5-minute collection interval. Collects IPMI, SMART, ZFS, network bonds, security posture, conntrack, systemd, NTP, and file descriptors.
|
|
11
|
+
|
|
12
|
+
**Security:** See [glassmkr.com/security](https://glassmkr.com/security) for the full list of what Crucible does and does not collect.
|
|
13
|
+
|
|
14
|
+
## Screenshots
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
*Alerts grouped by server, with AI-generated fix commands for each rule.*
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
*Per-disk SMART status, storage capacity, and network interface bonding.*
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
*Security posture, server overview, and active alerts.*
|
|
24
|
+
|
|
10
25
|
## Install
|
|
11
26
|
|
|
12
27
|
```bash
|
|
@@ -19,6 +34,35 @@ Or use the bootstrap script:
|
|
|
19
34
|
curl -sf https://forge.glassmkr.com/install | bash
|
|
20
35
|
```
|
|
21
36
|
|
|
37
|
+
## Docker
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Create config directory
|
|
41
|
+
sudo mkdir -p /etc/glassmkr
|
|
42
|
+
|
|
43
|
+
# Create config (replace with your Forge credentials)
|
|
44
|
+
sudo tee /etc/glassmkr/collector.yaml << 'EOF'
|
|
45
|
+
server_name: "web-01"
|
|
46
|
+
collection:
|
|
47
|
+
interval_seconds: 300
|
|
48
|
+
ipmi: true
|
|
49
|
+
smart: true
|
|
50
|
+
forge:
|
|
51
|
+
enabled: true
|
|
52
|
+
url: "https://forge.glassmkr.com"
|
|
53
|
+
api_key: "col_YOUR_KEY_HERE"
|
|
54
|
+
EOF
|
|
55
|
+
|
|
56
|
+
# Run with docker compose
|
|
57
|
+
curl -O https://raw.githubusercontent.com/glassmkr/crucible/main/docker-compose.yml
|
|
58
|
+
docker compose up -d
|
|
59
|
+
|
|
60
|
+
# Check logs
|
|
61
|
+
docker compose logs -f crucible
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Images are published to [ghcr.io/glassmkr/crucible](https://github.com/glassmkr/crucible/pkgs/container/crucible) on every tag release. The container needs `--privileged` and `network_mode: host` for IPMI, SMART, and accurate host network monitoring. Details in the [compose file](./docker-compose.yml).
|
|
65
|
+
|
|
22
66
|
## Quick Start
|
|
23
67
|
|
|
24
68
|
1. Create an API key in the Forge dashboard (Servers, then Add server).
|
|
@@ -48,6 +92,8 @@ curl -sf https://forge.glassmkr.com/install | bash
|
|
|
48
92
|
|
|
49
93
|
```
|
|
50
94
|
glassmkr-crucible [options]
|
|
95
|
+
glassmkr-crucible mark-reboot [--reason TEXT] [--ttl DURATION]
|
|
96
|
+
glassmkr-crucible reboot [--reason TEXT] [--ttl DURATION]
|
|
51
97
|
|
|
52
98
|
Options:
|
|
53
99
|
-v, --version Print version and exit
|
|
@@ -57,6 +103,29 @@ Options:
|
|
|
57
103
|
|
|
58
104
|
`--config=PATH` and the legacy positional form `glassmkr-crucible /path/to.yaml` both work. Without options, Crucible runs as a long-lived collector daemon.
|
|
59
105
|
|
|
106
|
+
## Rebooting without noise
|
|
107
|
+
|
|
108
|
+
Crucible distinguishes planned reboots from unplanned ones and gives each rule a short grace period after boot so that transient conditions (bond slave still negotiating, clock not synced yet) do not page you.
|
|
109
|
+
|
|
110
|
+
Before a planned reboot:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
sudo glassmkr-crucible reboot --reason "kernel update"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Or, if you prefer to trigger the reboot yourself:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
sudo glassmkr-crucible mark-reboot --reason "kernel update"
|
|
120
|
+
sudo reboot
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Both write a short-lived marker to `/var/lib/crucible/reboot-expected`. The agent reads it once on startup, sets `expected_reboot: true` on the first post-boot snapshot, and deletes the file. Forge reads that flag and suppresses the `server_rebooted_unexpectedly` alert for that boot only.
|
|
124
|
+
|
|
125
|
+
The marker is single-use and expires 10 minutes after it is written (override with `--ttl 5m` / `--ttl 1h`), so a forgotten marker cannot silence a genuine crash reboot next week. If systemd fails to reboot the host, the marker simply expires on its own.
|
|
126
|
+
|
|
127
|
+
Per-rule grace windows are applied separately: bond-slave-down and CPU-temperature get 60 s, interface errors 120 s, clock-sync / NTP 300 s, others 0 s. Suppressed evaluations are recorded in alert history with status `suppressed_boot_grace` or `suppressed_planned_reboot` so you can audit exactly why a rule didn't fire during a given boot.
|
|
128
|
+
|
|
60
129
|
## Systemd Service
|
|
61
130
|
|
|
62
131
|
Create `/etc/systemd/system/glassmkr-crucible.service`:
|
|
@@ -104,7 +173,7 @@ sudo systemctl status glassmkr-crucible
|
|
|
104
173
|
| NTP | Sync state and source |
|
|
105
174
|
| File descriptors | System-wide allocation |
|
|
106
175
|
|
|
107
|
-
Forge evaluates
|
|
176
|
+
Forge evaluates 38 alert rules server-side across OS, Storage, Network, Hardware, ZFS, Security, and Service Health, with priorities P1 Urgent through P4 Low. Full list: [forge.glassmkr.com/docs/alerts](https://forge.glassmkr.com/docs/alerts).
|
|
108
177
|
|
|
109
178
|
## Requirements
|
|
110
179
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtempSync, existsSync, writeFileSync, statSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { consumeRebootMarker, writeRebootMarker, parseDuration, } from "../lib/reboot-marker.js";
|
|
6
|
+
import { parseCliArgs } from "../cli.js";
|
|
7
|
+
let tmpDir;
|
|
8
|
+
let path;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
tmpDir = mkdtempSync(join(tmpdir(), "crucible-test-"));
|
|
11
|
+
path = join(tmpDir, "reboot-expected");
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
try {
|
|
15
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
});
|
|
19
|
+
describe("consumeRebootMarker", () => {
|
|
20
|
+
it("7. marker present, not expired: returns flag, deletes file", () => {
|
|
21
|
+
const future = new Date(Date.now() + 5 * 60_000).toISOString();
|
|
22
|
+
writeFileSync(path, JSON.stringify({ expires_at: future, reason: "kernel update" }));
|
|
23
|
+
const out = consumeRebootMarker(path);
|
|
24
|
+
expect(out).toEqual({ expected: true, reason: "kernel update" });
|
|
25
|
+
expect(existsSync(path)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
it("8. marker present, expired: returns null, deletes file", () => {
|
|
28
|
+
const past = new Date(Date.now() - 60_000).toISOString();
|
|
29
|
+
writeFileSync(path, JSON.stringify({ expires_at: past, reason: "stale" }));
|
|
30
|
+
expect(consumeRebootMarker(path)).toBeNull();
|
|
31
|
+
expect(existsSync(path)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
it("9. marker absent: returns null, no throw", () => {
|
|
34
|
+
expect(consumeRebootMarker(path)).toBeNull();
|
|
35
|
+
});
|
|
36
|
+
it("15. malformed JSON: returns null, file deleted, no crash", () => {
|
|
37
|
+
writeFileSync(path, "{not json at all");
|
|
38
|
+
expect(consumeRebootMarker(path)).toBeNull();
|
|
39
|
+
expect(existsSync(path)).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
it("invalid expires_at (missing): returns null, file deleted", () => {
|
|
42
|
+
writeFileSync(path, JSON.stringify({ reason: "oops" }));
|
|
43
|
+
expect(consumeRebootMarker(path)).toBeNull();
|
|
44
|
+
expect(existsSync(path)).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
it("consumed marker cannot be re-read (single-use)", () => {
|
|
47
|
+
const future = new Date(Date.now() + 60_000).toISOString();
|
|
48
|
+
writeFileSync(path, JSON.stringify({ expires_at: future }));
|
|
49
|
+
expect(consumeRebootMarker(path)).not.toBeNull();
|
|
50
|
+
expect(consumeRebootMarker(path)).toBeNull();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe("writeRebootMarker", () => {
|
|
54
|
+
it("13. writes file at given path with correct TTL and reason, 0600 mode", () => {
|
|
55
|
+
const now = new Date("2026-04-21T22:00:00Z");
|
|
56
|
+
const res = writeRebootMarker({ path, reason: "kernel update", ttlMs: 10 * 60_000, now });
|
|
57
|
+
expect(res.path).toBe(path);
|
|
58
|
+
expect(res.expires_at).toBe("2026-04-21T22:10:00.000Z");
|
|
59
|
+
expect(existsSync(path)).toBe(true);
|
|
60
|
+
const mode = statSync(path).mode & 0o777;
|
|
61
|
+
expect(mode).toBe(0o600);
|
|
62
|
+
const round = consumeRebootMarker(path, new Date("2026-04-21T22:05:00Z"));
|
|
63
|
+
expect(round).toEqual({ expected: true, reason: "kernel update" });
|
|
64
|
+
});
|
|
65
|
+
it("default TTL is 10 minutes", () => {
|
|
66
|
+
const now = new Date("2026-04-21T22:00:00Z");
|
|
67
|
+
const res = writeRebootMarker({ path, now });
|
|
68
|
+
expect(res.expires_at).toBe("2026-04-21T22:10:00.000Z");
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe("parseDuration", () => {
|
|
72
|
+
it.each([
|
|
73
|
+
["10m", 600_000],
|
|
74
|
+
["2h", 7_200_000],
|
|
75
|
+
["600s", 600_000],
|
|
76
|
+
["500ms", 500],
|
|
77
|
+
["30", 30_000], // bare number -> seconds
|
|
78
|
+
])("%s -> %d ms", (input, ms) => {
|
|
79
|
+
expect(parseDuration(input)).toBe(ms);
|
|
80
|
+
});
|
|
81
|
+
it("rejects garbage", () => {
|
|
82
|
+
expect(parseDuration("forever")).toBeNull();
|
|
83
|
+
expect(parseDuration("-5m")).toBeNull();
|
|
84
|
+
expect(parseDuration("")).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe("CLI parseCliArgs subcommands", () => {
|
|
88
|
+
it("14. `reboot` subcommand captured with flags", () => {
|
|
89
|
+
const { result } = parseCliArgs(["reboot", "--reason", "kernel update"], "1.0.0");
|
|
90
|
+
expect(result.mode).toBe("reboot");
|
|
91
|
+
expect(result.reason).toBe("kernel update");
|
|
92
|
+
});
|
|
93
|
+
it("`mark-reboot` with --ttl parsed through", () => {
|
|
94
|
+
const { result } = parseCliArgs(["mark-reboot", "--ttl=5m", "--reason=test"], "1.0.0");
|
|
95
|
+
expect(result.mode).toBe("mark-reboot");
|
|
96
|
+
expect(result.ttl).toBe("5m");
|
|
97
|
+
expect(result.reason).toBe("test");
|
|
98
|
+
});
|
|
99
|
+
it("`mark-reboot --help` returns help output without running", () => {
|
|
100
|
+
const { result, output } = parseCliArgs(["mark-reboot", "--help"], "1.0.0");
|
|
101
|
+
expect(result.mode).toBe("help");
|
|
102
|
+
expect(output).toContain("mark-reboot");
|
|
103
|
+
});
|
|
104
|
+
it("top-level help lists the new subcommands", () => {
|
|
105
|
+
const { output } = parseCliArgs(["--help"], "1.0.0");
|
|
106
|
+
expect(output).toMatch(/mark-reboot/);
|
|
107
|
+
expect(output).toMatch(/reboot/);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=reboot-marker.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reboot-marker.test.js","sourceRoot":"","sources":["../../src/__tests__/reboot-marker.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
export type CliMode = "version" | "help" | "run" | "mark-reboot" | "reboot";
|
|
1
2
|
export interface CliArgs {
|
|
2
|
-
mode:
|
|
3
|
+
mode: CliMode;
|
|
3
4
|
configPath: string;
|
|
5
|
+
reason?: string;
|
|
6
|
+
ttl?: string;
|
|
4
7
|
}
|
|
5
8
|
export declare const DEFAULT_CONFIG_PATH = "/etc/glassmkr/collector.yaml";
|
|
6
9
|
export declare function parseCliArgs(argv: string[], version: string): {
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,36 @@ export const DEFAULT_CONFIG_PATH = "/etc/glassmkr/collector.yaml";
|
|
|
5
5
|
export function parseCliArgs(argv, version) {
|
|
6
6
|
// argv is typically process.argv.slice(2)
|
|
7
7
|
let configPath = DEFAULT_CONFIG_PATH;
|
|
8
|
+
// Subcommand dispatch: `mark-reboot` and `reboot` take their own flags
|
|
9
|
+
// (--reason, --ttl) but re-use --help.
|
|
10
|
+
if (argv[0] === "mark-reboot" || argv[0] === "reboot") {
|
|
11
|
+
const mode = argv[0];
|
|
12
|
+
let reason;
|
|
13
|
+
let ttl;
|
|
14
|
+
for (let i = 1; i < argv.length; i++) {
|
|
15
|
+
const a = argv[i];
|
|
16
|
+
if (a === "--help" || a === "-h") {
|
|
17
|
+
return { result: { mode: "help", configPath: "" }, output: subcommandHelp(mode, version) };
|
|
18
|
+
}
|
|
19
|
+
if (a === "--reason") {
|
|
20
|
+
reason = argv[++i];
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (a.startsWith("--reason=")) {
|
|
24
|
+
reason = a.slice("--reason=".length);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (a === "--ttl") {
|
|
28
|
+
ttl = argv[++i];
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (a.startsWith("--ttl=")) {
|
|
32
|
+
ttl = a.slice("--ttl=".length);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { result: { mode, configPath: "", reason, ttl }, output: null };
|
|
37
|
+
}
|
|
8
38
|
for (let i = 0; i < argv.length; i++) {
|
|
9
39
|
const arg = argv[i];
|
|
10
40
|
if (arg === "--version" || arg === "-v") {
|
|
@@ -40,14 +70,40 @@ export function helpText(version) {
|
|
|
40
70
|
"",
|
|
41
71
|
"Usage:",
|
|
42
72
|
" glassmkr-crucible [options]",
|
|
73
|
+
" glassmkr-crucible mark-reboot [--reason TEXT] [--ttl DURATION]",
|
|
74
|
+
" glassmkr-crucible reboot [--reason TEXT] [--ttl DURATION]",
|
|
43
75
|
"",
|
|
44
76
|
"Options:",
|
|
45
77
|
" -v, --version Print version and exit",
|
|
46
78
|
" -h, --help Print this help and exit",
|
|
47
79
|
` -c, --config Path to config file (default: ${DEFAULT_CONFIG_PATH})`,
|
|
48
80
|
"",
|
|
81
|
+
"Subcommands:",
|
|
82
|
+
" mark-reboot Write a planned-reboot marker so the next boot",
|
|
83
|
+
" does not fire `server_rebooted_unexpectedly`.",
|
|
84
|
+
" You run the reboot yourself afterwards.",
|
|
85
|
+
" reboot Write the marker, then invoke `systemctl reboot`.",
|
|
86
|
+
"",
|
|
49
87
|
"Without options, starts the collector daemon using the config file.",
|
|
50
88
|
"Docs: https://github.com/glassmkr/crucible",
|
|
51
89
|
].join("\n");
|
|
52
90
|
}
|
|
91
|
+
function subcommandHelp(mode, version) {
|
|
92
|
+
const action = mode === "reboot"
|
|
93
|
+
? "Write a planned-reboot marker and invoke `systemctl reboot`."
|
|
94
|
+
: "Write a planned-reboot marker; operator triggers the reboot.";
|
|
95
|
+
return [
|
|
96
|
+
`glassmkr-crucible ${mode} - ${action}`,
|
|
97
|
+
"",
|
|
98
|
+
"Usage:",
|
|
99
|
+
` glassmkr-crucible ${mode} [--reason TEXT] [--ttl DURATION]`,
|
|
100
|
+
"",
|
|
101
|
+
"Options:",
|
|
102
|
+
' --reason TEXT Free-text reason (e.g. "kernel update")',
|
|
103
|
+
" --ttl DURATION Expiry window; e.g. 5m, 10m, 1h (default 10m)",
|
|
104
|
+
"",
|
|
105
|
+
`Marker path: /var/lib/crucible/reboot-expected (requires root).`,
|
|
106
|
+
`v${version}`,
|
|
107
|
+
].join("\n");
|
|
108
|
+
}
|
|
53
109
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { readOsReleaseField } from "../system.js";
|
|
3
|
+
describe("readOsReleaseField", () => {
|
|
4
|
+
it("parses unquoted Ubuntu values", () => {
|
|
5
|
+
const s = 'NAME="Ubuntu"\nID=ubuntu\nID_LIKE=debian\nVERSION_ID="24.04"';
|
|
6
|
+
expect(readOsReleaseField(s, "ID")).toBe("ubuntu");
|
|
7
|
+
expect(readOsReleaseField(s, "ID_LIKE")).toBe("debian");
|
|
8
|
+
});
|
|
9
|
+
it("parses quoted RHEL-family values", () => {
|
|
10
|
+
const s = 'NAME="Rocky Linux"\nID="rocky"\nID_LIKE="rhel centos fedora"';
|
|
11
|
+
expect(readOsReleaseField(s, "ID")).toBe("rocky");
|
|
12
|
+
expect(readOsReleaseField(s, "ID_LIKE")).toBe("rhel centos fedora");
|
|
13
|
+
});
|
|
14
|
+
it("lowercases the result (some distros uppercase their ID)", () => {
|
|
15
|
+
expect(readOsReleaseField("ID=Alpine", "ID")).toBe("alpine");
|
|
16
|
+
});
|
|
17
|
+
it("returns undefined for a missing key", () => {
|
|
18
|
+
expect(readOsReleaseField("ID=arch", "ID_LIKE")).toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
it("does not confuse ID with VERSION_ID", () => {
|
|
21
|
+
const s = 'VERSION_ID="24.04"\nID=ubuntu';
|
|
22
|
+
expect(readOsReleaseField(s, "ID")).toBe("ubuntu");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=system.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.test.js","sourceRoot":"","sources":["../../../src/collect/__tests__/system.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,GAAG,8DAA8D,CAAC;QACzE,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,GAAG,8DAA8D,CAAC;QACzE,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,kBAAkB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,GAAG,+BAA+B,CAAC;QAC1C,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/collect/network.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { readProcFile, sleep } from "../lib/parse.js";
|
|
2
2
|
import { readFileSync, readdirSync } from "fs";
|
|
3
3
|
const previousCounters = new Map();
|
|
4
|
+
function readStatCounter(iface, name) {
|
|
5
|
+
try {
|
|
6
|
+
const raw = readFileSync(`/sys/class/net/${iface}/statistics/${name}`, "utf-8").trim();
|
|
7
|
+
const val = parseInt(raw, 10);
|
|
8
|
+
return Number.isFinite(val) ? val : undefined;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
4
14
|
function parseNetDev() {
|
|
5
15
|
const raw = readProcFile("/proc/net/dev") || "";
|
|
6
16
|
const result = {};
|
|
@@ -52,6 +62,14 @@ function getBondMaster(iface) {
|
|
|
52
62
|
}
|
|
53
63
|
return undefined;
|
|
54
64
|
}
|
|
65
|
+
function isBondMaster(iface) {
|
|
66
|
+
try {
|
|
67
|
+
return readdirSync("/proc/net/bonding/").includes(iface);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
55
73
|
// Compute delta, handling counter wraps (current < previous means reset, use current as delta)
|
|
56
74
|
function delta(current, previous) {
|
|
57
75
|
if (current >= previous)
|
|
@@ -70,16 +88,39 @@ export async function collectNetwork() {
|
|
|
70
88
|
continue;
|
|
71
89
|
currentIfaces.add(name);
|
|
72
90
|
const prev = previousCounters.get(name);
|
|
91
|
+
// /sys/class/net/*/statistics/ exposes finer-grained RX/TX subtype
|
|
92
|
+
// counters than /proc/net/dev. Read cumulative values here; delta is
|
|
93
|
+
// derived below against the previous cycle's snapshot.
|
|
94
|
+
const rxCrcCum = readStatCounter(name, "rx_crc_errors");
|
|
95
|
+
const rxFrameCum = readStatCounter(name, "rx_frame_errors");
|
|
96
|
+
const rxLenCum = readStatCounter(name, "rx_length_errors");
|
|
97
|
+
const txCarrierCum = readStatCounter(name, "tx_carrier_errors");
|
|
73
98
|
// Compute error/drop deltas (0 on first cycle after start or new interface)
|
|
74
99
|
let rxErrorsDelta = 0;
|
|
75
100
|
let txErrorsDelta = 0;
|
|
76
101
|
let rxDropsDelta = 0;
|
|
77
102
|
let txDropsDelta = 0;
|
|
103
|
+
let rxPacketsDelta = 0;
|
|
104
|
+
let txPacketsDelta = 0;
|
|
105
|
+
let rxCrcDelta;
|
|
106
|
+
let rxFrameDelta;
|
|
107
|
+
let rxLenDelta;
|
|
108
|
+
let txCarrierDelta;
|
|
78
109
|
if (prev) {
|
|
79
110
|
rxErrorsDelta = delta(s2.rx_errors, prev.rx_errors);
|
|
80
111
|
txErrorsDelta = delta(s2.tx_errors, prev.tx_errors);
|
|
81
112
|
rxDropsDelta = delta(s2.rx_drops, prev.rx_drops);
|
|
82
113
|
txDropsDelta = delta(s2.tx_drops, prev.tx_drops);
|
|
114
|
+
rxPacketsDelta = delta(s2.rx_packets, prev.rx_packets);
|
|
115
|
+
txPacketsDelta = delta(s2.tx_packets, prev.tx_packets);
|
|
116
|
+
if (rxCrcCum != null && prev.rx_crc_errors != null)
|
|
117
|
+
rxCrcDelta = delta(rxCrcCum, prev.rx_crc_errors);
|
|
118
|
+
if (rxFrameCum != null && prev.rx_frame_errors != null)
|
|
119
|
+
rxFrameDelta = delta(rxFrameCum, prev.rx_frame_errors);
|
|
120
|
+
if (rxLenCum != null && prev.rx_length_errors != null)
|
|
121
|
+
rxLenDelta = delta(rxLenCum, prev.rx_length_errors);
|
|
122
|
+
if (txCarrierCum != null && prev.tx_carrier_errors != null)
|
|
123
|
+
txCarrierDelta = delta(txCarrierCum, prev.tx_carrier_errors);
|
|
83
124
|
}
|
|
84
125
|
// Store current cumulative values for next cycle
|
|
85
126
|
previousCounters.set(name, {
|
|
@@ -87,6 +128,12 @@ export async function collectNetwork() {
|
|
|
87
128
|
tx_errors: s2.tx_errors,
|
|
88
129
|
rx_drops: s2.rx_drops,
|
|
89
130
|
tx_drops: s2.tx_drops,
|
|
131
|
+
rx_packets: s2.rx_packets,
|
|
132
|
+
tx_packets: s2.tx_packets,
|
|
133
|
+
rx_crc_errors: rxCrcCum,
|
|
134
|
+
rx_frame_errors: rxFrameCum,
|
|
135
|
+
rx_length_errors: rxLenCum,
|
|
136
|
+
tx_carrier_errors: txCarrierCum,
|
|
90
137
|
});
|
|
91
138
|
const entry = {
|
|
92
139
|
interface: name,
|
|
@@ -97,11 +144,24 @@ export async function collectNetwork() {
|
|
|
97
144
|
tx_errors: txErrorsDelta,
|
|
98
145
|
rx_drops: rxDropsDelta,
|
|
99
146
|
tx_drops: txDropsDelta,
|
|
147
|
+
rx_packets: rxPacketsDelta,
|
|
148
|
+
tx_packets: txPacketsDelta,
|
|
100
149
|
operstate: getOperstate(name),
|
|
101
150
|
};
|
|
151
|
+
if (rxCrcDelta !== undefined)
|
|
152
|
+
entry.rx_crc_errors = rxCrcDelta;
|
|
153
|
+
if (rxFrameDelta !== undefined)
|
|
154
|
+
entry.rx_frame_errors = rxFrameDelta;
|
|
155
|
+
if (rxLenDelta !== undefined)
|
|
156
|
+
entry.rx_length_errors = rxLenDelta;
|
|
157
|
+
if (txCarrierDelta !== undefined)
|
|
158
|
+
entry.tx_carrier_errors = txCarrierDelta;
|
|
102
159
|
const master = getBondMaster(name);
|
|
103
160
|
if (master)
|
|
104
161
|
entry.bond_master = master;
|
|
162
|
+
// Identify bond masters (have at least one slave pointing at them).
|
|
163
|
+
if (isBondMaster(name))
|
|
164
|
+
entry.is_bond_master = true;
|
|
105
165
|
results.push(entry);
|
|
106
166
|
}
|
|
107
167
|
// Remove stale interfaces that disappeared
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/collect/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/collect/network.ts"],"names":[],"mappings":"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"}
|
package/dist/collect/system.d.ts
CHANGED