183 lines
5.4 KiB
Go
183 lines
5.4 KiB
Go
package collector
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type PBSInfo struct {
|
|
Available bool `json:"available"`
|
|
Version string `json:"version,omitempty"`
|
|
Datastores []PBSDatastore `json:"datastores,omitempty"`
|
|
Tasks []PBSTask `json:"tasks,omitempty"`
|
|
GC []PBSGCStatus `json:"gc,omitempty"`
|
|
SyncJobs int `json:"sync_jobs"`
|
|
}
|
|
|
|
type PBSDatastore struct {
|
|
Name string `json:"name"`
|
|
Path string `json:"path,omitempty"`
|
|
Total int64 `json:"total"`
|
|
Used int64 `json:"used"`
|
|
Available int64 `json:"available"`
|
|
BackupCount int `json:"backup_count"`
|
|
}
|
|
|
|
type PBSTask struct {
|
|
ID string `json:"id,omitempty"`
|
|
Node string `json:"node,omitempty"`
|
|
Type string `json:"type,omitempty"`
|
|
Status string `json:"status,omitempty"`
|
|
StartTime int64 `json:"start_time,omitempty"`
|
|
EndTime int64 `json:"end_time,omitempty"`
|
|
Duration int64 `json:"duration,omitempty"`
|
|
User string `json:"user,omitempty"`
|
|
Datastore string `json:"datastore,omitempty"`
|
|
}
|
|
|
|
type PBSGCStatus struct {
|
|
Datastore string `json:"datastore"`
|
|
Status string `json:"status,omitempty"`
|
|
LastRun int64 `json:"last_run,omitempty"`
|
|
Duration int64 `json:"duration,omitempty"`
|
|
}
|
|
|
|
func CollectPBS() *PBSInfo {
|
|
// PBS erkennen
|
|
if _, err := os.Stat("/usr/sbin/proxmox-backup-manager"); err != nil {
|
|
return nil // PBS nicht installiert
|
|
}
|
|
|
|
log.Printf("PBS: proxmox-backup-manager gefunden, sammle Daten...")
|
|
pbs := &PBSInfo{Available: true}
|
|
|
|
// Version
|
|
if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "versions", "--output-format", "json").Output(); err == nil {
|
|
var versions []map[string]interface{}
|
|
if json.Unmarshal(out, &versions) == nil {
|
|
for _, v := range versions {
|
|
if pkg, ok := v["Package"].(string); ok && pkg == "proxmox-backup-server" {
|
|
if ver, ok := v["Version"].(string); ok {
|
|
pbs.Version = ver
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Datastores
|
|
if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "datastore", "list", "--output-format", "json").Output(); err == nil {
|
|
var list []map[string]interface{}
|
|
if json.Unmarshal(out, &list) == nil {
|
|
for _, d := range list {
|
|
ds := PBSDatastore{}
|
|
if name, ok := d["name"].(string); ok {
|
|
ds.Name = name
|
|
}
|
|
if path, ok := d["path"].(string); ok {
|
|
ds.Path = path
|
|
}
|
|
if total, ok := d["total"].(float64); ok {
|
|
ds.Total = int64(total)
|
|
}
|
|
if used, ok := d["used"].(float64); ok {
|
|
ds.Used = int64(used)
|
|
}
|
|
if avail, ok := d["avail"].(float64); ok {
|
|
ds.Available = int64(avail)
|
|
}
|
|
// Backup-Anzahl: alle Timestamp-Verzeichnisse zaehlen
|
|
// Struktur: <path>/<type>/<id>/<timestamp> oder <path>/ns/<ns>/<type>/<id>/<timestamp>
|
|
// Timestamp-Format: 2026-02-18T18:24:36Z
|
|
if ds.Path != "" {
|
|
countCmd := exec.Command("/bin/sh", "-c",
|
|
`find `+ds.Path+` -type d 2>/dev/null | grep -cE '/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$'`)
|
|
if out, err := countCmd.Output(); err == nil {
|
|
if n, err := strconv.Atoi(strings.TrimSpace(string(out))); err == nil {
|
|
ds.BackupCount = n
|
|
}
|
|
}
|
|
}
|
|
|
|
pbs.Datastores = append(pbs.Datastores, ds)
|
|
}
|
|
}
|
|
} else {
|
|
log.Printf("PBS: datastore list fehler: %v", err)
|
|
}
|
|
|
|
// Letzte Tasks (max 20)
|
|
if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "task", "list", "--limit", "20", "--output-format", "json").Output(); err == nil {
|
|
var list []map[string]interface{}
|
|
if json.Unmarshal(out, &list) == nil {
|
|
for _, t := range list {
|
|
task := PBSTask{}
|
|
if id, ok := t["upid"].(string); ok {
|
|
task.ID = id
|
|
}
|
|
if node, ok := t["node"].(string); ok {
|
|
task.Node = node
|
|
}
|
|
if typ, ok := t["type"].(string); ok {
|
|
task.Type = typ
|
|
}
|
|
if status, ok := t["status"].(string); ok {
|
|
task.Status = status
|
|
}
|
|
if start, ok := t["starttime"].(float64); ok {
|
|
task.StartTime = int64(start)
|
|
}
|
|
if end, ok := t["endtime"].(float64); ok {
|
|
task.EndTime = int64(end)
|
|
if task.StartTime > 0 {
|
|
task.Duration = task.EndTime - task.StartTime
|
|
}
|
|
}
|
|
if user, ok := t["user"].(string); ok {
|
|
task.User = user
|
|
}
|
|
pbs.Tasks = append(pbs.Tasks, task)
|
|
}
|
|
}
|
|
} else {
|
|
log.Printf("PBS: task list fehler: %v", err)
|
|
}
|
|
|
|
// Garbage Collection Status pro Datastore
|
|
for _, ds := range pbs.Datastores {
|
|
gc := PBSGCStatus{Datastore: ds.Name}
|
|
if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "garbage-collection", "status", ds.Name, "--output-format", "json").Output(); err == nil {
|
|
var status map[string]interface{}
|
|
if json.Unmarshal(out, &status) == nil {
|
|
if upid, ok := status["upid"].(string); ok && upid != "" {
|
|
gc.Status = "running"
|
|
} else if lastRun, ok := status["last-run-starttime"].(float64); ok {
|
|
gc.LastRun = int64(lastRun)
|
|
if duration, ok := status["last-run-duration"].(float64); ok {
|
|
gc.Duration = int64(duration)
|
|
}
|
|
gc.Status = "ok"
|
|
} else {
|
|
gc.Status = "never"
|
|
}
|
|
}
|
|
}
|
|
pbs.GC = append(pbs.GC, gc)
|
|
}
|
|
|
|
// Sync Jobs zählen
|
|
if out, err := exec.Command("/usr/sbin/proxmox-backup-manager", "sync-job", "list", "--output-format", "json").Output(); err == nil {
|
|
var jobs []interface{}
|
|
if json.Unmarshal(out, &jobs) == nil {
|
|
pbs.SyncJobs = len(jobs)
|
|
}
|
|
}
|
|
|
|
log.Printf("PBS: %d Datastores, %d Tasks, %d SyncJobs gesammelt", len(pbs.Datastores), len(pbs.Tasks), pbs.SyncJobs)
|
|
return pbs
|
|
}
|