TUN-2872: Exit with non-0 status code when the binary is updated so launchd will restart the service
This commit is contained in:
parent
2cf327ba01
commit
c3fa4552aa
|
@ -118,10 +118,6 @@ case "$1" in
|
||||||
echo "Starting $name"
|
echo "Starting $name"
|
||||||
$cmd >> "$stdout_log" 2>> "$stderr_log" &
|
$cmd >> "$stdout_log" 2>> "$stderr_log" &
|
||||||
echo $! > "$pid_file"
|
echo $! > "$pid_file"
|
||||||
if ! is_running; then
|
|
||||||
echo "Unable to start, see $stdout_log and $stderr_log"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
stop)
|
stop)
|
||||||
|
|
|
@ -60,7 +60,7 @@ func newLaunchdTemplate(installPath, stdoutPath, stderrPath string) *ServiceTemp
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
<key>ThrottleInterval</key>
|
<key>ThrottleInterval</key>
|
||||||
<integer>20</integer>
|
<integer>5</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>`, launchdIdentifier, stdoutPath, stderrPath),
|
</plist>`, launchdIdentifier, stdoutPath, stderrPath),
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import (
|
||||||
"github.com/getsentry/raven-go"
|
"github.com/getsentry/raven-go"
|
||||||
"github.com/gliderlabs/ssh"
|
"github.com/gliderlabs/ssh"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
"gopkg.in/urfave/cli.v2/altsrc"
|
"gopkg.in/urfave/cli.v2/altsrc"
|
||||||
|
@ -433,7 +434,6 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
errC <- origin.StartTunnelDaemon(ctx, tunnelConfig, connectedSignal, cloudflaredID, reconnectCh)
|
errC <- origin.StartTunnelDaemon(ctx, tunnelConfig, connectedSignal, cloudflaredID, reconnectCh)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, c.Duration("grace-period"))
|
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, c.Duration("grace-period"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,9 +607,15 @@ func notifySystemd(waitForSignal *signal.Signal) {
|
||||||
|
|
||||||
func writePidFile(waitForSignal *signal.Signal, pidFile string) {
|
func writePidFile(waitForSignal *signal.Signal, pidFile string) {
|
||||||
<-waitForSignal.Wait()
|
<-waitForSignal.Wait()
|
||||||
file, err := os.Create(pidFile)
|
expandedPath, err := homedir.Expand(pidFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.WithError(err).Errorf("Unable to write pid to %s", pidFile)
|
logger.WithError(err).Errorf("Unable to expand %s, try to use absolute path in --pidfile", pidFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, err := os.Create(expandedPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Errorf("Unable to write pid to %s", expandedPath)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
fmt.Fprintf(file, "%d", os.Getpid())
|
fmt.Fprintf(file, "%d", os.Getpid())
|
||||||
|
|
|
@ -17,9 +17,11 @@ func waitForSignal(errC chan error, shutdownC chan struct{}) error {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case err := <-errC:
|
case err := <-errC:
|
||||||
|
logger.Infof("terminating due to error: %v", err)
|
||||||
close(shutdownC)
|
close(shutdownC)
|
||||||
return err
|
return err
|
||||||
case <-signals:
|
case s := <-signals:
|
||||||
|
logger.Infof("terminating due to signal %s", s)
|
||||||
close(shutdownC)
|
close(shutdownC)
|
||||||
case <-shutdownC:
|
case <-shutdownC:
|
||||||
}
|
}
|
||||||
|
@ -44,10 +46,12 @@ func waitForSignalWithGraceShutdown(errC chan error,
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case err := <-errC:
|
case err := <-errC:
|
||||||
|
logger.Infof("Initiating graceful shutdown due to %v ...", err)
|
||||||
close(graceShutdownC)
|
close(graceShutdownC)
|
||||||
close(shutdownC)
|
close(shutdownC)
|
||||||
return err
|
return err
|
||||||
case <-signals:
|
case s := <-signals:
|
||||||
|
logger.Infof("Initiating graceful shutdown due to signal %s ...", s)
|
||||||
close(graceShutdownC)
|
close(graceShutdownC)
|
||||||
waitForGracePeriod(signals, errC, shutdownC, gracePeriod)
|
waitForGracePeriod(signals, errC, shutdownC, gracePeriod)
|
||||||
case <-graceShutdownC:
|
case <-graceShutdownC:
|
||||||
|
@ -64,7 +68,6 @@ func waitForGracePeriod(signals chan os.Signal,
|
||||||
shutdownC chan struct{},
|
shutdownC chan struct{},
|
||||||
gracePeriod time.Duration,
|
gracePeriod time.Duration,
|
||||||
) {
|
) {
|
||||||
logger.Infof("Initiating graceful shutdown...")
|
|
||||||
// Unregister signal handler early, so the client can send a second SIGTERM/SIGINT
|
// Unregister signal handler early, so the client can send a second SIGTERM/SIGINT
|
||||||
// to force shutdown cloudflared
|
// to force shutdown cloudflared
|
||||||
signal.Stop(signals)
|
signal.Stop(signals)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package updater
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
@ -32,6 +33,33 @@ EKx0BZogHSor9Wy5VztdFaAaVbsJiCbO
|
||||||
logger = log.CreateLogger()
|
logger = log.CreateLogger()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BinaryUpdated implements ExitCoder interface, the app will exit with status code 11
|
||||||
|
// https://pkg.go.dev/gopkg.in/urfave/cli.v2?tab=doc#ExitCoder
|
||||||
|
type statusSuccess struct {
|
||||||
|
newVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *statusSuccess) Error() string {
|
||||||
|
return fmt.Sprintf("cloudflared has been updated to version %s", u.newVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *statusSuccess) ExitCode() int {
|
||||||
|
return 11
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateErr implements ExitCoder interface, the app will exit with status code 10
|
||||||
|
type statusErr struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *statusErr) Error() string {
|
||||||
|
return fmt.Sprintf("failed to update cloudflared: %v", e.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *statusErr) ExitCode() int {
|
||||||
|
return 10
|
||||||
|
}
|
||||||
|
|
||||||
type UpdateOutcome struct {
|
type UpdateOutcome struct {
|
||||||
Updated bool
|
Updated bool
|
||||||
Version string
|
Version string
|
||||||
|
@ -67,14 +95,15 @@ func checkForUpdateAndApply() UpdateOutcome {
|
||||||
func Update(_ *cli.Context) error {
|
func Update(_ *cli.Context) error {
|
||||||
updateOutcome := loggedUpdate()
|
updateOutcome := loggedUpdate()
|
||||||
if updateOutcome.Error != nil {
|
if updateOutcome.Error != nil {
|
||||||
os.Exit(10)
|
return &statusErr{updateOutcome.Error}
|
||||||
}
|
}
|
||||||
|
|
||||||
if updateOutcome.noUpdate() {
|
if updateOutcome.noUpdate() {
|
||||||
logger.Infof("cloudflared is up to date (%s)", updateOutcome.Version)
|
logger.Infof("cloudflared is up to date (%s)", updateOutcome.Version)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateOutcome.Error
|
return &statusSuccess{newVersion: updateOutcome.Version}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for an update and applies it if one is available
|
// Checks for an update and applies it if one is available
|
||||||
|
@ -126,15 +155,19 @@ func (a *AutoUpdater) Run(ctx context.Context) error {
|
||||||
updateOutcome := loggedUpdate()
|
updateOutcome := loggedUpdate()
|
||||||
if updateOutcome.Updated {
|
if updateOutcome.Updated {
|
||||||
os.Args = append(os.Args, "--is-autoupdated=true")
|
os.Args = append(os.Args, "--is-autoupdated=true")
|
||||||
pid, err := a.listeners.StartProcess()
|
if IsSysV() {
|
||||||
if err != nil {
|
// SysV doesn't have a mechanism to keep service alive, we have to restart the process
|
||||||
logger.WithError(err).Error("Unable to restart server automatically")
|
logger.Infof("Restarting service managed by SysV...")
|
||||||
return err
|
pid, err := a.listeners.StartProcess()
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("Unable to restart server automatically")
|
||||||
|
return &statusErr{err: err}
|
||||||
|
}
|
||||||
|
// stop old process after autoupdate. Otherwise we create a new process
|
||||||
|
// after each update
|
||||||
|
logger.Infof("PID of the new process is %d", pid)
|
||||||
}
|
}
|
||||||
// stop old process after autoupdate. Otherwise we create a new process
|
return &statusSuccess{newVersion: updateOutcome.Version}
|
||||||
// after each update
|
|
||||||
logger.Infof("PID of the new process is %d", pid)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
@ -187,3 +220,14 @@ func SupportAutoUpdate() bool {
|
||||||
func isRunningFromTerminal() bool {
|
func isRunningFromTerminal() bool {
|
||||||
return terminal.IsTerminal(int(os.Stdout.Fd()))
|
return terminal.IsTerminal(int(os.Stdout.Fd()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsSysV() bool {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat("/run/systemd/system"); err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module github.com/cloudflare/cloudflared
|
||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/BurntSushi/go-sumtype v0.0.0-20190304192233-fcb4a6205bdc // indirect
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3
|
github.com/DATA-DOG/go-sqlmock v1.3.3
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.25.8
|
github.com/aws/aws-sdk-go v1.25.8
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,6 +1,8 @@
|
||||||
bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4=
|
bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/go-sumtype v0.0.0-20190304192233-fcb4a6205bdc h1:nvTP+jmloR0+J4YQur/rLRdLcGVEU4SquDgH+Bo7gBY=
|
||||||
|
github.com/BurntSushi/go-sumtype v0.0.0-20190304192233-fcb4a6205bdc/go.mod h1:7yTWMMG2vOm4ABVciEt4EgNVP7fxwtcKIb/EuiLiKqY=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
|
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
|
||||||
|
@ -244,9 +246,11 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
|
Loading…
Reference in New Issue