Skip to content

Commit

Permalink
Merge branch 'release/0.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
nbari committed Aug 5, 2016
2 parents aa4e49d + 0c7b2c5 commit c1f7c84
Show file tree
Hide file tree
Showing 32 changed files with 1,508 additions and 623 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -8,6 +8,7 @@ before_install:
- go get gopkg.in/yaml.v2
- go get github.com/immortal/logrotate
- go get github.com/immortal/multiwriter
- go get github.com/immortal/natcasesort
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
Expand Down
7 changes: 3 additions & 4 deletions Makefile
@@ -1,12 +1,11 @@
.PHONY: all get test clean build cover compile goxc bintray

VERSION=0.3.0
GO ?= go
BIN_NAME=immortal
GO_XC = ${GOPATH}/bin/goxc -os="freebsd netbsd openbsd darwin linux"
GOXC_FILE = .goxc.json
GOXC_FILE_LOCAL = .goxc.local.json
GITHASH=$(shell git rev-parse HEAD)
VERSION=$(shell git describe --tags --always)

all: clean build

Expand All @@ -15,7 +14,7 @@ get:

build: get
# ${GO} get -u gopkg.in/yaml.v2;
${GO} build -ldflags "-X main.version=${VERSION} -X main.githash=${GITHASH}" -o ${BIN_NAME} cmd/immortal/main.go;
${GO} build -ldflags "-X main.version=${VERSION}" -o ${BIN_NAME} cmd/immortal/main.go;

clean:
@rm -rf ir-* ${BIN_NAME} ${BIN_NAME}.debug *.out build debian
Expand Down Expand Up @@ -43,7 +42,7 @@ goxc:
$(shell echo ' "subject": "nbari"' >> $(GOXC_FILE))
$(shell echo ' }\n },' >> $(GOXC_FILE))
$(shell echo ' "BuildSettings": {' >> $(GOXC_FILE))
$(shell echo ' "LdFlags": "-X main.version=${VERSION} -X main.githash=${GITHASH}"' >> $(GOXC_FILE))
$(shell echo ' "LdFlags": "-X main.version=${VERSION}"' >> $(GOXC_FILE))
$(shell echo ' }\n}' >> $(GOXC_FILE))
$(shell echo '{\n "ConfigVersion": "0.9",' > $(GOXC_FILE_LOCAL))
$(shell echo ' "TaskSettings": {' >> $(GOXC_FILE_LOCAL))
Expand Down
13 changes: 13 additions & 0 deletions a_test.go
@@ -0,0 +1,13 @@
package immortal

import (
"reflect"
"testing"
)

/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected: %v (type %v) Got: %v (type %v)", a, reflect.TypeOf(a), b, reflect.TypeOf(b))
}
}
124 changes: 27 additions & 97 deletions cmd/immortal/main.go
Expand Up @@ -3,138 +3,68 @@ package main
import (
"flag"
"fmt"
ir "github.com/immortal/immortal"
"github.com/immortal/immortal"
"log"
"log/syslog"
"os"
"os/user"
)

var version, githash string

func exists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
}
return true
}

func is_exec(path string) (bool, error) {
if f, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
return false, nil
} else {
return false, err
}
} else if m := f.Mode(); !m.IsDir() && m&0111 != 0 {
return true, nil
} else {
return false, nil
}
}
var version string

func main() {
var (
c = flag.String("c", "", "`run.yml` configuration file")
d = flag.String("d", "", "Change to `dir` before starting the command")
f = flag.String("f", "", "Follow PID in `pidfile`")
l = flag.String("l", "", "Write stdout/stderr to `logfile`")
logger = flag.String("logger", "", "A `command` to pipe stdout/stderr to stdin")
p = flag.String("p", "", "Path to write the child `pidfile`")
P = flag.String("P", "", "Path to write the supervisor `pidfile`")
u = flag.String("u", "", "Execute command on behalf `user`")
ctrl = flag.Bool("ctrl", false, "Create supervise directory")
v = flag.Bool("v", false, fmt.Sprintf("Print version: %s", version))
err error
pid int
usr *user.User
D *ir.Daemon
)

flag.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s [-v -ctrl] [-f pidfile] [-l logfile] [-logger logger] [-p child_pidfile] [-P supervisor_pidfile] [-u user] command\n\n", os.Args[0])
fmt.Printf(" command\n The command with arguments if any, to supervise.\n\n")
flag.PrintDefaults()
parser := &immortal.Parse{
UserLookup: user.Lookup,
}

flag.Parse()

// if v print version
if *v {
if githash != "" {
fmt.Printf("%s+%s\n", version, githash)
} else {
fmt.Printf("%s\n", version)
}
os.Exit(0)
}
// flag set
fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
fs.Usage = parser.Usage(fs)

// if no args exit
if len(flag.Args()) < 1 {
fmt.Fprintf(os.Stderr, "Missing command, use (\"%s -h\") for help.\n", os.Args[0])
cfg, err := immortal.ParseArgs(parser, fs)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}

if *c != "" {
if !exists(*c) {
fmt.Printf("Cannot read file: %s, use -h for more info.\n", *c)
os.Exit(1)
}
}

if *d != "" {
if !exists(*d) {
fmt.Printf("-d %s does not exist or has wrong permissions.\n", *d)
os.Exit(1)
}
}

if *u != "" {
usr, err = user.Lookup(*u)
if err != nil {
if _, ok := err.(user.UnknownUserError); ok {
fmt.Printf("User %s does not exist.\n", *u)
} else if err != nil {
fmt.Printf("Error looking up user: %s\n", *u)
}
os.Exit(1)
}
// if -v print version
if (fs.Lookup("v")).Value.(flag.Getter).Get().(bool) {
fmt.Printf("%s\n", version)
os.Exit(0)
}

// log
logwriter, err := syslog.New(syslog.LOG_NOTICE|syslog.LOG_DAEMON, "immortal")
// log to syslog
logger, err := syslog.New(syslog.LOG_NOTICE|syslog.LOG_DAEMON, "immortal")
if err == nil {
log.SetOutput(logwriter)
log.SetOutput(logger)
log.SetFlags(0)
} else {
defer logwriter.Close()
defer logger.Close()
}

// start Daemon
D, err = ir.New(usr, c, d, f, l, logger, p, P, flag.Args(), ctrl)
// create daemon
daemon, err := immortal.New(cfg)
if err != nil {
fmt.Println(err)
fmt.Fprintln(os.Stderr, err)
log.Print(err)
os.Exit(1)
}

// fork
if os.Getppid() > 1 {
if pid, err = ir.Fork(); err != nil {
if pid, err := daemon.Fork(); err != nil {
log.Printf("Error while forking: %s", err)
os.Exit(1)
} else {
if pid > 0 {
fmt.Printf("%c %d\n", ir.Logo(), pid)
fmt.Printf("%c %d\n", immortal.Logo(), pid)
os.Exit(0)
}
}
}

log.Printf("%c %d", ir.Logo(), os.Getpid())
log.Printf("%c %d", immortal.Logo(), os.Getpid())

D.Logger()
if *ctrl {
D.Control()
}
D.Supervice()
daemon.Run()
immortal.Supervise(&immortal.Sup{}, daemon)
}
131 changes: 20 additions & 111 deletions config.go
@@ -1,124 +1,33 @@
package immortal

import (
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
"os"
"os/user"
"path/filepath"
"sync"
)

type Daemon struct {
sync.Mutex
type Config struct {
Cmd string `yaml:"cmd" json:"cmd"`
Cwd string `yaml:",omitempty" json:",omitempty"`
Env map[string]string `yaml:",omitempty" json:",omitempty"`
Log `yaml:",omitempty" json:",omitempty"`
Logger string `yaml:",omitempty" json:",omitempty"`
Pid `yaml:",omitempty" json:",omitempty"`
User string `yaml:",omitempty" json:",omitempty"`
Wait int `yaml:",omitempty"`
command []string
count uint32
ctrl Ctrl
ctrl bool
log bool
logger *log.Logger
owner *user.User
pid int
run Run
user *user.User
}

type Run struct {
Command string
Ctrl bool
Cwd string
Env map[string]string
Logfile string
Logger string
Signals map[string]string
User string
ParentPid string
ChildPid string
FollowPid string
type Pid struct {
Follow string `yaml:",omitempty"`
Parent string `yaml:",omitempty"`
Child string `yaml:",omitempty"`
}

type Ctrl struct {
fifo chan Return
quit chan struct{}
state chan error
control_fifo *os.File
status_fifo *os.File
}

type Return struct {
err error
msg string
}

// New return a instances of Daemon
// u - usr
// c - config
// d - working dir
// f - follow pid
// l - log file
// logger - command to pipe stdout/stderr
// P - parent pidfile
// p - child pidfile
// cmd - command to supervice
// ctrl - create supervise dir
func New(u *user.User, c, d, f, l, logger, p, P *string, cmd []string, ctrl *bool) (*Daemon, error) {
if *c != "" {
yml_file, err := ioutil.ReadFile(*c)
if err != nil {
return nil, err
}

var D Daemon

if err := yaml.Unmarshal(yml_file, &D); err != nil {
return nil, err
}

return &D, nil
}

daemon := &Daemon{
owner: u,
command: cmd,
run: Run{
Cwd: *d,
FollowPid: *f,
Logfile: *l,
Logger: *logger,
ParentPid: *P,
ChildPid: *p,
Ctrl: *ctrl,
},
ctrl: Ctrl{
fifo: make(chan Return),
quit: make(chan struct{}),
state: make(chan error),
},
}

if *ctrl {
wd, err := os.Getwd()
if err != nil {
return nil, err
}
wd = filepath.Join(wd, "supervise")
if err := os.MkdirAll(wd, 0700); err != nil {
return nil, err
}
// create control pipe
daemon.ctrl.control_fifo, err = MakeFIFO(filepath.Join(wd, "control"))
if err != nil {
return nil, err
}
// create status pipe
daemon.ctrl.status_fifo, err = MakeFIFO(filepath.Join(wd, "status"))
if err != nil {
return nil, err
}
// create lock
if err = Lock(filepath.Join(wd, "lock")); err != nil {
return nil, err
}
}

return daemon, nil
type Log struct {
File string `yaml:",omitempty"`
Age int `yaml:",omitempty"`
Num int `yaml:",omitempty"`
Size int `yaml:",omitempty"`
}

0 comments on commit c1f7c84

Please sign in to comment.