mirror of
https://github.com/kemko/nomad.git
synced 2026-01-05 09:55:44 +03:00
Refactor spawn-daemon so it can be used by all OSes and make it write exit code to a file
This commit is contained in:
@@ -1,115 +1,16 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
import "syscall"
|
||||
|
||||
// Configuration for the command to start as a daemon.
|
||||
type DaemonConfig struct {
|
||||
exec.Cmd
|
||||
// configureChroot enters the user command into a chroot if specified in the
|
||||
// config and on an OS that supports Chroots.
|
||||
func (c *SpawnDaemonCommand) configureChroot() {
|
||||
if len(c.config.Chroot) != 0 {
|
||||
if c.config.Cmd.SysProcAttr == nil {
|
||||
c.config.Cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
|
||||
// The paths, if not /dev/null, must be either in the tasks root directory
|
||||
// or in the shared alloc directory.
|
||||
StdoutFile string
|
||||
StdinFile string
|
||||
StderrFile string
|
||||
|
||||
Chroot string
|
||||
}
|
||||
|
||||
// Whether to start the user command or abort.
|
||||
type TaskStart bool
|
||||
|
||||
func (c *SpawnDaemonCommand) Run(args []string) int {
|
||||
flags := c.Meta.FlagSet("spawn-daemon", FlagSetClient)
|
||||
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Check that we got json input.
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
c.Ui.Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
jsonInput, err := strconv.Unquote(args[0])
|
||||
if err != nil {
|
||||
return c.outputStartStatus(fmt.Errorf("Failed to unquote json input: %v", err), 1)
|
||||
}
|
||||
|
||||
// De-serialize the passed command.
|
||||
var cmd DaemonConfig
|
||||
dec := json.NewDecoder(strings.NewReader(jsonInput))
|
||||
if err := dec.Decode(&cmd); err != nil {
|
||||
return c.outputStartStatus(err, 1)
|
||||
}
|
||||
|
||||
// Isolate the user process.
|
||||
if _, err := syscall.Setsid(); err != nil {
|
||||
return c.outputStartStatus(fmt.Errorf("Failed setting sid: %v", err), 1)
|
||||
}
|
||||
|
||||
syscall.Umask(0)
|
||||
|
||||
// Redirect logs.
|
||||
stdo, err := os.OpenFile(cmd.StdoutFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
return c.outputStartStatus(fmt.Errorf("Error opening file to redirect Stdout: %v", err), 1)
|
||||
}
|
||||
|
||||
stde, err := os.OpenFile(cmd.StderrFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
return c.outputStartStatus(fmt.Errorf("Error opening file to redirect Stderr: %v", err), 1)
|
||||
}
|
||||
|
||||
stdi, err := os.OpenFile(cmd.StdinFile, os.O_CREATE|os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return c.outputStartStatus(fmt.Errorf("Error opening file to redirect Stdin: %v", err), 1)
|
||||
}
|
||||
|
||||
cmd.Cmd.Stdout = stdo
|
||||
cmd.Cmd.Stderr = stde
|
||||
cmd.Cmd.Stdin = stdi
|
||||
|
||||
// Chroot jail the process and set its working directory.
|
||||
if cmd.Cmd.SysProcAttr == nil {
|
||||
cmd.Cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
|
||||
cmd.Cmd.SysProcAttr.Chroot = cmd.Chroot
|
||||
cmd.Cmd.Dir = "/"
|
||||
|
||||
// Wait to get the start command.
|
||||
var start TaskStart
|
||||
dec = json.NewDecoder(os.Stdin)
|
||||
if err := dec.Decode(&start); err != nil {
|
||||
return c.outputStartStatus(err, 1)
|
||||
}
|
||||
|
||||
if !start {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Spawn the user process.
|
||||
if err := cmd.Cmd.Start(); err != nil {
|
||||
return c.outputStartStatus(fmt.Errorf("Error starting user command: %v", err), 1)
|
||||
}
|
||||
|
||||
// Indicate that the command was started successfully.
|
||||
c.outputStartStatus(nil, 0)
|
||||
|
||||
// Wait and then output the exit status.
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
c.config.Cmd.SysProcAttr.Chroot = c.config.Chroot
|
||||
c.config.Cmd.Dir = "/"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user