use bin dir as tmp dir for next binary, copy owner

master
Jaime Pillora 2016-02-09 17:01:06 +11:00
parent 0de2aea26b
commit 29e33ed1c7
5 changed files with 50 additions and 31 deletions

View File

@ -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

View File

@ -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,
},
})
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -2,4 +2,4 @@
package overseer
const supported = false
var supported = false