From 29e33ed1c7900978ff21b445adb1c2b91c5e5d40 Mon Sep 17 00:00:00 2001 From: Jaime Pillora Date: Tue, 9 Feb 2016 17:01:06 +1100 Subject: [PATCH] use bin dir as tmp dir for next binary, copy owner --- README.md | 8 ++++---- example/main.go | 9 ++++---- proc_master.go | 51 ++++++++++++++++++++++++++++++---------------- sys_posix.go | 11 +++++----- sys_unsupported.go | 2 +- 5 files changed, 50 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index a693a35..0cff83d 100644 --- a/README.md +++ b/README.md @@ -110,12 +110,12 @@ app#3 (286848c2aefcd3f7321a65b5e4efae987fb17911) exiting... 1. Then run it with: ```sh - #run app inside alpine linux (5MB linux distro) - docker run -d -v /path/on/docker/host/myapp/:/home/ -w /home/ alpine -w /home/app + docker run -d -v /path/on/docker/host/myapp/:/home/ -w /home/ debian -w /home/app ``` 1. For testing, swap out `-d` (daemonize) for `--rm -it` (remove on exit, input, terminal) 1. `app` can use the current working directory as storage +1. `debian` doesn't ship with TLS certs, you can mount them in with `-v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt` ### Alternatives @@ -124,8 +124,8 @@ app#3 (286848c2aefcd3f7321a65b5e4efae987fb17911) exiting... ### TODO -* Github fetcher (given a repo) -* S3 fetcher (given a bucket and credentials) +* Log levels +* Github fetcher (given a repo, poll releases) * etcd fetcher (given a cluster, watch key) * `overseer` CLI tool ([TODO](cmd/overseer/TODO.md)) * `overseer` package diff --git a/example/main.go b/example/main.go index ceadc49..9c81532 100644 --- a/example/main.go +++ b/example/main.go @@ -6,6 +6,7 @@ import ( "time" "github.com/jpillora/overseer" + "github.com/jpillora/overseer/fetcher" ) //see example.sh for the use-case @@ -32,9 +33,9 @@ func main() { Log: true, //display log of overseer actions Program: prog, Address: ":5001", - // Fetcher: &fetcher.HTTP{ - // URL: "http://localhost:5002/myappnew", - // Interval: 1 * time.Second, - // }, + Fetcher: &fetcher.HTTP{ + URL: "http://localhost:5002/myappnew", + Interval: 1 * time.Second, + }, }) } diff --git a/proc_master.go b/proc_master.go index 47f26dd..3b2f02e 100644 --- a/proc_master.go +++ b/proc_master.go @@ -21,14 +21,14 @@ import ( "github.com/kardianos/osext" ) -var tmpBinPath = filepath.Join(os.TempDir(), "overseer") +var tmpBinPath = filepath.Join(os.TempDir(), "overseer-"+token()) //a overseer master process type master struct { Config slaveCmd *exec.Cmd slaveExtraFiles []*os.File - binPath string + binPath, tmpBinPath string binPerms os.FileMode binHash []byte restartMux sync.Mutex @@ -90,12 +90,11 @@ func (mp *master) checkBinary() error { io.Copy(hash, f) mp.binHash = hash.Sum(nil) f.Close() - //tmp path - tmpPath := mp.binPath + ".tmp" - if err := os.Rename(mp.binPath, tmpPath); err != nil { + //test bin<->tmpbin moves + if err := os.Rename(mp.binPath, tmpBinPath); err != nil { return fmt.Errorf("cannot move binary (%s)", err) } - if err := os.Rename(tmpPath, mp.binPath); err != nil { + if err := os.Rename(tmpBinPath, mp.binPath); err != nil { return fmt.Errorf("cannot move binary back (%s)", err) } return nil @@ -195,6 +194,7 @@ func (mp *master) fetch() { if mp.restarting { return //skip if restarting } + mp.logf("checking for updates...") reader, err := mp.Fetcher.Fetch() if err != nil { @@ -205,19 +205,20 @@ func (mp *master) fetch() { mp.logf("no updates") return //fetcher has explicitly said there are no updates } + mp.logf("streaming update...") //optional closer if closer, ok := reader.(io.Closer); ok { defer closer.Close() } - tmpBin, err := os.Create(tmpBinPath) + tmpBin, err := os.OpenFile(tmpBinPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { mp.logf("failed to open temp binary: %s", err) return } - defer func() { - tmpBin.Close() - os.Remove(tmpBinPath) - }() + // defer func() { + // tmpBin.Close() + // os.Remove(tmpBinPath) + // }() //tee off to sha1 hash := sha1.New() reader = io.TeeReader(reader, hash) @@ -235,20 +236,30 @@ func (mp *master) fetch() { } //copy permissions if err := tmpBin.Chmod(mp.binPerms); err != nil { - mp.logf("failed to make binary executable: %s", err) + mp.logf("failed to make temp binary executable: %s", err) + return + } + if err := tmpBin.Chown(uid, gid); err != nil { + mp.logf("failed to change owner of binary: %s", err) + return + } + if _, err := tmpBin.Stat(); err != nil { + mp.logf("failed to stat temp binary: %s", err) return } tmpBin.Close() + if _, err := os.Stat(tmpBinPath); err != nil { + mp.logf("failed to stat temp binary by path: %s", err) + return + } if mp.Config.PreUpgrade != nil { if err := mp.Config.PreUpgrade(tmpBinPath); err != nil { mp.logf("user cancelled upgrade: %s", err) return } } - //overseer sanity check, dont replace our good binary with a text file - buff := make([]byte, 8) - rand.Read(buff) - tokenIn := hex.EncodeToString(buff) + //overseer sanity check, dont replace our good binary with a non-executable file + tokenIn := token() cmd := exec.Command(tmpBinPath) cmd.Env = []string{envBinCheck + "=" + tokenIn} tokenOut, err := cmd.Output() @@ -261,7 +272,7 @@ func (mp *master) fetch() { return } //overwrite! - if err := move(mp.binPath, tmpBinPath); err != nil { + if err := os.Rename(tmpBinPath, mp.binPath); err != nil { mp.logf("failed to overwrite binary: %s", err) return } @@ -372,3 +383,9 @@ func (mp *master) logf(f string, args ...interface{}) { log.Printf("[overseer master] "+f, args...) } } + +func token() string { + buff := make([]byte, 8) + rand.Read(buff) + return hex.EncodeToString(buff) +} diff --git a/sys_posix.go b/sys_posix.go index 4fc52a4..54c3f70 100644 --- a/sys_posix.go +++ b/sys_posix.go @@ -11,12 +11,13 @@ import ( "syscall" ) -const supported = true - var ( - SIGUSR1 = syscall.SIGUSR1 - SIGUSR2 = syscall.SIGUSR2 - SIGTERM = syscall.SIGTERM + supported = true + uid = syscall.Getuid() + gid = syscall.Getgid() + SIGUSR1 = syscall.SIGUSR1 + SIGUSR2 = syscall.SIGUSR2 + SIGTERM = syscall.SIGTERM ) func move(dst, src string) error { diff --git a/sys_unsupported.go b/sys_unsupported.go index 9226fdc..3885a9d 100644 --- a/sys_unsupported.go +++ b/sys_unsupported.go @@ -2,4 +2,4 @@ package overseer -const supported = false +var supported = false