Browse Source

added configuration file with adjustable precision and tasks location

tags/version-1.1
Vladimir Smagin 5 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 @@
1 1
 #!/bin/bash
2 2
 
3
-VERSION="1.0.1"
3
+VERSION="1.1"
4 4
 
5 5
 # build gogocron
6 6
 go build
@@ -16,6 +16,7 @@ mkdir -p ./debian/usr/share/gogocron/samples/
16 16
 mkdir -p ./debian/DEBIAN
17 17
 
18 18
 cp gogocron ./debian/usr/bin/
19
+cp config/gogocron.yml ./debian/etc/gogocron/
19 20
 cp configs/*.yml ./debian/usr/share/gogocron/samples/
20 21
 
21 22
 # build deb package

+ 66
- 6
config.go View File

@@ -1,17 +1,77 @@
1 1
 package main
2 2
 
3
-import "log"
3
+import (
4
+	"io/ioutil"
5
+	"log"
6
+	"time"
4 7
 
5
-// loadConfig() searches for config files and reading them to cronTasks
8
+	yaml "gopkg.in/yaml.v2"
9
+)
10
+
11
+// loadConfig loads gogocron settings from preallocated yaml config file
12
+func loadConfig() cronConfig {
13
+	var gogoconfig cronConfig
14
+
15
+	yamldata, err := ioutil.ReadFile(cronDefaultConfigLocation)
16
+	if err != nil {
17
+		log.Fatalf("Error opening file %v", err)
18
+	}
19
+
20
+	marshErr := yaml.Unmarshal(yamldata, &gogoconfig)
21
+	if marshErr != nil {
22
+		log.Fatalf("Task file malformed: %v", marshErr)
23
+	}
24
+
25
+	gogoconfig.Precision, _ = time.ParseDuration(cronDefaultPrecision)
26
+
27
+	if gogoconfig.TasksLocation == "" {
28
+		gogoconfig.TasksLocation = cronDefaultTasksLocation
29
+	}
30
+
31
+	if gogoconfig.PrecisionString != "" {
32
+		// config value was not empty, trying to parse it
33
+		if precision, err := time.ParseDuration(gogoconfig.PrecisionString); err == nil {
34
+			// check if precision between 10ms and 500ms
35
+			if precision >= time.Duration(10000000) && precision <= time.Duration(500000000) {
36
+				// ok! using value from config file
37
+				gogoconfig.Precision = precision
38
+				log.Printf("Precision was set to %s", gogoconfig.PrecisionString)
39
+			}
40
+		}
41
+
42
+	}
43
+
44
+	return gogoconfig
45
+}
46
+
47
+// readTaskConfigFile reads config file and returns cronTask struct back to loadTasks()
48
+func readTaskConfigFile(path string) cronTask {
49
+	var config cronTask
50
+
51
+	yamldata, err := ioutil.ReadFile(path)
52
+	if err != nil {
53
+		log.Fatalf("Error opening file %v", err)
54
+	}
55
+
56
+	//log.Printf(string(yamldata))
57
+
58
+	marshErr := yaml.Unmarshal(yamldata, &config)
59
+	if marshErr != nil {
60
+		log.Fatalf("Task file malformed: %v", marshErr)
61
+	}
62
+
63
+	return config
64
+}
65
+
66
+// loadTasks() searches for config files and reading them to cronTasks
6 67
 // used once at start and every HUP signal
7
-// TODO: add HUP signal
8
-func loadConfig() cronTasks {
68
+func loadTasks(gogoconfig cronConfig) cronTasks {
9 69
 	var tasks cronTasks
10 70
 
11
-	configFiles := readConfigDirectory("configs")
71
+	configFiles := readTasksDirectory(gogoconfig.TasksLocation)
12 72
 	log.Printf("Configuration files found: %v", configFiles)
13 73
 	for _, configFile := range configFiles {
14
-		config := readConfigFile(configFile)
74
+		config := readTaskConfigFile(configFile)
15 75
 		//log.Printf("Parsed %#v", config)
16 76
 		if config.Name != "" && len(config.Commands) > 0 {
17 77
 			tasks = append(tasks, config)

+ 17
- 0
config/gogocron.yml View File

@@ -0,0 +1,17 @@
1
+---
2
+# ticktack_precision
3
+#
4
+# Precision means how frequently gogocron checks seconds number change. Lower
5
+# interval gets more resources because check circle works faster. This parameter
6
+# created for high precision requirements where maximum cron run time deviation
7
+# can't be more than 10 ms.
8
+#
9
+# Value (milliseconds) from 10ms to 500ms
10
+# default: 100ms
11
+ticktack_precision: 100ms
12
+
13
+# tasks_location
14
+# Set where tasks yaml files located
15
+# Value (string)
16
+# default: /etc/gogocron/configs
17
+tasks_location: /etc/gogocron/configs

+ 3
- 2
configs/test1.yml View File

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

+ 2
- 1
configs/test2.yml View File

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

+ 1
- 1
debian/DEBIAN/control View File

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

+ 2
- 22
file_utils.go View File

@@ -12,11 +12,10 @@ import (
12 12
 	"time"
13 13
 
14 14
 	"github.com/kr/pty" // required to run commands as other users
15
-	"gopkg.in/yaml.v2"
16 15
 )
17 16
 
18
-// readConfigDirectory get contents of target directory
19
-func readConfigDirectory(path string) []string {
17
+// readTasksDirectory get contents of target directory
18
+func readTasksDirectory(path string) []string {
20 19
 	var res []string
21 20
 
22 21
 	files, err := ioutil.ReadDir(path)
@@ -32,25 +31,6 @@ func readConfigDirectory(path string) []string {
32 31
 	return res
33 32
 }
34 33
 
35
-// readConfigFile reads config file and returns cronTask struct back to loadConfig()
36
-func readConfigFile(path string) cronTask {
37
-	var config cronTask
38
-
39
-	yamldata, err := ioutil.ReadFile(path)
40
-	if err != nil {
41
-		log.Fatalf("Error opening file %v", err)
42
-	}
43
-
44
-	//log.Printf(string(yamldata))
45
-
46
-	marshErr := yaml.Unmarshal(yamldata, &config)
47
-	if marshErr != nil {
48
-		log.Fatalf("Task file malformed: %v", marshErr)
49
-	}
50
-
51
-	return config
52
-}
53
-
54 34
 func inArray(val interface{}, array interface{}) (exists bool, index int) {
55 35
 	exists = false
56 36
 	index = -1

+ 23
- 10
gogocron.go View File

@@ -18,9 +18,21 @@ import (
18 18
 	"time"
19 19
 )
20 20
 
21
+const (
22
+	cronDefaultConfigLocation string = "/etc/gogocron/gogocron.yml"
23
+	cronDefaultTasksLocation  string = "/etc/gogocron/configs"
24
+	cronDefaultPrecision      string = "100ms"
25
+)
26
+
27
+type cronConfig struct {
28
+	Precision       time.Duration
29
+	PrecisionString string `yaml:"ticktack_precision,omitempty"` // how frequently check seconds change
30
+	TasksLocation   string `yaml:"tasks_location,omitempty"`     // where tasks configs stored
31
+}
32
+
21 33
 type cronTask struct {
22
-	Name      string   `yaml:"name"`                //name of task
23
-	AsUser    string   `yaml:"user,omitempty"`      //run as user
34
+	Name      string   `yaml:"name"`                // name of task
35
+	AsUser    string   `yaml:"user,omitempty"`      // run as user
24 36
 	RunSecond string   `yaml:"runsecond,omitempty"` // second
25 37
 	RunMinute string   `yaml:"runminute,omitempty"` // minute
26 38
 	RunHour   string   `yaml:"runhour,omitempty"`   // hour
@@ -140,25 +152,26 @@ func executeTask(ctx context.Context, task cronTask) {
140 152
 }
141 153
 
142 154
 func main() {
143
-	log.Println(`GoGoCron 1.0.1 welcomes you!
144
-Copyright by Vladimir Smagin, 2018 (21h@blindage.org)
145
-Visit http://gogocron.blindage.org to read manual and updates`)
155
+	log.Println("gogocron 1.1 by Vladimir Smagin (http://gogocron.blindage.org)")
156
+
157
+	// Load config at startup, once
158
+	gogoConfig := loadConfig()
146 159
 
147
-	// Load config at startup
148
-	tasks := loadConfig()
160
+	// Load tasks
161
+	tasks := loadTasks(gogoConfig)
149 162
 
150
-	// Goroutine reloads config if SIGHUP received
163
+	// Goroutine reloads tasks if SIGHUP received
151 164
 	sigchan := make(chan os.Signal, 1)
152 165
 	signal.Notify(sigchan, syscall.SIGHUP)
153 166
 	go func() {
154 167
 		for signame := range sigchan {
155 168
 			log.Println("Received signal HUP, reloading configuration", signame)
156
-			tasks = loadConfig()
169
+			tasks = loadTasks(gogoConfig)
157 170
 		}
158 171
 	}()
159 172
 
160 173
 	tickchan := make(chan struct{})
161
-	go ticktack(tickchan)
174
+	go ticktack(tickchan, gogoConfig)
162 175
 
163 176
 	for {
164 177
 		select {

+ 2
- 2
timing.go View File

@@ -8,7 +8,7 @@ import (
8 8
 )
9 9
 
10 10
 // tick tack tick tack tick tack tick tack
11
-func ticktack(tickchan chan struct{}) {
11
+func ticktack(tickchan chan struct{}, gogoConfig cronConfig) {
12 12
 	lastSecond := time.Now().Second()
13 13
 	for {
14 14
 		currentSecond := time.Now().Second()
@@ -16,7 +16,7 @@ func ticktack(tickchan chan struct{}) {
16 16
 			tickchan <- struct{}{}
17 17
 			lastSecond = currentSecond
18 18
 		}
19
-		time.Sleep(time.Second / 100) // check time every 10 ms
19
+		time.Sleep(gogoConfig.Precision)
20 20
 	}
21 21
 }
22 22
 

Loading…
Cancel
Save