Switch java/exec to use Exec in Executor

This commit is contained in:
Michael Schurter
2017-04-21 16:20:37 -07:00
parent ba1c2e7936
commit 90f5e232a5
6 changed files with 98 additions and 7 deletions

View File

@@ -195,7 +195,6 @@ func (r *AllocRunner) RestoreState() error {
// Restart task runner if RestoreState gave a reason
if restartReason != "" {
r.logger.Printf("[INFO] client: restarting alloc %s task %q due to upgrade: %s", r.alloc.ID, name, restartReason)
tr.Restart("upgrade", restartReason)
}
}

View File

@@ -259,7 +259,12 @@ func (h *execHandle) Update(task *structs.Task) error {
}
func (h *execHandle) Exec(ctx context.Context, cmd string, args []string) ([]byte, int, error) {
return execChroot(ctx, h.taskDir.Dir, cmd, args)
deadline, ok := ctx.Deadline()
if !ok {
// No deadline set on context; default to 1 minute
deadline = time.Now().Add(time.Minute)
}
return h.executor.Exec(deadline, cmd, args)
}
func (h *execHandle) Signal(s os.Signal) error {

View File

@@ -1,6 +1,7 @@
package executor
import (
"context"
"fmt"
"io/ioutil"
"log"
@@ -15,6 +16,7 @@ import (
"syscall"
"time"
"github.com/armon/circbuf"
"github.com/hashicorp/go-multierror"
"github.com/mitchellh/go-ps"
"github.com/shirou/gopsutil/process"
@@ -57,6 +59,7 @@ type Executor interface {
Version() (*ExecutorVersion, error)
Stats() (*cstructs.TaskResourceUsage, error)
Signal(s os.Signal) error
Exec(deadline time.Time, cmd string, args []string) ([]byte, int, error)
}
// ExecutorContext holds context to configure the command user
@@ -203,8 +206,8 @@ func (e *UniversalExecutor) SetContext(ctx *ExecutorContext) error {
return nil
}
// LaunchCmd launches a process and returns it's state. It also configures an
// applies isolation on certain platforms.
// LaunchCmd launches the main process and returns its state. It also
// configures an applies isolation on certain platforms.
func (e *UniversalExecutor) LaunchCmd(command *ExecCommand) (*ProcessState, error) {
e.logger.Printf("[DEBUG] executor: launching command %v %v", command.Cmd, strings.Join(command.Args, " "))
@@ -283,6 +286,45 @@ func (e *UniversalExecutor) LaunchCmd(command *ExecCommand) (*ProcessState, erro
return &ProcessState{Pid: e.cmd.Process.Pid, ExitCode: -1, IsolationConfig: ic, Time: time.Now()}, nil
}
// Exec a command inside a container for exec and java drivers.
func (e *UniversalExecutor) Exec(deadline time.Time, name string, args []string) ([]byte, int, error) {
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()
name = e.ctx.TaskEnv.ReplaceEnv(name)
cmd := exec.CommandContext(ctx, name, e.ctx.TaskEnv.ParseAndReplace(args)...)
// Copy runtime environment from the main command
cmd.SysProcAttr = e.cmd.SysProcAttr
cmd.Dir = e.cmd.Dir
cmd.Env = e.ctx.TaskEnv.EnvList()
// Capture output
buf, _ := circbuf.NewBuffer(int64(dstructs.CheckBufSize))
cmd.Stdout = buf
cmd.Stderr = buf
if err := cmd.Run(); err != nil {
exitErr, ok := err.(*exec.ExitError)
if !ok {
// Non-exit error, return it and let the caller treat
// it as a critical failure
return nil, 0, err
}
// Some kind of error happened; default to critical
exitCode := 2
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
exitCode = status.ExitStatus()
}
// Don't return the exitError as the caller only needs the
// output and code.
return buf.Bytes(), exitCode, nil
}
return buf.Bytes(), 0, nil
}
// configureLoggers sets up the standard out/error file rotators
func (e *UniversalExecutor) configureLoggers() error {
e.rotatorLock.Lock()

View File

@@ -6,6 +6,7 @@ import (
"net/rpc"
"os"
"syscall"
"time"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/nomad/client/driver/executor"
@@ -33,6 +34,17 @@ type LaunchCmdArgs struct {
Cmd *executor.ExecCommand
}
type ExecCmdArgs struct {
Deadline time.Time
Name string
Args []string
}
type ExecCmdReturn struct {
Output []byte
Code int
}
func (e *ExecutorRPC) LaunchCmd(cmd *executor.ExecCommand) (*executor.ProcessState, error) {
var ps *executor.ProcessState
err := e.client.Call("Plugin.LaunchCmd", LaunchCmdArgs{Cmd: cmd}, &ps)
@@ -91,6 +103,20 @@ func (e *ExecutorRPC) Signal(s os.Signal) error {
return e.client.Call("Plugin.Signal", &s, new(interface{}))
}
func (e *ExecutorRPC) Exec(deadline time.Time, name string, args []string) ([]byte, int, error) {
req := ExecCmdArgs{
Deadline: deadline,
Name: name,
Args: args,
}
var resp *ExecCmdReturn
err := e.client.Call("Plugin.Exec", req, &resp)
if resp == nil {
return nil, 0, err
}
return resp.Output, resp.Code, err
}
type ExecutorRPCServer struct {
Impl executor.Executor
logger *log.Logger
@@ -165,6 +191,16 @@ func (e *ExecutorRPCServer) Signal(args os.Signal, resp *interface{}) error {
return e.Impl.Signal(args)
}
func (e *ExecutorRPCServer) Exec(args ExecCmdArgs, result *ExecCmdReturn) error {
out, code, err := e.Impl.Exec(args.Deadline, args.Name, args.Args)
ret := &ExecCmdReturn{
Output: out,
Code: code,
}
*result = *ret
return err
}
type ExecutorPlugin struct {
logger *log.Logger
Impl *ExecutorRPCServer

View File

@@ -390,7 +390,12 @@ func (h *javaHandle) Update(task *structs.Task) error {
}
func (h *javaHandle) Exec(ctx context.Context, cmd string, args []string) ([]byte, int, error) {
return execChroot(ctx, h.taskDir, cmd, args)
deadline, ok := ctx.Deadline()
if !ok {
// No deadline set on context; default to 1 minute
deadline = time.Now().Add(time.Minute)
}
return h.executor.Exec(deadline, cmd, args)
}
func (h *javaHandle) Signal(s os.Signal) error {

View File

@@ -297,7 +297,7 @@ func (r *TaskRunner) RestoreState() (string, error) {
return "", nil
}
if pre06ScriptCheck(snap.Version, r.task.Services) {
if pre06ScriptCheck(snap.Version, r.task.Driver, r.task.Services) {
restartReason = "upgrading pre-0.6 script checks"
}
@@ -323,7 +323,11 @@ func (r *TaskRunner) RestoreState() (string, error) {
var ver06 = version.Must(version.NewVersion("0.6.0dev"))
// pre06ScriptCheck returns true if version is prior to 0.6.0dev.
func pre06ScriptCheck(ver string, services []*structs.Service) bool {
func pre06ScriptCheck(ver, driver string, services []*structs.Service) bool {
if driver != "exec" && driver != "java" {
// Only exec and java are affected
return false
}
v, err := version.NewVersion(ver)
if err != nil {
// Treat it as old