/
updater.go
134 lines (119 loc) · 2.57 KB
/
updater.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package updater
import (
"os"
"path/filepath"
"strings"
"time"
"github.com/rs/zerolog/log"
)
type AdminConfig struct {
URI string
Username string
Password string
}
type UpdaterConfig struct {
Hostname string
Admin AdminConfig
DataDir string
UpdateInterval time.Duration
Variables map[string]string
}
type Updater struct {
config UpdaterConfig
mtime string
done chan struct{}
}
func NewUpdater(config UpdaterConfig) *Updater {
if config.DataDir == "" {
config.DataDir = "/usr/local/etc/onlineconf"
}
if config.UpdateInterval == time.Duration(0) {
config.UpdateInterval = 10 * time.Second
}
return &Updater{
config: config,
done: make(chan struct{}),
}
}
func (u *Updater) Run() {
ticker := time.NewTicker(u.config.UpdateInterval)
defer ticker.Stop()
for {
select {
case <-u.done:
return
case <-ticker.C:
u.Update()
}
}
}
func (u *Updater) Stop() {
close(u.done)
}
func (u *Updater) Update() error {
respMtime, modules, err := getModules(u.config.Admin, u.config.Hostname, u.mtime, u.config.Variables)
if err != nil {
if err != ErrNotModified {
log.Error().Err(err).Msg("failed to fetch config")
}
return err
}
err = writeModules(u.config.DataDir, modules, respMtime)
if err != nil {
log.Error().Err(err).Msg("failed to write config files")
return err
}
u.mtime = respMtime
log.Info().Str("mtime", u.mtime).Msg("configuration updated")
return nil
}
func writeModules(dir string, modules map[string][]moduleParam, mtime string) error {
var err error
for module, params := range modules {
err1 := writeModule(dir, module, params, mtime)
if err1 != nil && err == nil {
err = err1
}
}
if err != nil {
return err
}
return removeOldFiles(dir, modules)
}
func removeOldFiles(dir string, modules map[string][]moduleParam) error {
d, err := os.Open(dir)
if err != nil {
return err
}
defer d.Close()
names, err := d.Readdirnames(0)
if err != nil {
return err
}
for _, name := range names {
var module string
if strings.HasSuffix(name, ".cdb") {
module = strings.TrimSuffix(name, ".cdb")
} else if strings.HasSuffix(name, ".conf") {
module = strings.TrimSuffix(name, ".conf")
}
if module == "" {
continue
}
_, ok := modules[module]
if ok {
continue
}
file := filepath.Join(dir, name)
err1 := os.Remove(file)
if err1 != nil {
log.Error().Err(err1).Str("file", file).Msg("failed to remove file")
if err == nil {
err = err1
}
continue
}
log.Info().Str("module", module).Str("file", file).Msg("removed old module file")
}
return err
}