Files
dokploy/packages/server/src/utils/deployment-failure-classifier.ts
T
Narciso 4bf6dfff13 feat: add Docker Health diagnostics tab
Server diagnostics tab (Docker dashboard) with:
- Per-network IP usage: subnet capacity vs. containers in use, including
  reserved networks like dokploy-network which are excluded from the
  managed Networks tab. Surfaces read errors instead of silently showing
  zeroes when the Docker API call fails.
- Broadened daemon-error detection and failure classification for Swarm
  network failures: IP pool exhaustion on an existing network
  ("could not find an available IP", "task allocation failure") and
  network attach timeouts ("attaching to network failed", "context
  deadline exceeded") — both previously fell through as Unclassified.
  Verified end-to-end against a real systemd-managed dockerd.
- Failed-deployment rows now carry the raw log tail used for
  classification, shown on hover and linked to their service/project,
  so a guess (or lack of one) can be verified against the actual error
  and followed straight to the app.
- Daemon-error panel is a read-only code editor, always visible (not
  hidden when empty), prefixed with the actual "Logs from X to Y"
  window passed to journalctl so the --since window can be verified.
- "Download report" exports everything on screen (metrics + raw logs)
  as Markdown, so a customer can send one file instead of a screen-share.
- Health check now IS_CLOUD-gated the same way network sync already is:
  a cloud org can no longer omit serverId and have the check silently
  run against the shared platform host instead of their own server.

Includes an inotify diagnostics card (current vs. max_user_instances/
watches/queued_events) and a failed-deployments log with automatic
cause classification based on daemon/log error patterns.
2026-08-13 10:00:54 -04:00

70 lines
1.6 KiB
TypeScript

export interface FailurePattern {
id: string;
label: string;
pattern: RegExp;
}
export const FAILURE_PATTERNS: FailurePattern[] = [
{
id: "inotify-limit",
label: "Inotify limit reached",
pattern: /max_user_instances|max_user_watches|inotify watch limit reached/i,
},
{
id: "oom",
label: "Out of memory (OOM)",
pattern: /\boom[-_ ]?kill(er|ed)?\b|killed process|out of memory/i,
},
{
id: "address-pool-exhausted",
label: "Docker network address pool exhausted",
pattern:
/could not find an available[,]? non-overlapping|available.*address pool/i,
},
{
id: "network-ip-exhausted",
label: "Network out of IP addresses",
pattern:
/could not find an available ip|no available ip addresses|task allocation failure/i,
},
{
id: "network-attach-timeout",
label: "Network attach timed out",
pattern:
/attaching to network failed|failed to set up container networking/i,
},
{
id: "disk-full",
label: "Disk space exhausted",
pattern: /no space left on device/i,
},
{
id: "conntrack-full",
label: "Connection tracking table full",
pattern: /nf_conntrack:?\s*table full/i,
},
{
id: "fd-limit",
label: "File descriptor limit reached",
pattern: /too many open files/i,
},
{
id: "pid-limit",
label: "Process/PID limit reached",
pattern:
/pids\.max|cannot allocate memory|fork:.*resource temporarily unavailable/i,
},
];
export const classifyFailure = (
text: string | null | undefined,
): { id: string; label: string } | null => {
if (!text) return null;
for (const entry of FAILURE_PATTERNS) {
if (entry.pattern.test(text)) {
return { id: entry.id, label: entry.label };
}
}
return null;
};