Browse Source

added configuration file with adjustable precision and tasks location

tags/version-1.1
Vladimir Smagin 7 months ago
parent
commit
e577cddf19
9 changed files with 118 additions and 45 deletions
  1. 2
    1
      build.sh
  2. 66
    6
      config.go
  3. 17
    0
      config/gogocron.yml
  4. 3
    2
      configs/test1.yml
  5. 2
    1
      configs/test2.yml
  6. 1
    1
      debian/DEBIAN/control
  7. 2
    22
      file_utils.go
  8. 23
    10
      gogocron.go
  9. 2
    2
      timing.go

+ 2
- 1
build.sh View File

@@ -1,6 +1,6 @@
#!/bin/bash

VERSION="1.0.1"
VERSION="1.1"

# build gogocron
go build
@@ -16,6 +16,7 @@ mkdir -p ./debian/usr/share/gogocron/samples/
mkdir -p ./debian/DEBIAN

cp gogocron ./debian/usr/bin/
cp config/gogocron.yml ./debian/etc/gogocron/
cp configs/*.yml ./debian/usr/share/gogocron/samples/

# build deb package

+ 66
- 6
config.go View File

@@ -1,17 +1,77 @@
package main

import "log"
import (
"io/ioutil"
"log"
"time"

// loadConfig() searches for config files and reading them to cronTasks
yaml "gopkg.in/yaml.v2"
)

// loadConfig loads gogocron settings from preallocated yaml config file
func loadConfig() cronConfig {
var gogoconfig cronConfig

yamldata, err := ioutil.ReadFile(cronDefaultConfigLocation)
if err != nil {
log.Fatalf("Error opening file %v", err)
}

marshErr := yaml.Unmarshal(yamldata, &gogoconfig)
if marshErr != nil {
log.Fatalf("Task file malformed: %v", marshErr)
}

gogoconfig.Precision, _ = time.ParseDuration(cronDefaultPrecision)

if gogoconfig.TasksLocation == "" {
gogoconfig.TasksLocation = cronDefaultTasksLocation
}

if gogoconfig.PrecisionString != "" {
// config value was not empty, trying to parse it
if precision, err := time.ParseDuration(gogoconfig.PrecisionString); err == nil {
// check if precision between 10ms and 500ms
if precision >= time.Duration(10000000) && precision <= time.Duration(500000000) {
// ok! using value from config file
gogoconfig.Precision = precision
log.Printf("Precision was set to %s", gogoconfig.PrecisionString)
}
}

}

return gogoconfig
}

// readTaskConfigFile reads config file and returns cronTask struct back to loadTasks()
func readTaskConfigFile(path string) cronTask {
var config cronTask

yamldata, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("Error opening file %v", err)
}

//log.Printf(string(yamldata))

marshErr := yaml.Unmarshal(yamldata, &config)
if marshErr != nil {
log.Fatalf("Task file malformed: %v", marshErr)
}

return config
}

// loadTasks() searches for config files and reading them to cronTasks
// used once at start and every HUP signal
// TODO: add HUP signal
func loadConfig() cronTasks {
func loadTasks(gogoconfig cronConfig) cronTasks {
var tasks cronTasks

configFiles := readConfigDirectory("configs")
configFiles := readTasksDirectory(gogoconfig.TasksLocation)
log.Printf("Configuration files found: %v", configFiles)
for _, configFile := range configFiles {
config := readConfigFile(configFile)
config := readTaskConfigFile(configFile)
//log.Printf("Parsed %#v", config)
if config.Name != "" && len(config.Commands) > 0 {
tasks = append(tasks, config)

+ 17
- 0
config/gogocron.yml View File

@@ -0,0 +1,17 @@
---
# ticktack_precision
#
# Precision means how frequently gogocron checks seconds number change. Lower
# interval gets more resources because check circle works faster. This parameter
# created for high precision requirements where maximum cron run time deviation
# can't be more than 10 ms.
#
# Value (milliseconds) from 10ms to 500ms
# default: 100ms
ticktack_precision: 100ms

# tasks_location
# Set where tasks yaml files located
# Value (string)
# default: /etc/gogocron/configs
tasks_location: /etc/gogocron/configs

+ 3
- 2
configs/test1.yml View File

@@ -1,7 +1,8 @@
---
name: "Print base64 of 20 random symbols"
name: "TASK #1"
runsecond: "*/5"
logtype: disabled
logtype: full
user: vlad
env:
- TESTVAR="test variable"
commands:

+ 2
- 1
configs/test2.yml View File

@@ -1,7 +1,8 @@
---
name: "Test task #2"
name: "TASK #2"
runsecond: "*/15"
timeout: 1s
logtype: full
user: root
commands:
- "head -c 2 /dev/urandom |base64"

+ 1
- 1
debian/DEBIAN/control View File

@@ -1,5 +1,5 @@
Package: gogocron
Version: 1.0.1
Version: 1.1
Section: base
Priority: optional
Architecture: all

+ 2
- 22
file_utils.go View File

@@ -12,11 +12,10 @@ import (
"time"

"github.com/kr/pty" // required to run commands as other users
"gopkg.in/yaml.v2"
)

// readConfigDirectory get contents of target directory
func readConfigDirectory(path string) []string {
// readTasksDirectory get contents of target directory
func readTasksDirectory(path string) []string {
var res []string

files, err := ioutil.ReadDir(path)
@@ -32,25 +31,6 @@ func readConfigDirectory(path string) []string {
return res
}

// readConfigFile reads config file and returns cronTask struct back to loadConfig()
func readConfigFile(path string) cronTask {
var config cronTask

yamldata, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("Error opening file %v", err)
}

//log.Printf(string(yamldata))

marshErr := yaml.Unmarshal(yamldata, &config)
if marshErr != nil {
log.Fatalf("Task file malformed: %v", marshErr)
}

return config
}

func inArray(val interface{}, array interface{}) (exists bool, index int) {
exists = false
index = -1

+ 23
- 10
gogocron.go View File

@@ -18,9 +18,21 @@ import (
"time"
)

const (
cronDefaultConfigLocation string = "/etc/gogocron/gogocron.yml"
cronDefaultTasksLocation string = "/etc/gogocron/configs"
cronDefaultPrecision string = "100ms"
)

type cronConfig struct {
Precision time.Duration
PrecisionString string `yaml:"ticktack_precision,omitempty"` // how frequently check seconds change
TasksLocation string `yaml:"tasks_location,omitempty"` // where tasks configs stored
}

type cronTask struct {
Name string `yaml:"name"` //name of task
AsUser string `yaml:"user,omitempty"` //run as user
Name string `yaml:"name"` // name of task
AsUser string `yaml:"user,omitempty"` // run as user
RunSecond string `yaml:"runsecond,omitempty"` // second
RunMinute string `yaml:"runminute,omitempty"` // minute
RunHour string `yaml:"runhour,omitempty"` // hour
@@ -140,25 +152,26 @@ func executeTask(ctx context.Context, task cronTask) {
}

func main() {
log.Println(`GoGoCron 1.0.1 welcomes you!
Copyright by Vladimir Smagin, 2018 (21h@blindage.org)
Visit http://gogocron.blindage.org to read manual and updates`)
log.Println("gogocron 1.1 by Vladimir Smagin (http://gogocron.blindage.org)")

// Load config at startup, once
gogoConfig := loadConfig()

// Load config at startup
tasks := loadConfig()
// Load tasks
tasks := loadTasks(gogoConfig)

// Goroutine reloads config if SIGHUP received
// Goroutine reloads tasks if SIGHUP received
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGHUP)
go func() {
for signame := range sigchan {
log.Println("Received signal HUP, reloading configuration", signame)
tasks = loadConfig()
tasks = loadTasks(gogoConfig)
}
}()

tickchan := make(chan struct{})
go ticktack(tickchan)
go ticktack(tickchan, gogoConfig)

for {
select {

+ 2
- 2
timing.go View File

@@ -8,7 +8,7 @@ import (
)

// tick tack tick tack tick tack tick tack
func ticktack(tickchan chan struct{}) {
func ticktack(tickchan chan struct{}, gogoConfig cronConfig) {
lastSecond := time.Now().Second()
for {
currentSecond := time.Now().Second()
@@ -16,7 +16,7 @@ func ticktack(tickchan chan struct{}) {
tickchan <- struct{}{}
lastSecond = currentSecond
}
time.Sleep(time.Second / 100) // check time every 10 ms
time.Sleep(gogoConfig.Precision)
}
}


Loading…
Cancel
Save