forked from Pluies/config-reloader-sidecar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
135 lines (116 loc) · 2.81 KB
/
main.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
135
package main
import (
"fmt"
"log"
"os"
"strings"
"syscall"
"time"
"github.com/bep/debounce"
"github.com/fsnotify/fsnotify"
"github.com/mitchellh/go-ps"
"golang.org/x/sys/unix"
)
func main() {
configDir := os.Getenv("CONFIG_DIR")
if configDir == "" {
log.Fatal("mandatory env var CONFIG_DIR is empty, exiting")
}
processName := os.Getenv("PROCESS_NAME")
if processName == "" {
log.Fatal("mandatory env var PROCESS_NAME is empty, exiting")
}
verbose := false
verboseFlag := os.Getenv("VERBOSE")
if verboseFlag == "true" {
verbose = true
}
delay, _ := time.ParseDuration("0")
delayFlag := os.Getenv("DEBOUNCE_DELAY")
if delayFlag != "" {
delayDuration, err := time.ParseDuration(delayFlag)
if err != nil {
log.Fatal(err)
}
delay = delayDuration
}
debounced := debounce.New(delay)
var reloadSignal syscall.Signal
reloadSignalStr := os.Getenv("RELOAD_SIGNAL")
if reloadSignalStr == "" {
log.Printf("RELOAD_SIGNAL is empty, defaulting to SIGHUP")
reloadSignal = syscall.SIGHUP
} else {
reloadSignal = unix.SignalNum(reloadSignalStr)
if reloadSignal == 0 {
log.Fatalf("cannot find signal for RELOAD_SIGNAL: %s", reloadSignalStr)
}
}
log.Printf("starting with CONFIG_DIR=%s, PROCESS_NAME=%s, RELOAD_SIGNAL=%s, DEBOUNCE_DELAY=%s\n", configDir, processName, reloadSignal, delay)
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
done := make(chan bool)
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if verbose {
log.Println("event:", event)
}
if event.Op&fsnotify.Chmod != fsnotify.Chmod {
log.Println("modified file:", event.Name)
debounced(func() {
err := reloadProcess(processName, reloadSignal)
if err != nil {
log.Println("error:", err)
}
})
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error:", err)
}
}
}()
configDirs := strings.Split(configDir, ",")
for _, dir := range configDirs {
err = watcher.Add(dir)
if err != nil {
log.Fatal(err)
}
}
<-done
}
func findPID(process string) (int, error) {
processes, err := ps.Processes()
if err != nil {
return -1, fmt.Errorf("failed to list processes: %v\n", err)
}
for _, p := range processes {
if p.Executable() == process {
log.Printf("found executable %s (pid: %d)\n", p.Executable(), p.Pid())
return p.Pid(), nil
}
}
return -1, fmt.Errorf("no process matching %s found\n", process)
}
func reloadProcess(process string, signal syscall.Signal) error {
pid, err := findPID(process)
if err != nil {
return err
}
err = syscall.Kill(pid, signal)
if err != nil {
return fmt.Errorf("could not send signal: %v\n", err)
}
log.Printf("signal %s sent to %s (pid: %d)\n", signal, process, pid)
return nil
}