forked from jpillora/overseer
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathoverseer.go
More file actions
131 lines (123 loc) · 3.46 KB
/
overseer.go
File metadata and controls
131 lines (123 loc) · 3.46 KB
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
// Daemonizable self-upgrading binaries in Go (golang).
package overseer
import (
"errors"
"fmt"
"log"
"os"
"runtime"
"time"
"github.com/jpillora/overseer/fetcher"
)
const (
envSlaveID = "GO_UPGRADE_SLAVE_ID"
envIsSlave = "GO_UPGRADE_IS_SLAVE"
envNumFDs = "GO_UPGRADE_NUM_FDS"
envBinID = "GO_UPGRADE_BIN_ID"
envBinCheck = "GO_UPGRADE_BIN_CHECK"
)
type Config struct {
//Required will prevent overseer from fallback to running
//running the program in the main process on failure.
Required bool
//Program's main function
Program func(state State)
//Program's zero-downtime socket listening address (set this or Addresses)
Address string
//Program's zero-downtime socket listening addresses (set this or Address)
Addresses []string
//RestartSignal will manually trigger a graceful restart. Defaults to SIGUSR2.
RestartSignal os.Signal
//TerminateTimeout controls how long overseer should
//wait for the program to terminate itself. After this
//timeout, overseer will issue a SIGKILL.
TerminateTimeout time.Duration
//MinFetchInterval defines the smallest duration between Fetch()s.
//This helps to prevent unwieldy fetch.Interfaces from hogging
//too many resources. Defaults to 1 second.
MinFetchInterval time.Duration
//PreUpgrade runs after a binary has been retreived, user defined checks
//can be run here and returning an error will cancel the upgrade.
PreUpgrade func(tempBinaryPath string) error
//Debug enables all [overseer] logs.
Debug bool
//NoWarn disables warning [overseer] logs.
NoWarn bool
//NoRestart disables all restarts, this option essentially converts
//the RestartSignal into a "ShutdownSignal".
NoRestart bool
//NoRestartAfterFetch disables automatic restarts after each upgrade.
//Though manual restarts using the RestartSignal can still be performed.
NoRestartAfterFetch bool
NoFetchLoop bool
FetchOnRestart bool
//Fetcher will be used to fetch binaries.
Fetcher fetcher.Interface
}
func validate(c *Config) error {
//validate
if c.Program == nil {
return errors.New("overseer.Config.Program required")
}
if c.Address != "" {
if len(c.Addresses) > 0 {
return errors.New("overseer.Config.Address and Addresses cant both be set")
}
c.Addresses = []string{c.Address}
} else if len(c.Addresses) > 0 {
c.Address = c.Addresses[0]
}
if c.RestartSignal == nil {
c.RestartSignal = SIGUSR2
}
if c.TerminateTimeout <= 0 {
c.TerminateTimeout = 30 * time.Second
}
if c.MinFetchInterval <= 0 {
c.MinFetchInterval = 1 * time.Second
}
return nil
}
//RunErr allows manual handling of any
//overseer errors.
func RunErr(c Config) error {
return runErr(&c)
}
//Run executes overseer, if an error is
//encounted, overseer fallsback to running
//the program directly (unless Required is set).
func Run(c Config) {
err := runErr(&c)
if err != nil {
if c.Required {
log.Fatalf("[overseer] %s", err)
} else if c.Debug || !c.NoWarn {
log.Printf("[overseer] disabled. run failed: %s", err)
}
c.Program(DisabledState)
return
}
os.Exit(0)
}
func runErr(c *Config) error {
if err := validate(c); err != nil {
return err
}
//sanity check
if token := os.Getenv(envBinCheck); token != "" {
fmt.Fprint(os.Stdout, token)
return nil
}
//os not supported
if !supported {
return fmt.Errorf("os (%s) not supported", runtime.GOOS)
}
//run either in master or slave mode
if os.Getenv(envIsSlave) == "1" {
sp := slave{Config: c}
return sp.run()
} else {
mp := master{Config: c}
return mp.run()
}
}