Update For Docker Socket Support
This commit is contained in:
@@ -34,7 +34,9 @@ PEARDATA_DEFAULT_ROLE=viewer
|
|||||||
# PEARDATA_HYPERDB=1
|
# PEARDATA_HYPERDB=1
|
||||||
# PEARDATA_SWARM=0
|
# PEARDATA_SWARM=0
|
||||||
# PEARDATA_DOCKER=0
|
# PEARDATA_DOCKER=0
|
||||||
|
# Installer sets PEARDATA_DOCKER=1 when Docker is detected (names via socket).
|
||||||
# PEARDATA_DOCKER_SOCKET=/var/run/docker.sock
|
# PEARDATA_DOCKER_SOCKET=/var/run/docker.sock
|
||||||
|
|
||||||
# PEARDATA_CGROUPS=1
|
# PEARDATA_CGROUPS=1
|
||||||
# PEARDATA_CGROUPS_MAX=32
|
# PEARDATA_CGROUPS_MAX=32
|
||||||
# PEARDATA_SENSORS=1
|
# PEARDATA_SENSORS=1
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ Description=PearData PearMonitor agent (HyperDHT + REST metrics)
|
|||||||
Documentation=https://git.ssh.surf/snxraven/peardata
|
Documentation=https://git.ssh.surf/snxraven/peardata
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
# Installer adds these when Docker is detected:
|
||||||
|
# After=docker.service
|
||||||
|
# Wants=docker.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
@@ -14,13 +17,15 @@ TimeoutStartSec=30
|
|||||||
TimeoutStopSec=30
|
TimeoutStopSec=30
|
||||||
User=peardata
|
User=peardata
|
||||||
Group=peardata
|
Group=peardata
|
||||||
# Host journal for Logs tab (journalctl). Installer also adds peardata to this group.
|
# Host journal for Logs tab. Installer also adds docker when Docker is present:
|
||||||
|
# SupplementaryGroups=systemd-journal docker
|
||||||
SupplementaryGroups=systemd-journal
|
SupplementaryGroups=systemd-journal
|
||||||
NoNewPrivileges=true
|
NoNewPrivileges=true
|
||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
# Journal on by default; override in .env with PEARDATA_JOURNAL=0 to disable
|
# Journal on by default; override in .env with PEARDATA_JOURNAL=0 to disable
|
||||||
Environment=PEARDATA_JOURNAL=1
|
Environment=PEARDATA_JOURNAL=1
|
||||||
|
# Docker: installer sets PEARDATA_DOCKER=1 + PEARDATA_DOCKER_SOCKET in .env when detected
|
||||||
EnvironmentFile=-/opt/peardata/.env
|
EnvironmentFile=-/opt/peardata/.env
|
||||||
# Identity + HyperDB / metric buffers
|
# Identity + HyperDB / metric buffers
|
||||||
ReadWritePaths=/opt/peardata
|
ReadWritePaths=/opt/peardata
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ Live retention is edited in the desktop **Settings → Data** tab (admin) and pe
|
|||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `PEARDATA_HYPERDB` | on | `0` / `off` disables HyperDB |
|
| `PEARDATA_HYPERDB` | on | `0` / `off` disables HyperDB |
|
||||||
| `PEARDATA_SWARM` | off | `1` enables Hyperswarm Corestore replication |
|
| `PEARDATA_SWARM` | off | `1` enables Hyperswarm Corestore replication |
|
||||||
| `PEARDATA_DOCKER` | off | `1` enables Docker Engine collector (socket + per-container cpu/mem) |
|
| `PEARDATA_DOCKER` | off* | `1` enables Docker Engine collector (socket + per-container cpu/mem). *Installer sets `1` when Docker is detected |
|
||||||
| `PEARDATA_DOCKER_SOCKET` | `/var/run/docker.sock` | Unix socket for container name enrichment |
|
| `PEARDATA_DOCKER_SOCKET` | auto | Socket path for names + API (`/var/run/docker.sock`, `/run/docker.sock`, Podman). Installer writes the detected path |
|
||||||
| `PEARDATA_CGROUPS` | on (Linux) | `0` disables cgroup v2 CPU/mem/IO charts; `1` forces on |
|
| `PEARDATA_CGROUPS` | on (Linux) | `0` disables cgroup v2 CPU/mem/IO charts; `1` forces on |
|
||||||
| `PEARDATA_CGROUPS_MAX` | `32` | Max cgroup instances to chart |
|
| `PEARDATA_CGROUPS_MAX` | `32` | Max cgroup instances to chart |
|
||||||
| `PEARDATA_SENSORS` | on (Linux) | `0` disables hwmon/thermal charts |
|
| `PEARDATA_SENSORS` | on (Linux) | `0` disables hwmon/thermal charts |
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ Have `pipeline.js` start each enabled collector; all emit `samples` batches into
|
|||||||
|
|
||||||
1. Set `PEARDATA_DOCKER=1` on the agent.
|
1. Set `PEARDATA_DOCKER=1` on the agent.
|
||||||
2. Charts: `docker.containers`, `docker.cpu.<id>`, `docker.mem.<id>` (registered at runtime).
|
2. Charts: `docker.containers`, `docker.cpu.<id>`, `docker.mem.<id>` (registered at runtime).
|
||||||
3. Discovery: cgroup v2 `docker-*.scope` / `libpod-*.scope`; names from `PEARDATA_DOCKER_SOCKET` when present.
|
3. Discovery: cgroup v2 `docker-*.scope` / `libpod-*.scope`; names from the Docker socket (`PEARDATA_DOCKER_SOCKET`). Installer adds `peardata` to the `docker` group and enables `PEARDATA_DOCKER=1` when Docker is detected.
|
||||||
4. Pick them in the desktop Explore chart dropdown (`docker.*`).
|
4. Pick them in the desktop Explore chart dropdown (`docker.*`).
|
||||||
|
|
||||||
### Process top-N collector
|
### Process top-N collector
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ npm start
|
|||||||
|
|
||||||
## systemd (Linux)
|
## systemd (Linux)
|
||||||
|
|
||||||
Prefer the [one-line installer](#one-line-installer-recommended) (`--server`). It installs the Bare binary, writes `peardata.service`, adds `peardata` to **`systemd-journal`**, and enables host journal for the Logs tab (`PEARDATA_JOURNAL=1`).
|
Prefer the [one-line installer](#one-line-installer-recommended) (`--server`). It installs the Bare binary, writes `peardata.service`, adds `peardata` to **`systemd-journal`**, and enables host journal for the Logs tab (`PEARDATA_JOURNAL=1`). When **Docker** is detected it also adds `peardata` to the **`docker`** group, sets `SupplementaryGroups=… docker`, and enables `PEARDATA_DOCKER=1` so charts show human names (e.g. `dozzle`) instead of hashes.
|
||||||
|
|
||||||
Manual (matches installer layout):
|
Manual (matches installer layout):
|
||||||
|
|
||||||
@@ -118,6 +118,10 @@ Manual (matches installer layout):
|
|||||||
# After placing peardata-server + .env under /opt/peardata
|
# After placing peardata-server + .env under /opt/peardata
|
||||||
sudo useradd --system --home /opt/peardata --shell /usr/sbin/nologin peardata # if needed
|
sudo useradd --system --home /opt/peardata --shell /usr/sbin/nologin peardata # if needed
|
||||||
sudo usermod -aG systemd-journal peardata
|
sudo usermod -aG systemd-journal peardata
|
||||||
|
# If Docker is installed:
|
||||||
|
sudo usermod -aG docker peardata
|
||||||
|
# In /opt/peardata/.env: PEARDATA_DOCKER=1 and PEARDATA_DOCKER_SOCKET=/var/run/docker.sock
|
||||||
|
# In the unit: SupplementaryGroups=systemd-journal docker
|
||||||
sudo cp deploy/peardata.service /etc/systemd/system/
|
sudo cp deploy/peardata.service /etc/systemd/system/
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
sudo systemctl enable --now peardata
|
sudo systemctl enable --now peardata
|
||||||
|
|||||||
+87
-3
@@ -102,6 +102,23 @@ host_triple() {
|
|||||||
echo "${os}-${arch}"
|
echo "${os}-${arch}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# First existing Docker Engine unix socket (empty if none).
|
||||||
|
detect_docker_socket() {
|
||||||
|
local p
|
||||||
|
for p in \
|
||||||
|
"${PEARDATA_DOCKER_SOCKET:-}" \
|
||||||
|
/var/run/docker.sock \
|
||||||
|
/run/docker.sock \
|
||||||
|
/var/run/podman/podman.sock \
|
||||||
|
/run/podman/podman.sock
|
||||||
|
do
|
||||||
|
[[ -n "$p" && -S "$p" ]] || continue
|
||||||
|
printf '%s\n' "$p"
|
||||||
|
return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# ─── args ───────────────────────────────────────────────────────────────────
|
# ─── args ───────────────────────────────────────────────────────────────────
|
||||||
parse_args() {
|
parse_args() {
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
@@ -341,12 +358,71 @@ install_server() {
|
|||||||
run_root sh -c "printf '\\n# Host journal for Logs tab (set to 0 to disable)\\nPEARDATA_JOURNAL=1\\n' >> '${SERVER_DIR}/.env'"
|
run_root sh -c "printf '\\n# Host journal for Logs tab (set to 0 to disable)\\nPEARDATA_JOURNAL=1\\n' >> '${SERVER_DIR}/.env'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Docker socket access — container names (e.g. dozzle) + per-container metrics
|
||||||
|
local docker_detected=0
|
||||||
|
local docker_sock=""
|
||||||
|
local docker_group_name=""
|
||||||
|
docker_sock="$(detect_docker_socket || true)"
|
||||||
|
if [[ -n "$docker_sock" ]]; then
|
||||||
|
docker_detected=1
|
||||||
|
elif getent group docker >/dev/null 2>&1; then
|
||||||
|
docker_detected=1
|
||||||
|
docker_sock="/var/run/docker.sock"
|
||||||
|
elif command -v docker >/dev/null 2>&1; then
|
||||||
|
docker_detected=1
|
||||||
|
docker_sock="/var/run/docker.sock"
|
||||||
|
fi
|
||||||
|
if getent group docker >/dev/null 2>&1; then
|
||||||
|
docker_group_name="docker"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$docker_detected" -eq 1 ]]; then
|
||||||
|
ok "Docker detected${docker_sock:+ (socket ${docker_sock})}"
|
||||||
|
if [[ -n "$docker_group_name" ]]; then
|
||||||
|
log "Adding peardata to ${docker_group_name} for Docker socket / container names…"
|
||||||
|
if command -v usermod >/dev/null 2>&1; then
|
||||||
|
run_root usermod -aG "$docker_group_name" peardata || warn "usermod -aG ${docker_group_name} peardata failed"
|
||||||
|
elif command -v gpasswd >/dev/null 2>&1; then
|
||||||
|
run_root gpasswd -a peardata "$docker_group_name" || warn "gpasswd -a peardata ${docker_group_name} failed"
|
||||||
|
else
|
||||||
|
warn "Could not add peardata to ${docker_group_name} (no usermod/gpasswd)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Docker socket present but no 'docker' group — grant peardata read access to ${docker_sock} manually"
|
||||||
|
fi
|
||||||
|
if ! run_root grep -qE '^PEARDATA_DOCKER=' "${SERVER_DIR}/.env" 2>/dev/null; then
|
||||||
|
log "Enabling PEARDATA_DOCKER=1 in ${SERVER_DIR}/.env (container metrics + names)"
|
||||||
|
run_root sh -c "printf '\\n# Docker collector (names via socket; set to 0 to disable)\\nPEARDATA_DOCKER=1\\nPEARDATA_DOCKER_SOCKET=%s\\n' '${docker_sock}' >> '${SERVER_DIR}/.env'"
|
||||||
|
else
|
||||||
|
# Keep collector flag; refresh socket path if unset
|
||||||
|
if ! run_root grep -qE '^PEARDATA_DOCKER_SOCKET=' "${SERVER_DIR}/.env" 2>/dev/null; then
|
||||||
|
run_root sh -c "printf 'PEARDATA_DOCKER_SOCKET=%s\\n' '${docker_sock}' >> '${SERVER_DIR}/.env'"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "Docker not detected — skipping socket access (install Docker later, then re-run installer or: usermod -aG docker peardata && PEARDATA_DOCKER=1)"
|
||||||
|
fi
|
||||||
|
|
||||||
run_root chown -R peardata:peardata "$SERVER_DIR" 2>/dev/null || run_root chown -R peardata "$SERVER_DIR"
|
run_root chown -R peardata:peardata "$SERVER_DIR" 2>/dev/null || run_root chown -R peardata "$SERVER_DIR"
|
||||||
|
|
||||||
unit_path="/etc/systemd/system/peardata.service"
|
unit_path="/etc/systemd/system/peardata.service"
|
||||||
local journal_group_line=""
|
# systemd SupplementaryGroups replaces the user's supplementary set — list every group we need
|
||||||
|
local supp_groups=()
|
||||||
if getent group systemd-journal >/dev/null 2>&1; then
|
if getent group systemd-journal >/dev/null 2>&1; then
|
||||||
journal_group_line="SupplementaryGroups=systemd-journal"
|
supp_groups+=("systemd-journal")
|
||||||
|
fi
|
||||||
|
if [[ "$docker_detected" -eq 1 && -n "$docker_group_name" ]]; then
|
||||||
|
supp_groups+=("$docker_group_name")
|
||||||
|
fi
|
||||||
|
local supp_groups_line=""
|
||||||
|
if [[ ${#supp_groups[@]} -gt 0 ]]; then
|
||||||
|
supp_groups_line="SupplementaryGroups=${supp_groups[*]}"
|
||||||
|
fi
|
||||||
|
local docker_after_line=""
|
||||||
|
local docker_wants_line=""
|
||||||
|
if [[ "$docker_detected" -eq 1 ]]; then
|
||||||
|
docker_after_line="After=docker.service"
|
||||||
|
docker_wants_line="Wants=docker.service"
|
||||||
fi
|
fi
|
||||||
log "Writing ${unit_path}…"
|
log "Writing ${unit_path}…"
|
||||||
run_root tee "$unit_path" >/dev/null <<EOF
|
run_root tee "$unit_path" >/dev/null <<EOF
|
||||||
@@ -355,6 +431,8 @@ Description=PearData PearMonitor agent (HyperDHT + REST metrics)
|
|||||||
Documentation=${GITEA_URL}/${OWNER}/${REPO}
|
Documentation=${GITEA_URL}/${OWNER}/${REPO}
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
${docker_after_line}
|
||||||
|
${docker_wants_line}
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
@@ -366,7 +444,7 @@ TimeoutStartSec=30
|
|||||||
TimeoutStopSec=30
|
TimeoutStopSec=30
|
||||||
User=peardata
|
User=peardata
|
||||||
Group=peardata
|
Group=peardata
|
||||||
${journal_group_line}
|
${supp_groups_line}
|
||||||
NoNewPrivileges=true
|
NoNewPrivileges=true
|
||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
@@ -399,6 +477,11 @@ EOF
|
|||||||
env_pk="$(run_root grep -E '^SERVER_PUBLIC_KEY=' "${SERVER_DIR}/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '[:space:]' || true)"
|
env_pk="$(run_root grep -E '^SERVER_PUBLIC_KEY=' "${SERVER_DIR}/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '[:space:]' || true)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local docker_summary="not detected (optional)"
|
||||||
|
if [[ "$docker_detected" -eq 1 ]]; then
|
||||||
|
docker_summary="enabled · peardata ∈ ${docker_group_name:-docker} · ${docker_sock} (human container names)"
|
||||||
|
fi
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
${C_BOLD}Server installed${C_RESET}
|
${C_BOLD}Server installed${C_RESET}
|
||||||
@@ -407,6 +490,7 @@ ${C_BOLD}Server installed${C_RESET}
|
|||||||
Data: ${SERVER_DIR}/data
|
Data: ${SERVER_DIR}/data
|
||||||
Service: peardata.service
|
Service: peardata.service
|
||||||
Journal: peardata ∈ systemd-journal · PEARDATA_JOURNAL=1 (Logs tab)
|
Journal: peardata ∈ systemd-journal · PEARDATA_JOURNAL=1 (Logs tab)
|
||||||
|
Docker: ${docker_summary}
|
||||||
REST: http://127.0.0.1:18888/api/v3/info (localhost by default)
|
REST: http://127.0.0.1:18888/api/v3/info (localhost by default)
|
||||||
|
|
||||||
${C_BOLD}Keys (written on first successful start)${C_RESET}
|
${C_BOLD}Keys (written on first successful start)${C_RESET}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
makeCgroupThrottleChart,
|
makeCgroupThrottleChart,
|
||||||
} from '../../../shared/metrics.js'
|
} from '../../../shared/metrics.js'
|
||||||
import { resolveContainerLabel } from '../../../shared/container-names.js'
|
import { resolveContainerLabel } from '../../../shared/container-names.js'
|
||||||
import { fetchDockerNames } from './docker.js'
|
import { fetchDockerNames, resolveDockerSocket } from './docker.js'
|
||||||
import logger from '../../utils/logger.js'
|
import logger from '../../utils/logger.js'
|
||||||
|
|
||||||
const log = logger.child('cgroups')
|
const log = logger.child('cgroups')
|
||||||
@@ -185,7 +185,7 @@ export class CgroupsCollector extends EventEmitter {
|
|||||||
constructor(opts = {}) {
|
constructor(opts = {}) {
|
||||||
super()
|
super()
|
||||||
this.intervalMs = opts.intervalMs ?? (Number(process.env.PEARDATA_SAMPLE_MS) || SAMPLE_INTERVAL_MS)
|
this.intervalMs = opts.intervalMs ?? (Number(process.env.PEARDATA_SAMPLE_MS) || SAMPLE_INTERVAL_MS)
|
||||||
this.socketPath = opts.socketPath || process.env.PEARDATA_DOCKER_SOCKET || '/var/run/docker.sock'
|
this.socketPath = resolveDockerSocket(opts.socketPath)
|
||||||
this.timer = null
|
this.timer = null
|
||||||
this.running = false
|
this.running = false
|
||||||
/** @type {Map<string, { usage: number, user: number, system: number, rbytes: number, wbytes: number, throttledUsec: number }>} */
|
/** @type {Map<string, { usage: number, user: number, system: number, rbytes: number, wbytes: number, throttledUsec: number }>} */
|
||||||
@@ -220,8 +220,10 @@ export class CgroupsCollector extends EventEmitter {
|
|||||||
if (now - this._nameRefreshAt < 30_000) return
|
if (now - this._nameRefreshAt < 30_000) return
|
||||||
this._nameRefreshAt = now
|
this._nameRefreshAt = now
|
||||||
try {
|
try {
|
||||||
|
this.socketPath = resolveDockerSocket(this.socketPath)
|
||||||
if (fs.existsSync(this.socketPath)) {
|
if (fs.existsSync(this.socketPath)) {
|
||||||
this._names = await fetchDockerNames(this.socketPath)
|
const map = await fetchDockerNames(this.socketPath)
|
||||||
|
if (map.size) this._names = map
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// ignore — titles fall back to humanized hashes
|
// ignore — titles fall back to humanized hashes
|
||||||
|
|||||||
@@ -32,6 +32,26 @@ export function isDockerCollectorEnabled() {
|
|||||||
return v === '1' || v === 'on' || v === 'true'
|
return v === '1' || v === 'on' || v === 'true'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Candidate Docker / Podman engine sockets (first existing wins). */
|
||||||
|
export function resolveDockerSocket(preferred) {
|
||||||
|
const candidates = [
|
||||||
|
preferred,
|
||||||
|
process.env.PEARDATA_DOCKER_SOCKET,
|
||||||
|
'/var/run/docker.sock',
|
||||||
|
'/run/docker.sock',
|
||||||
|
'/var/run/podman/podman.sock',
|
||||||
|
'/run/podman/podman.sock',
|
||||||
|
].filter(Boolean)
|
||||||
|
for (const p of candidates) {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(p)) return p
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return preferred || process.env.PEARDATA_DOCKER_SOCKET || '/var/run/docker.sock'
|
||||||
|
}
|
||||||
|
|
||||||
function readFile(p) {
|
function readFile(p) {
|
||||||
try {
|
try {
|
||||||
return fs.readFileSync(p, 'utf8')
|
return fs.readFileSync(p, 'utf8')
|
||||||
@@ -222,7 +242,7 @@ export class DockerCollector extends EventEmitter {
|
|||||||
constructor(opts = {}) {
|
constructor(opts = {}) {
|
||||||
super()
|
super()
|
||||||
this.intervalMs = opts.intervalMs || Number(process.env.PEARDATA_SAMPLE_MS) || SAMPLE_INTERVAL_MS
|
this.intervalMs = opts.intervalMs || Number(process.env.PEARDATA_SAMPLE_MS) || SAMPLE_INTERVAL_MS
|
||||||
this.socketPath = opts.socketPath || process.env.PEARDATA_DOCKER_SOCKET || '/var/run/docker.sock'
|
this.socketPath = resolveDockerSocket(opts.socketPath)
|
||||||
this._timer = null
|
this._timer = null
|
||||||
/** @type {Map<string, { usageNs: number, wallMs: number }>} */
|
/** @type {Map<string, { usageNs: number, wallMs: number }>} */
|
||||||
this._prevCpu = new Map()
|
this._prevCpu = new Map()
|
||||||
@@ -233,6 +253,7 @@ export class DockerCollector extends EventEmitter {
|
|||||||
|
|
||||||
start() {
|
start() {
|
||||||
if (this._timer) return
|
if (this._timer) return
|
||||||
|
this.socketPath = resolveDockerSocket(this.socketPath)
|
||||||
registerChart(DOCKER_CONTAINERS_CHART)
|
registerChart(DOCKER_CONTAINERS_CHART)
|
||||||
log.info('Docker collector started', { socket: this.socketPath })
|
log.info('Docker collector started', { socket: this.socketPath })
|
||||||
this._tick()
|
this._tick()
|
||||||
@@ -252,11 +273,23 @@ export class DockerCollector extends EventEmitter {
|
|||||||
if (now - this._nameRefreshAt < 30_000) return
|
if (now - this._nameRefreshAt < 30_000) return
|
||||||
this._nameRefreshAt = now
|
this._nameRefreshAt = now
|
||||||
try {
|
try {
|
||||||
|
this.socketPath = resolveDockerSocket(this.socketPath)
|
||||||
if (fs.existsSync(this.socketPath)) {
|
if (fs.existsSync(this.socketPath)) {
|
||||||
this._names = await fetchDockerNames(this.socketPath)
|
const map = await fetchDockerNames(this.socketPath)
|
||||||
|
if (map.size) {
|
||||||
|
const prev = this._names.size
|
||||||
|
this._names = map
|
||||||
|
if (prev !== map.size) {
|
||||||
|
log.info('Docker container names loaded', { count: map.size, socket: this.socketPath })
|
||||||
|
}
|
||||||
|
} else if (!this._names.size) {
|
||||||
|
log.warn('Docker socket reachable but no container names (check peardata ∈ docker group)', {
|
||||||
|
socket: this.socketPath,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (err) {
|
||||||
// ignore
|
log.warn('Docker name refresh failed', { error: err.message, socket: this.socketPath })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
readCgroupCpu,
|
readCgroupCpu,
|
||||||
readCgroupMemory,
|
readCgroupMemory,
|
||||||
isDockerCollectorEnabled,
|
isDockerCollectorEnabled,
|
||||||
|
resolveDockerSocket,
|
||||||
} from '../server/services/collectors/docker.js'
|
} from '../server/services/collectors/docker.js'
|
||||||
import {
|
import {
|
||||||
makeDockerCpuChart,
|
makeDockerCpuChart,
|
||||||
@@ -49,6 +50,12 @@ test('isDockerCollectorEnabled', (t) => {
|
|||||||
else process.env.PEARDATA_DOCKER = prev
|
else process.env.PEARDATA_DOCKER = prev
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('resolveDockerSocket prefers existing preferred path', (t) => {
|
||||||
|
const fallback = resolveDockerSocket('/nonexistent-docker-sock-peardata-test')
|
||||||
|
t.ok(typeof fallback === 'string')
|
||||||
|
t.ok(fallback.includes('docker.sock') || fallback.includes('podman.sock'))
|
||||||
|
})
|
||||||
|
|
||||||
test('readCgroupCpu / memory from fixture', (t) => {
|
test('readCgroupCpu / memory from fixture', (t) => {
|
||||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'peardata-cgroup-'))
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'peardata-cgroup-'))
|
||||||
const slice = path.join(tmp, 'system.slice')
|
const slice = path.join(tmp, 'system.slice')
|
||||||
|
|||||||
Reference in New Issue
Block a user