v0.4.0: monitoring & backup — scheduler, CPU/temp metrics, healthchecks, restic backups
Phase 2 (Monitoring & Health): - Central job scheduler replacing ad-hoc goroutines (internal/scheduler) - CPU usage collector via /proc/stat background sampling (internal/system/cpu_linux.go) - Temperature reading from /sys/class/thermal + /host/sys (Docker mount) - Load average from /proc/loadavg - Healthchecks.io-compatible HTTP pinger (internal/monitor/pinger.go) - System health checks: disk, memory, CPU, temp, Docker, protected containers (internal/monitor/healthcheck.go) Phase 3 (Backups): - Database auto-discovery via docker ps + docker inspect (internal/backup/dbdump.go) - Database dumping via docker exec (pg_dump / mariadb-dump) with atomic writes - Restic backup integration with auto-password generation (internal/backup/restic.go) - Backup orchestrator: DB dumps + restic snapshots + weekly prune (internal/backup/backup.go) - Manual backup trigger via dashboard button and POST /api/backup/run Dashboard UI: - CPU usage bar with load average display - Temperature with colored indicator dot - Backup status card with last run time, DB count, repo stats - "Mentés most" button for manual backup trigger Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,29 @@
|
||||
<div class="system-bar-fill system-bar-{{usageColor .SystemInfo.MemPercent}}" style="width:{{printf "%.0f" .SystemInfo.MemPercent}}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="system-info-item">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">CPU</span>
|
||||
<span class="system-info-value">{{printf "%.0f" .SystemInfo.CPUPercent}}%</span>
|
||||
</div>
|
||||
<div class="system-bar">
|
||||
<div class="system-bar-fill system-bar-{{usageColor .SystemInfo.CPUPercent}}" style="width:{{printf "%.0f" .SystemInfo.CPUPercent}}%"></div>
|
||||
</div>
|
||||
<div class="system-load-avg">Load: {{fmtLoad .SystemInfo.LoadAvg1}} / {{fmtLoad .SystemInfo.LoadAvg5}} / {{fmtLoad .SystemInfo.LoadAvg15}}</div>
|
||||
</div>
|
||||
{{if .SystemInfo.TemperatureCelsius}}
|
||||
<div class="system-info-item system-info-item-compact">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">Hőmérséklet</span>
|
||||
<span class="system-info-value">
|
||||
<span class="temp-dot temp-dot-{{tempColor .SystemInfo.TemperatureCelsius}}"></span>
|
||||
{{fmtTemp .SystemInfo.TemperatureCelsius}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="system-info-items" style="margin-top: 1rem;">
|
||||
<div class="system-info-item">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">SSD tárhely</span>
|
||||
@@ -57,6 +80,46 @@
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .BackupEnabled}}
|
||||
<div class="backup-status-card">
|
||||
<h3>Biztonsági mentés</h3>
|
||||
{{if .BackupStatus}}
|
||||
<div class="backup-info-row">
|
||||
<span class="backup-label">Utolsó mentés:</span>
|
||||
<span class="backup-value">
|
||||
{{if .BackupStatus.Success}}
|
||||
<span class="backup-status-ok">{{.BackupStatus.LastRun.Format "2006-01-02 15:04"}}</span>
|
||||
{{else}}
|
||||
<span class="backup-status-fail">Sikertelen</span>
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="backup-info-row">
|
||||
<span class="backup-label">Utolsó mentés:</span>
|
||||
<span class="backup-value backup-status-none">Még nem futott</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .DBDumpStatus}}
|
||||
<div class="backup-info-row">
|
||||
<span class="backup-label">Adatbázisok:</span>
|
||||
<span class="backup-value">{{len .DBDumpStatus.Results}} mentve</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .BackupStatus}}{{if .BackupStatus.RepoStats}}
|
||||
<div class="backup-info-row">
|
||||
<span class="backup-label">Tároló méret:</span>
|
||||
<span class="backup-value">{{.BackupStatus.RepoStats.TotalSize}} ({{.BackupStatus.RepoStats.SnapshotCount}} pillanatkép)</span>
|
||||
</div>
|
||||
{{end}}{{end}}
|
||||
<div class="backup-actions" style="margin-top: .75rem;">
|
||||
<button class="btn btn-sm btn-primary" onclick="triggerBackup()" id="backup-btn">
|
||||
{{if .BackupRunning}}Mentés folyamatban...{{else}}Mentés most{{end}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<h3>Alkalmazások állapota</h3>
|
||||
|
||||
<div class="stack-list">
|
||||
@@ -97,5 +160,28 @@
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function triggerBackup() {
|
||||
const btn = document.getElementById('backup-btn');
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Mentés indítása...';
|
||||
fetch('/api/backup/run', { method: 'POST' })
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.ok) {
|
||||
btn.textContent = 'Mentés folyamatban...';
|
||||
btn.classList.add('loading');
|
||||
} else {
|
||||
btn.textContent = data.error || 'Hiba';
|
||||
btn.disabled = false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
btn.textContent = 'Hiba';
|
||||
btn.disabled = false;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{{template "layout_end" .}}
|
||||
{{end}}
|
||||
|
||||
@@ -1122,6 +1122,62 @@ select.form-control option { background: var(--bg-secondary); color: var(--text-
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* Load average text */
|
||||
.system-load-avg {
|
||||
font-size: .7rem;
|
||||
color: var(--text-muted);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
margin-top: .25rem;
|
||||
}
|
||||
|
||||
/* Temperature dot */
|
||||
.temp-dot {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
margin-right: .25rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.temp-dot-green { background: var(--green); box-shadow: 0 0 4px rgba(35, 134, 54, 0.5); }
|
||||
.temp-dot-yellow { background: var(--yellow); box-shadow: 0 0 4px rgba(210, 153, 34, 0.5); }
|
||||
.temp-dot-red { background: var(--red); box-shadow: 0 0 4px rgba(218, 54, 51, 0.5); }
|
||||
|
||||
.system-info-item-compact {
|
||||
flex: 0 1 auto;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
/* Backup status card */
|
||||
.backup-status-card {
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius);
|
||||
padding: 1rem 1.25rem;
|
||||
border: 1px solid var(--border-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.backup-status-card h3 {
|
||||
margin-bottom: .75rem;
|
||||
}
|
||||
.backup-info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: .25rem 0;
|
||||
font-size: .85rem;
|
||||
}
|
||||
.backup-label {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.backup-value {
|
||||
color: var(--text-primary);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: .8rem;
|
||||
}
|
||||
.backup-status-ok { color: var(--green); }
|
||||
.backup-status-fail { color: var(--red); }
|
||||
.backup-status-none { color: var(--text-muted); }
|
||||
|
||||
/* Responsive */
|
||||
@media(max-width: 768px) {
|
||||
.sidebar { width: 100%; height: auto; position: relative; border-right: none; border-bottom: 1px solid var(--border-color); }
|
||||
|
||||
Reference in New Issue
Block a user