forked from mustafaakin/gonit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
services.go
139 lines (116 loc) · 2.98 KB
/
services.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
136
137
138
139
package overwatch
import (
"os"
"os/signal"
"path"
"syscall"
"time"
"io/ioutil"
log "github.com/Sirupsen/logrus"
"github.com/mitchellh/go-ps"
"github.com/shirou/gopsutil/host"
)
// runningServices holds the pids of the services
var runningServices map[string]int
// Service describes how should a service be run, what its name is and what it does TODO: add respawn and something like runlevels? maybe dependencies
type Service struct {
Name string
Description string
}
// setupSignalHandler catches SIGCHILD for now only.
func setupSignalHandler() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt,
syscall.SIGCHLD,
syscall.SIGTERM,
syscall.SIGKILL)
go func() {
for sig := range c {
log.Printf("captured %v", sig)
}
}()
}
func printStatus() {
h, err := host.HostInfo()
if err != nil {
log.Println("Could not get host info", err)
}
log.Println(h.String())
procs, err := ps.Processes()
if err != nil {
log.Println("Could not get processes")
}
log.Println(len(procs))
for _, e := range procs {
log.Println(e.Executable(), e.Pid(), e.PPid())
}
}
// ConfigureServices stars the services, registers the SIGCHILD handler
func ConfigureServices(c *Config) {
log.WithFields(log.Fields{
"title": c.Title,
"version": c.Version,
}).Info("Starting services")
setupSignalHandler()
for _, serv := range c.Services {
log.WithFields(log.Fields{
"service": serv.Name,
}).Info("Starting service")
spawn(serv.Name)
}
// printStatus()
}
// spawn spawns the given filename in background using syscall
func spawn(name string) {
filepath := path.Join("/init/services", name)
stdinpath := path.Join("/logs/", name+".stdin")
stdoutpath := path.Join("/logs/", name+".stdout")
stderrpath := path.Join("/logs/", name+".stderr")
os.MkdirAll(path.Dir(stdinpath), 0777)
os.MkdirAll(path.Dir(stdoutpath), 0777)
os.MkdirAll(path.Dir(stderrpath), 0777)
fstdin, err := os.Create(stdinpath)
if err != nil {
log.Println("waat", err)
}
fstdout, err := os.Create(stdoutpath)
if err != nil {
log.Println("waat", err)
}
fstderr, err := os.Create(stderrpath)
if err != nil {
log.Println("waat", err)
}
// Open Files for stdout, stderr
procAttr := &syscall.ProcAttr{
Dir: "/",
Env: []string{"MYVAR=345"},
Files: []uintptr{fstdin.Fd(), fstdout.Fd(), fstderr.Fd()},
Sys: nil,
}
pid, err := syscall.ForkExec(filepath, nil, procAttr)
if err != nil {
log.WithFields(log.Fields{
"service": filepath,
"error": err,
}).Error("Could not start service.")
} else {
log.WithFields(log.Fields{
"service": filepath,
"pid": pid,
}).Info("Started service succesfully")
}
log.Info("Waiting for 3 seconds")
time.Sleep(3 * time.Second)
a, err1 := ioutil.ReadFile(stdoutpath)
b, err2 := ioutil.ReadFile(stderrpath)
if err1 != nil || err2 != nil {
log.Error("Could not read", err1, err2)
} else {
log.WithFields(log.Fields{
"service": name,
"stdout": string(a),
"stderr": string(b),
}).Info("Service ended.")
}
}