- Neuer Collector: agent/collector/cron.go - Zwei Quellen: crontab -l (System) + config.xml OPNsense-Jobs - Daten im Heartbeat unter 'cron_jobs' - Pro Job: source, schedule, enabled, command, description, uuid, origin - Backend Model CronJob in models/system.go - Getestet: 18 Jobs auf Produktion (8 System + 10 OPNsense) - README + Dateistruktur aktualisiert - Agent auf allen 3 Firewalls deployed
146 lines
3.5 KiB
Go
146 lines
3.5 KiB
Go
package collector
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
type CronJob struct {
|
|
Source string `json:"source"` // "system" oder "opnsense"
|
|
Enabled bool `json:"enabled"`
|
|
Minutes string `json:"minutes"`
|
|
Hours string `json:"hours"`
|
|
Days string `json:"days"`
|
|
Months string `json:"months"`
|
|
Weekdays string `json:"weekdays"`
|
|
Command string `json:"command"`
|
|
Parameters string `json:"parameters,omitempty"`
|
|
Who string `json:"who,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
UUID string `json:"uuid,omitempty"`
|
|
Origin string `json:"origin,omitempty"`
|
|
Schedule string `json:"schedule"` // Menschenlesbar: "*/4 * * * *"
|
|
}
|
|
|
|
func CollectCron() []CronJob {
|
|
var jobs []CronJob
|
|
|
|
// 1. System-Crontab (crontab -l)
|
|
sysJobs := collectSystemCrontab()
|
|
jobs = append(jobs, sysJobs...)
|
|
|
|
// 2. OPNsense config.xml Cron-Jobs
|
|
opnJobs := collectOPNsenseCron()
|
|
jobs = append(jobs, opnJobs...)
|
|
|
|
log.Printf("Cron: %d Jobs gesammelt (%d System, %d OPNsense)",
|
|
len(jobs), len(sysJobs), len(opnJobs))
|
|
|
|
return jobs
|
|
}
|
|
|
|
func collectSystemCrontab() []CronJob {
|
|
out, err := exec.Command("/bin/sh", "-c", "/usr/bin/crontab -l").Output()
|
|
output := string(out)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
var jobs []CronJob
|
|
for _, line := range strings.Split(output, "\n") {
|
|
line = strings.TrimSpace(line)
|
|
// Kommentare, leere Zeilen, Variablen ueberspringen
|
|
if line == "" || strings.HasPrefix(line, "#") || strings.Contains(line, "=") {
|
|
continue
|
|
}
|
|
|
|
// Crontab-Format: min hour day month weekday command
|
|
fields := strings.Fields(line)
|
|
if len(fields) < 6 {
|
|
continue
|
|
}
|
|
|
|
command := strings.Join(fields[5:], " ")
|
|
// Klammern und Redirects bereinigen
|
|
command = strings.TrimPrefix(command, "(")
|
|
command = strings.TrimSuffix(command, ") > /dev/null")
|
|
|
|
jobs = append(jobs, CronJob{
|
|
Source: "system",
|
|
Enabled: true,
|
|
Minutes: fields[0],
|
|
Hours: fields[1],
|
|
Days: fields[2],
|
|
Months: fields[3],
|
|
Weekdays: fields[4],
|
|
Command: command,
|
|
Schedule: strings.Join(fields[:5], " "),
|
|
})
|
|
}
|
|
|
|
return jobs
|
|
}
|
|
|
|
func collectOPNsenseCron() []CronJob {
|
|
data, err := os.ReadFile("/conf/config.xml")
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
type cronJob struct {
|
|
UUID string `xml:"uuid,attr"`
|
|
Origin string `xml:"origin"`
|
|
Enabled string `xml:"enabled"`
|
|
Minutes string `xml:"minutes"`
|
|
Hours string `xml:"hours"`
|
|
Days string `xml:"days"`
|
|
Months string `xml:"months"`
|
|
Weekdays string `xml:"weekdays"`
|
|
Who string `xml:"who"`
|
|
Command string `xml:"command"`
|
|
Parameters string `xml:"parameters"`
|
|
Description string `xml:"description"`
|
|
}
|
|
|
|
type opnsenseCron struct {
|
|
Jobs []cronJob `xml:"OPNsense>cron>jobs>job"`
|
|
}
|
|
|
|
var cfg opnsenseCron
|
|
if err := xml.Unmarshal(data, &cfg); err != nil {
|
|
log.Printf("Cron XML parsen fehlgeschlagen: %v", err)
|
|
return nil
|
|
}
|
|
|
|
var jobs []CronJob
|
|
for _, j := range cfg.Jobs {
|
|
schedule := strings.Join([]string{j.Minutes, j.Hours, j.Days, j.Months, j.Weekdays}, " ")
|
|
|
|
cmd := j.Command
|
|
if j.Parameters != "" {
|
|
cmd += " " + j.Parameters
|
|
}
|
|
|
|
jobs = append(jobs, CronJob{
|
|
Source: "opnsense",
|
|
Enabled: j.Enabled == "1",
|
|
Minutes: j.Minutes,
|
|
Hours: j.Hours,
|
|
Days: j.Days,
|
|
Months: j.Months,
|
|
Weekdays: j.Weekdays,
|
|
Command: cmd,
|
|
Who: j.Who,
|
|
Description: strings.TrimSpace(j.Description),
|
|
UUID: j.UUID,
|
|
Origin: j.Origin,
|
|
Schedule: schedule,
|
|
})
|
|
}
|
|
|
|
return jobs
|
|
}
|