scron/main.go
kekskurse b80ac51326
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
feat: add dump-conig function
2025-08-26 13:43:53 +02:00

185 lines
4.1 KiB
Go

package main
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"syscall"
"time"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v2"
"github.com/urfave/cli/v3"
)
var currentConfig config
func main() {
// zerolog.SetGlobalLevel(zerolog.InfoLevel)
log.Info().Msg("Start")
cmd := &cli.Command{
Commands: []*cli.Command{
{
Name: "run",
Usage: "run the scron",
Action: func(context.Context, *cli.Command) error {
deamon()
return nil
},
},
{
Name: "dump-config",
Usage: "show the complete config",
Action: func(context.Context, *cli.Command) error {
var err error
currentConfig, err = ReadFromFile("config.yml")
if err != nil {
return err
}
res, err := yaml.Marshal(currentConfig)
if err != nil {
return err
}
fmt.Println(string(res))
return nil
},
},
},
}
if err := cmd.Run(context.Background(), os.Args); err != nil {
log.Fatal().Err(err).Msg("error calling scron")
}
}
func deamon() {
var err error
currentConfig, err = ReadFromFile("config.yml")
if err != nil {
log.Fatal().Err(err).Msg("Cant read config file")
}
log.Debug().Interface("config", currentConfig).Msg("config")
if len(currentConfig.Jobs) == 0 {
log.Warn().Msg("config dont include any jobs")
}
cronTicker, configTicker := createTickers(realTimeProvider{})
// Hauptloop mit select
for {
select {
case t := <-cronTicker:
execucteJobs(t, currentConfig)
case <-configTicker:
log.Debug().Msg("Reload Config")
currentConfig, err = ReadFromFile("config.yml")
if err != nil {
log.Error().Err(err).Msg("cant read config")
}
}
}
}
func execucteJobs(t time.Time, c config) {
for _, job := range c.Jobs {
execute, err := job.MatchCurrentTime(t)
log.Debug().Bool("execution", execute).Time("t", t).Msg("check cron execution")
if err != nil {
log.Error().Err(err).Msg("cant pars time for job")
}
if !execute {
continue
}
go executeJob(t, job, c)
}
}
func executeJob(t time.Time, job jobconfig, c config) {
result, err := executeCommand(job)
log.Info().Str("name", job.Name).Str("command", job.Command).Time("execute-for", t).Int("execCode", result.execCode).Str("output", result.outputString).Err(result.err).Msg("Done execute task")
if err != nil {
log.Err(err).Msg("Error while Execute command")
}
for _, n := range c.Notification {
if n.Name == job.Notification {
sendNotification(result, n)
}
}
}
func sendNotification(result jobResult, notification notificationConfig) error {
title := ""
msg := Message{}
msg.Priority = 10
if result.isSuccess() {
title = "✅ [scron][success] " + result.job.Name
msg.Priority = -1
} else {
title = "❌ [scron][error] " + result.job.Name
}
msg.Message = result.outputString
msg.Title = title
if result.isSuccess() {
if notification.Success.Gotify.URL != "" {
err := SendGotifyNotification(notification.Success.Gotify.URL, msg)
if err != nil {
log.Error().Err(err).Msg("cant send gotify notification")
}
}
if notification.Success.Smtp.Host != "" {
err := SendSMTPNotification(notification.Success.Smtp, title, result.outputString)
if err != nil {
log.Error().Err(err).Msg("cant send smtp notification")
}
}
} else {
if notification.Error.Gotify.URL != "" {
err := SendGotifyNotification(notification.Error.Gotify.URL, msg)
if err != nil {
log.Error().Err(err).Msg("cant send gotify notification")
}
}
if notification.Error.Smtp.Host != "" {
err := SendSMTPNotification(notification.Error.Smtp, title, result.outputString)
if err != nil {
log.Error().Err(err).Msg("cant send smtp notification")
}
}
}
return nil
}
func executeCommand(job jobconfig) (jobResult, error) {
j := jobResult{}
j.job = job
var output bytes.Buffer
cmd := exec.Command("bash", "-c", job.Command)
cmd.Stdout = &output
cmd.Stderr = &output
err := cmd.Run()
j.outputString = output.String()
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
j.execCode = status.ExitStatus()
}
} else {
j.err = err
return j, err
}
}
return j, nil
}