185 lines
4.1 KiB
Go
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
|
|
}
|