Revert "Make drivers take arguments as a list and not as a string"
This commit is contained in:
parent
e22d7e2a27
commit
0e51375285
|
@ -65,7 +65,7 @@ func TestAllocRunner_Destroy(t *testing.T) {
|
||||||
// Ensure task takes some time
|
// Ensure task takes some time
|
||||||
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
|
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
|
||||||
task.Config["command"] = "/bin/sleep"
|
task.Config["command"] = "/bin/sleep"
|
||||||
task.Config["args"] = []string{"10"}
|
task.Config["args"] = "10"
|
||||||
go ar.Run()
|
go ar.Run()
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ func TestAllocRunner_Update(t *testing.T) {
|
||||||
// Ensure task takes some time
|
// Ensure task takes some time
|
||||||
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
|
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
|
||||||
task.Config["command"] = "/bin/sleep"
|
task.Config["command"] = "/bin/sleep"
|
||||||
task.Config["args"] = []string{"10"}
|
task.Config["args"] = "10"
|
||||||
go ar.Run()
|
go ar.Run()
|
||||||
defer ar.Destroy()
|
defer ar.Destroy()
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
@ -130,7 +130,7 @@ func TestAllocRunner_SaveRestoreState(t *testing.T) {
|
||||||
// Ensure task takes some time
|
// Ensure task takes some time
|
||||||
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
|
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
|
||||||
task.Config["command"] = "/bin/sleep"
|
task.Config["command"] = "/bin/sleep"
|
||||||
task.Config["args"] = []string{"10"}
|
task.Config["args"] = "10"
|
||||||
go ar.Run()
|
go ar.Run()
|
||||||
defer ar.Destroy()
|
defer ar.Destroy()
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,7 @@ func TestClient_SaveRestoreState(t *testing.T) {
|
||||||
alloc1.NodeID = c1.Node().ID
|
alloc1.NodeID = c1.Node().ID
|
||||||
task := alloc1.Job.TaskGroups[0].Tasks[0]
|
task := alloc1.Job.TaskGroups[0].Tasks[0]
|
||||||
task.Config["command"] = "/bin/sleep"
|
task.Config["command"] = "/bin/sleep"
|
||||||
task.Config["args"] = []string{"10"}
|
task.Config["args"] = "10"
|
||||||
|
|
||||||
state := s1.State()
|
state := s1.State()
|
||||||
err := state.UpsertAllocs(100,
|
err := state.UpsertAllocs(100,
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
package args
|
package args
|
||||||
|
|
||||||
import "regexp"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/mattn/go-shellwords"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`)
|
envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`)
|
||||||
|
@ -8,17 +13,27 @@ var (
|
||||||
|
|
||||||
// ParseAndReplace takes the user supplied args and a map of environment
|
// ParseAndReplace takes the user supplied args and a map of environment
|
||||||
// variables. It replaces any instance of an environment variable in the args
|
// variables. It replaces any instance of an environment variable in the args
|
||||||
// with the actual value.
|
// with the actual value and does correct splitting of the arg list.
|
||||||
func ParseAndReplace(args []string, env map[string]string) []string {
|
func ParseAndReplace(args string, env map[string]string) ([]string, error) {
|
||||||
replaced := make([]string, len(args))
|
// Set up parser.
|
||||||
for i, arg := range args {
|
p := shellwords.NewParser()
|
||||||
|
p.ParseEnv = false
|
||||||
|
p.ParseBacktick = false
|
||||||
|
|
||||||
|
parsed, err := p.Parse(args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Couldn't parse args %v: %v", args, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
replaced := make([]string, len(parsed))
|
||||||
|
for i, arg := range parsed {
|
||||||
replaced[i] = ReplaceEnv(arg, env)
|
replaced[i] = ReplaceEnv(arg, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
return replaced
|
return replaced, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplaceEnv takes an arg and replaces all occurences of environment variables.
|
// replaceEnv takes an arg and replaces all occurences of environment variables.
|
||||||
// If the variable is found in the passed map it is replaced, otherwise the
|
// If the variable is found in the passed map it is replaced, otherwise the
|
||||||
// original string is returned.
|
// original string is returned.
|
||||||
func ReplaceEnv(arg string, env map[string]string) string {
|
func ReplaceEnv(arg string, env map[string]string) string {
|
||||||
|
|
|
@ -21,9 +21,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDriverArgs_ParseAndReplaceInvalidEnv(t *testing.T) {
|
func TestDriverArgs_ParseAndReplaceInvalidEnv(t *testing.T) {
|
||||||
input := []string{"invalid", "$FOO"}
|
input := "invalid $FOO"
|
||||||
exp := []string{"invalid", "$FOO"}
|
exp := []string{"invalid", "$FOO"}
|
||||||
act := ParseAndReplace(input, envVars)
|
act, err := ParseAndReplace(input, envVars)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse valid input args %v: %v", input, err)
|
||||||
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(act, exp) {
|
if !reflect.DeepEqual(act, exp) {
|
||||||
t.Fatalf("ParseAndReplace(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
|
t.Fatalf("ParseAndReplace(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
|
||||||
|
@ -31,9 +34,12 @@ func TestDriverArgs_ParseAndReplaceInvalidEnv(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDriverArgs_ParseAndReplaceValidEnv(t *testing.T) {
|
func TestDriverArgs_ParseAndReplaceValidEnv(t *testing.T) {
|
||||||
input := []string{"nomad_ip", fmt.Sprintf(`"$%v"!`, ipKey)}
|
input := fmt.Sprintf("nomad_ip \\\"$%v\\\"!", ipKey)
|
||||||
exp := []string{"nomad_ip", fmt.Sprintf("\"%s\"!", ipVal)}
|
exp := []string{"nomad_ip", fmt.Sprintf("\"%s\"!", ipVal)}
|
||||||
act := ParseAndReplace(input, envVars)
|
act, err := ParseAndReplace(input, envVars)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse valid input args %v: %v", input, err)
|
||||||
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(act, exp) {
|
if !reflect.DeepEqual(act, exp) {
|
||||||
t.Fatalf("ParseAndReplace(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
|
t.Fatalf("ParseAndReplace(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
|
||||||
|
@ -41,9 +47,32 @@ func TestDriverArgs_ParseAndReplaceValidEnv(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDriverArgs_ParseAndReplaceChainedEnv(t *testing.T) {
|
func TestDriverArgs_ParseAndReplaceChainedEnv(t *testing.T) {
|
||||||
input := []string{"-foo", fmt.Sprintf("$%s$%s", ipKey, portKey)}
|
input := fmt.Sprintf("-foo $%s$%s", ipKey, portKey)
|
||||||
exp := []string{"-foo", fmt.Sprintf("%s%s", ipVal, portVal)}
|
exp := []string{"-foo", fmt.Sprintf("%s%s", ipVal, portVal)}
|
||||||
act := ParseAndReplace(input, envVars)
|
act, err := ParseAndReplace(input, envVars)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse valid input args %v: %v", input, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(act, exp) {
|
||||||
|
t.Fatalf("ParseAndReplace(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDriverArgs_ParseAndReplaceInvalidArgEscape(t *testing.T) {
|
||||||
|
input := "-c \"echo \"foo\\\" > bar.txt\""
|
||||||
|
if _, err := ParseAndReplace(input, envVars); err == nil {
|
||||||
|
t.Fatalf("ParseAndReplace(%v, %v) should have failed", input, envVars)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDriverArgs_ParseAndReplaceValidArgEscape(t *testing.T) {
|
||||||
|
input := "-c \"echo \\\"foo\\\" > bar.txt\""
|
||||||
|
exp := []string{"-c", "echo \"foo\" > bar.txt"}
|
||||||
|
act, err := ParseAndReplace(input, envVars)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse valid input args %v: %v", input, err)
|
||||||
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(act, exp) {
|
if !reflect.DeepEqual(act, exp) {
|
||||||
t.Fatalf("ParseAndReplace(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
|
t.Fatalf("ParseAndReplace(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
|
||||||
|
|
|
@ -35,7 +35,7 @@ type DockerDriverAuth struct {
|
||||||
type DockerDriverConfig struct {
|
type DockerDriverConfig struct {
|
||||||
ImageName string `mapstructure:"image"` // Container's Image Name
|
ImageName string `mapstructure:"image"` // Container's Image Name
|
||||||
Command string `mapstructure:"command"` // The Command/Entrypoint to run when the container starts up
|
Command string `mapstructure:"command"` // The Command/Entrypoint to run when the container starts up
|
||||||
Args []string `mapstructure:"args"` // The arguments to the Command/Entrypoint
|
Args string `mapstructure:"args"` // The arguments to the Command/Entrypoint
|
||||||
NetworkMode string `mapstructure:"network_mode"` // The network mode of the container - host, net and none
|
NetworkMode string `mapstructure:"network_mode"` // The network mode of the container - host, net and none
|
||||||
PortMap []map[string]int `mapstructure:"port_map"` // A map of host port labels and the ports exposed on the container
|
PortMap []map[string]int `mapstructure:"port_map"` // A map of host port labels and the ports exposed on the container
|
||||||
Privileged bool `mapstructure:"privileged"` // Flag to run the container in priviledged mode
|
Privileged bool `mapstructure:"privileged"` // Flag to run the container in priviledged mode
|
||||||
|
@ -293,18 +293,21 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, dri
|
||||||
config.ExposedPorts = exposedPorts
|
config.ExposedPorts = exposedPorts
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedArgs := args.ParseAndReplace(driverConfig.Args, env.Map())
|
parsedArgs, err := args.ParseAndReplace(driverConfig.Args, env.Map())
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
// If the user specified a custom command to run as their entrypoint, we'll
|
// If the user specified a custom command to run as their entrypoint, we'll
|
||||||
// inject it here.
|
// inject it here.
|
||||||
if driverConfig.Command != "" {
|
if driverConfig.Command != "" {
|
||||||
cmd := []string{driverConfig.Command}
|
cmd := []string{driverConfig.Command}
|
||||||
if len(driverConfig.Args) != 0 {
|
if driverConfig.Args != "" {
|
||||||
cmd = append(cmd, parsedArgs...)
|
cmd = append(cmd, parsedArgs...)
|
||||||
}
|
}
|
||||||
d.logger.Printf("[DEBUG] driver.docker: setting container startup command to: %s", strings.Join(cmd, " "))
|
d.logger.Printf("[DEBUG] driver.docker: setting container startup command to: %s", strings.Join(cmd, " "))
|
||||||
config.Cmd = cmd
|
config.Cmd = cmd
|
||||||
} else if len(driverConfig.Args) != 0 {
|
} else if driverConfig.Args != "" {
|
||||||
d.logger.Println("[DEBUG] driver.docker: ignoring command arguments because command is not specified")
|
d.logger.Println("[DEBUG] driver.docker: ignoring command arguments because command is not specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +431,7 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle
|
||||||
|
|
||||||
if len(containers) != 1 {
|
if len(containers) != 1 {
|
||||||
log.Printf("[ERR] driver.docker: failed to get id for container %s", config.Name)
|
log.Printf("[ERR] driver.docker: failed to get id for container %s", config.Name)
|
||||||
return nil, fmt.Errorf("Failed to get id for container %s", config.Name)
|
return nil, fmt.Errorf("Failed to get id for container %s: %s", config.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] driver.docker: a container with the name %s already exists; will attempt to purge and re-create", config.Name)
|
log.Printf("[INFO] driver.docker: a container with the name %s already exists; will attempt to purge and re-create", config.Name)
|
||||||
|
|
|
@ -137,7 +137,7 @@ func TestDockerDriver_Start_Wait(t *testing.T) {
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"image": "redis",
|
"image": "redis",
|
||||||
"command": "redis-server",
|
"command": "redis-server",
|
||||||
"args": []string{"-v"},
|
"args": "-v",
|
||||||
},
|
},
|
||||||
Resources: &structs.Resources{
|
Resources: &structs.Resources{
|
||||||
MemoryMB: 256,
|
MemoryMB: 256,
|
||||||
|
@ -190,11 +190,7 @@ func TestDockerDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"image": "redis",
|
"image": "redis",
|
||||||
"command": "/bin/bash",
|
"command": "/bin/bash",
|
||||||
"args": []string{
|
"args": fmt.Sprintf(`-c "sleep 1; echo -n %s > $%s/%s"`, string(exp), environment.AllocDir, file),
|
||||||
"-c",
|
|
||||||
fmt.Sprintf(`sleep 1; echo -n %s > $%s/%s`,
|
|
||||||
string(exp), environment.AllocDir, file),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Resources: &structs.Resources{
|
Resources: &structs.Resources{
|
||||||
MemoryMB: 256,
|
MemoryMB: 256,
|
||||||
|
@ -247,7 +243,7 @@ func TestDockerDriver_Start_Kill_Wait(t *testing.T) {
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"image": "redis",
|
"image": "redis",
|
||||||
"command": "/bin/sleep",
|
"command": "/bin/sleep",
|
||||||
"args": []string{"10"},
|
"args": "10",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ type ExecDriverConfig struct {
|
||||||
ArtifactSource string `mapstructure:"artifact_source"`
|
ArtifactSource string `mapstructure:"artifact_source"`
|
||||||
Checksum string `mapstructure:"checksum"`
|
Checksum string `mapstructure:"checksum"`
|
||||||
Command string `mapstructure:"command"`
|
Command string `mapstructure:"command"`
|
||||||
Args []string `mapstructure:"args"`
|
Args string `mapstructure:"args"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// execHandle is returned from Start/Open as a handle to the PID
|
// execHandle is returned from Start/Open as a handle to the PID
|
||||||
|
@ -91,8 +91,14 @@ func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
|
||||||
// Get the environment variables.
|
// Get the environment variables.
|
||||||
envVars := TaskEnvironmentVariables(ctx, task)
|
envVars := TaskEnvironmentVariables(ctx, task)
|
||||||
|
|
||||||
|
// Look for arguments
|
||||||
|
var args []string
|
||||||
|
if driverConfig.Args != "" {
|
||||||
|
args = append(args, driverConfig.Args)
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the command
|
// Setup the command
|
||||||
cmd := executor.Command(command, driverConfig.Args...)
|
cmd := executor.Command(command, args...)
|
||||||
if err := cmd.Limit(task.Resources); err != nil {
|
if err := cmd.Limit(task.Resources); err != nil {
|
||||||
return nil, fmt.Errorf("failed to constrain resources: %s", err)
|
return nil, fmt.Errorf("failed to constrain resources: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func TestExecDriver_StartOpen_Wait(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/sleep",
|
"command": "/bin/sleep",
|
||||||
"args": []string{"5"},
|
"args": "5",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func TestExecDriver_Start_Wait(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/sleep",
|
"command": "/bin/sleep",
|
||||||
"args": []string{"2"},
|
"args": "2",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -161,10 +161,7 @@ func TestExecDriver_Start_Artifact_expanded(t *testing.T) {
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"artifact_source": fmt.Sprintf("https://dl.dropboxusercontent.com/u/47675/jar_thing/%s", file),
|
"artifact_source": fmt.Sprintf("https://dl.dropboxusercontent.com/u/47675/jar_thing/%s", file),
|
||||||
"command": "/bin/bash",
|
"command": "/bin/bash",
|
||||||
"args": []string{
|
"args": fmt.Sprintf("-c '/bin/sleep 1 && %s'", filepath.Join("$NOMAD_TASK_DIR", file)),
|
||||||
"-c",
|
|
||||||
fmt.Sprintf(`/bin/sleep 1 && %s`, filepath.Join("$NOMAD_TASK_DIR", file)),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -207,10 +204,7 @@ func TestExecDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/bash",
|
"command": "/bin/bash",
|
||||||
"args": []string{
|
"args": fmt.Sprintf("-c \"sleep 1; echo -n %s > $%s/%s\"", string(exp), environment.AllocDir, file),
|
||||||
"-c",
|
|
||||||
fmt.Sprintf(`sleep 1; echo -n %s > $%s/%s`, string(exp), environment.AllocDir, file),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -256,7 +250,7 @@ func TestExecDriver_Start_Kill_Wait(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/sleep",
|
"command": "/bin/sleep",
|
||||||
"args": []string{"1"},
|
"args": "1",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ type BasicExecutor struct {
|
||||||
allocDir string
|
allocDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Have raw_exec use this as well.
|
||||||
func NewBasicExecutor() Executor {
|
func NewBasicExecutor() Executor {
|
||||||
return &BasicExecutor{}
|
return &BasicExecutor{}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,12 @@ func (e *BasicExecutor) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
e.cmd.Path = args.ReplaceEnv(e.cmd.Path, envVars.Map())
|
e.cmd.Path = args.ReplaceEnv(e.cmd.Path, envVars.Map())
|
||||||
e.cmd.Args = args.ParseAndReplace(e.cmd.Args, envVars.Map())
|
combined := strings.Join(e.cmd.Args, " ")
|
||||||
|
parsed, err := args.ParseAndReplace(combined, envVars.Map())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.cmd.Args = parsed
|
||||||
|
|
||||||
spawnState := filepath.Join(e.allocDir, fmt.Sprintf("%s_%s", e.taskName, "exit_status"))
|
spawnState := filepath.Join(e.allocDir, fmt.Sprintf("%s_%s", e.taskName, "exit_status"))
|
||||||
e.spawn = spawn.NewSpawner(spawnState)
|
e.spawn = spawn.NewSpawner(spawnState)
|
||||||
|
|
|
@ -167,7 +167,12 @@ func (e *LinuxExecutor) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
e.cmd.Path = args.ReplaceEnv(e.cmd.Path, envVars.Map())
|
e.cmd.Path = args.ReplaceEnv(e.cmd.Path, envVars.Map())
|
||||||
e.cmd.Args = args.ParseAndReplace(e.cmd.Args, envVars.Map())
|
combined := strings.Join(e.cmd.Args, " ")
|
||||||
|
parsed, err := args.ParseAndReplace(combined, envVars.Map())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.cmd.Args = parsed
|
||||||
|
|
||||||
spawnState := filepath.Join(e.allocDir, fmt.Sprintf("%s_%s", e.taskName, "exit_status"))
|
spawnState := filepath.Join(e.allocDir, fmt.Sprintf("%s_%s", e.taskName, "exit_status"))
|
||||||
e.spawn = spawn.NewSpawner(spawnState)
|
e.spawn = spawn.NewSpawner(spawnState)
|
||||||
|
|
|
@ -112,7 +112,7 @@ func Executor_Start_Wait(t *testing.T, command buildExecCommand) {
|
||||||
expected := "hello world"
|
expected := "hello world"
|
||||||
file := filepath.Join(allocdir.TaskLocal, "output.txt")
|
file := filepath.Join(allocdir.TaskLocal, "output.txt")
|
||||||
absFilePath := filepath.Join(taskDir, file)
|
absFilePath := filepath.Join(taskDir, file)
|
||||||
cmd := fmt.Sprintf(`/bin/sleep 1 ; echo -n %v > %v`, expected, file)
|
cmd := fmt.Sprintf(`"%v \"%v\" > %v"`, "/bin/sleep 1 ; echo -n", expected, file)
|
||||||
e := command("/bin/bash", "-c", cmd)
|
e := command("/bin/bash", "-c", cmd)
|
||||||
|
|
||||||
if err := e.Limit(constraint); err != nil {
|
if err := e.Limit(constraint); err != nil {
|
||||||
|
@ -190,7 +190,7 @@ func Executor_Open(t *testing.T, command buildExecCommand, newExecutor func() Ex
|
||||||
expected := "hello world"
|
expected := "hello world"
|
||||||
file := filepath.Join(allocdir.TaskLocal, "output.txt")
|
file := filepath.Join(allocdir.TaskLocal, "output.txt")
|
||||||
absFilePath := filepath.Join(taskDir, file)
|
absFilePath := filepath.Join(taskDir, file)
|
||||||
cmd := fmt.Sprintf(`/bin/sleep 1 ; echo -n %v > %v`, expected, file)
|
cmd := fmt.Sprintf(`"%v \"%v\" > %v"`, "/bin/sleep 1 ; echo -n", expected, file)
|
||||||
e := command("/bin/bash", "-c", cmd)
|
e := command("/bin/bash", "-c", cmd)
|
||||||
|
|
||||||
if err := e.Limit(constraint); err != nil {
|
if err := e.Limit(constraint); err != nil {
|
||||||
|
|
|
@ -28,10 +28,10 @@ type JavaDriver struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type JavaDriverConfig struct {
|
type JavaDriverConfig struct {
|
||||||
JvmOpts []string `mapstructure:"jvm_options"`
|
JvmOpts string `mapstructure:"jvm_options"`
|
||||||
ArtifactSource string `mapstructure:"artifact_source"`
|
ArtifactSource string `mapstructure:"artifact_source"`
|
||||||
Checksum string `mapstructure:"checksum"`
|
Checksum string `mapstructure:"checksum"`
|
||||||
Args []string `mapstructure:"args"`
|
Args string `mapstructure:"args"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// javaHandle is returned from Start/Open as a handle to the PID
|
// javaHandle is returned from Start/Open as a handle to the PID
|
||||||
|
@ -126,15 +126,15 @@ func (d *JavaDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
|
||||||
|
|
||||||
args := []string{}
|
args := []string{}
|
||||||
// Look for jvm options
|
// Look for jvm options
|
||||||
if len(driverConfig.JvmOpts) != 0 {
|
if driverConfig.JvmOpts != "" {
|
||||||
d.logger.Printf("[DEBUG] driver.java: found JVM options: %s", driverConfig.JvmOpts)
|
d.logger.Printf("[DEBUG] driver.java: found JVM options: %s", driverConfig.JvmOpts)
|
||||||
args = append(args, driverConfig.JvmOpts...)
|
args = append(args, driverConfig.JvmOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the argument list.
|
// Build the argument list.
|
||||||
args = append(args, "-jar", filepath.Join(allocdir.TaskLocal, jarName))
|
args = append(args, "-jar", filepath.Join(allocdir.TaskLocal, jarName))
|
||||||
if len(driverConfig.Args) != 0 {
|
if driverConfig.Args != "" {
|
||||||
args = append(args, driverConfig.Args...)
|
args = append(args, driverConfig.Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the command
|
// Setup the command
|
||||||
|
|
|
@ -51,7 +51,7 @@ func TestJavaDriver_StartOpen_Wait(t *testing.T) {
|
||||||
Name: "demo-app",
|
Name: "demo-app",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"artifact_source": "https://dl.dropboxusercontent.com/u/47675/jar_thing/demoapp.jar",
|
"artifact_source": "https://dl.dropboxusercontent.com/u/47675/jar_thing/demoapp.jar",
|
||||||
"jvm_options": []string{"-Xmx64m", "-Xms32m"},
|
"jvm_options": "-Xmx2048m -Xms256m",
|
||||||
"checksum": "sha256:58d6e8130308d32e197c5108edd4f56ddf1417408f743097c2e662df0f0b17c8",
|
"checksum": "sha256:58d6e8130308d32e197c5108edd4f56ddf1417408f743097c2e662df0f0b17c8",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
|
@ -97,6 +97,7 @@ func TestJavaDriver_Start_Wait(t *testing.T) {
|
||||||
Name: "demo-app",
|
Name: "demo-app",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"artifact_source": "https://dl.dropboxusercontent.com/u/47675/jar_thing/demoapp.jar",
|
"artifact_source": "https://dl.dropboxusercontent.com/u/47675/jar_thing/demoapp.jar",
|
||||||
|
"jvm_options": "-Xmx2048m -Xms256m",
|
||||||
"checksum": "sha256:58d6e8130308d32e197c5108edd4f56ddf1417408f743097c2e662df0f0b17c8",
|
"checksum": "sha256:58d6e8130308d32e197c5108edd4f56ddf1417408f743097c2e662df0f0b17c8",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
|
|
|
@ -93,9 +93,15 @@ func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandl
|
||||||
// Get the environment variables.
|
// Get the environment variables.
|
||||||
envVars := TaskEnvironmentVariables(ctx, task)
|
envVars := TaskEnvironmentVariables(ctx, task)
|
||||||
|
|
||||||
|
// Look for arguments
|
||||||
|
var args []string
|
||||||
|
if driverConfig.Args != "" {
|
||||||
|
args = append(args, driverConfig.Args)
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the command
|
// Setup the command
|
||||||
cmd := executor.NewBasicExecutor()
|
cmd := executor.NewBasicExecutor()
|
||||||
executor.SetCommand(cmd, command, driverConfig.Args)
|
executor.SetCommand(cmd, command, args)
|
||||||
if err := cmd.Limit(task.Resources); err != nil {
|
if err := cmd.Limit(task.Resources); err != nil {
|
||||||
return nil, fmt.Errorf("failed to constrain resources: %s", err)
|
return nil, fmt.Errorf("failed to constrain resources: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ func TestRawExecDriver_StartOpen_Wait(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/sleep",
|
"command": "/bin/sleep",
|
||||||
"args": []string{"1"},
|
"args": "1",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -151,10 +151,7 @@ func TestRawExecDriver_Start_Artifact_expanded(t *testing.T) {
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"artifact_source": fmt.Sprintf("https://dl.dropboxusercontent.com/u/47675/jar_thing/%s", file),
|
"artifact_source": fmt.Sprintf("https://dl.dropboxusercontent.com/u/47675/jar_thing/%s", file),
|
||||||
"command": "/bin/bash",
|
"command": "/bin/bash",
|
||||||
"args": []string{
|
"args": fmt.Sprintf("-c '/bin/sleep 1 && %s'", filepath.Join("$NOMAD_TASK_DIR", file)),
|
||||||
"-c",
|
|
||||||
fmt.Sprintf(`'/bin/sleep 1 && %s'`, filepath.Join("$NOMAD_TASK_DIR", file)),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -193,7 +190,7 @@ func TestRawExecDriver_Start_Wait(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/sleep",
|
"command": "/bin/sleep",
|
||||||
"args": []string{"1"},
|
"args": "1",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -235,10 +232,7 @@ func TestRawExecDriver_Start_Wait_AllocDir(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/bash",
|
"command": "/bin/bash",
|
||||||
"args": []string{
|
"args": fmt.Sprintf(`-c "sleep 1; echo -n %s > $%s/%s"`, string(exp), environment.AllocDir, file),
|
||||||
"-c",
|
|
||||||
fmt.Sprintf(`sleep 1; echo -n %s > $%s/%s`, string(exp), environment.AllocDir, file),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
@ -283,7 +277,7 @@ func TestRawExecDriver_Start_Kill_Wait(t *testing.T) {
|
||||||
Name: "sleep",
|
Name: "sleep",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/sleep",
|
"command": "/bin/sleep",
|
||||||
"args": []string{"1"},
|
"args": "1",
|
||||||
},
|
},
|
||||||
Resources: basicResources,
|
Resources: basicResources,
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ type RktDriver struct {
|
||||||
|
|
||||||
type RktDriverConfig struct {
|
type RktDriverConfig struct {
|
||||||
ImageName string `mapstructure:"image"`
|
ImageName string `mapstructure:"image"`
|
||||||
Args []string `mapstructure:"args"`
|
Args string `mapstructure:"args"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// rktHandle is returned from Start/Open as a handle to the PID
|
// rktHandle is returned from Start/Open as a handle to the PID
|
||||||
|
@ -150,8 +150,11 @@ func (d *RktDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user passed arguments.
|
// Add user passed arguments.
|
||||||
if len(driverConfig.Args) != 0 {
|
if driverConfig.Args != "" {
|
||||||
parsed := args.ParseAndReplace(driverConfig.Args, envVars.Map())
|
parsed, err := args.ParseAndReplace(driverConfig.Args, envVars.Map())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Need to start arguments with "--"
|
// Need to start arguments with "--"
|
||||||
if len(parsed) > 0 {
|
if len(parsed) > 0 {
|
||||||
|
|
|
@ -119,7 +119,7 @@ func TestRktDriver_Start_Wait(t *testing.T) {
|
||||||
"trust_prefix": "coreos.com/etcd",
|
"trust_prefix": "coreos.com/etcd",
|
||||||
"image": "coreos.com/etcd:v2.0.4",
|
"image": "coreos.com/etcd:v2.0.4",
|
||||||
"command": "/etcd",
|
"command": "/etcd",
|
||||||
"args": []string{"--version"},
|
"args": "--version",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ func TestRktDriver_Start_Wait_Skip_Trust(t *testing.T) {
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"image": "coreos.com/etcd:v2.0.4",
|
"image": "coreos.com/etcd:v2.0.4",
|
||||||
"command": "/etcd",
|
"command": "/etcd",
|
||||||
"args": []string{"--version"},
|
"args": "--version",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ func TestRktDriver_Start_Wait_Logs(t *testing.T) {
|
||||||
"trust_prefix": "coreos.com/etcd",
|
"trust_prefix": "coreos.com/etcd",
|
||||||
"image": "coreos.com/etcd:v2.0.4",
|
"image": "coreos.com/etcd:v2.0.4",
|
||||||
"command": "/etcd",
|
"command": "/etcd",
|
||||||
"args": []string{"--version"},
|
"args": "--version",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ func TestTaskRunner_Destroy(t *testing.T) {
|
||||||
|
|
||||||
// Change command to ensure we run for a bit
|
// Change command to ensure we run for a bit
|
||||||
tr.task.Config["command"] = "/bin/sleep"
|
tr.task.Config["command"] = "/bin/sleep"
|
||||||
tr.task.Config["args"] = []string{"10"}
|
tr.task.Config["args"] = "10"
|
||||||
go tr.Run()
|
go tr.Run()
|
||||||
|
|
||||||
// Begin the tear down
|
// Begin the tear down
|
||||||
|
@ -128,7 +128,7 @@ func TestTaskRunner_Update(t *testing.T) {
|
||||||
|
|
||||||
// Change command to ensure we run for a bit
|
// Change command to ensure we run for a bit
|
||||||
tr.task.Config["command"] = "/bin/sleep"
|
tr.task.Config["command"] = "/bin/sleep"
|
||||||
tr.task.Config["args"] = []string{"10"}
|
tr.task.Config["args"] = "10"
|
||||||
go tr.Run()
|
go tr.Run()
|
||||||
defer tr.Destroy()
|
defer tr.Destroy()
|
||||||
defer tr.ctx.AllocDir.Destroy()
|
defer tr.ctx.AllocDir.Destroy()
|
||||||
|
@ -153,7 +153,7 @@ func TestTaskRunner_SaveRestoreState(t *testing.T) {
|
||||||
|
|
||||||
// Change command to ensure we run for a bit
|
// Change command to ensure we run for a bit
|
||||||
tr.task.Config["command"] = "/bin/sleep"
|
tr.task.Config["command"] = "/bin/sleep"
|
||||||
tr.task.Config["args"] = []string{"10"}
|
tr.task.Config["args"] = "10"
|
||||||
go tr.Run()
|
go tr.Run()
|
||||||
defer tr.Destroy()
|
defer tr.Destroy()
|
||||||
|
|
||||||
|
|
11
nomad/fsm.go
11
nomad/fsm.go
|
@ -13,6 +13,13 @@ import (
|
||||||
"github.com/hashicorp/raft"
|
"github.com/hashicorp/raft"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
msgpackHandle = &codec.MsgpackHandle{
|
||||||
|
RawToString: true,
|
||||||
|
WriteExt: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// timeTableGranularity is the granularity of index to time tracking
|
// timeTableGranularity is the granularity of index to time tracking
|
||||||
timeTableGranularity = 5 * time.Minute
|
timeTableGranularity = 5 * time.Minute
|
||||||
|
@ -321,7 +328,7 @@ func (n *nomadFSM) Restore(old io.ReadCloser) error {
|
||||||
defer restore.Abort()
|
defer restore.Abort()
|
||||||
|
|
||||||
// Create a decoder
|
// Create a decoder
|
||||||
dec := codec.NewDecoder(old, structs.MsgpackHandle)
|
dec := codec.NewDecoder(old, msgpackHandle)
|
||||||
|
|
||||||
// Read in the header
|
// Read in the header
|
||||||
var header snapshotHeader
|
var header snapshotHeader
|
||||||
|
@ -405,7 +412,7 @@ func (n *nomadFSM) Restore(old io.ReadCloser) error {
|
||||||
func (s *nomadSnapshot) Persist(sink raft.SnapshotSink) error {
|
func (s *nomadSnapshot) Persist(sink raft.SnapshotSink) error {
|
||||||
defer metrics.MeasureSince([]string{"nomad", "fsm", "persist"}, time.Now())
|
defer metrics.MeasureSince([]string{"nomad", "fsm", "persist"}, time.Now())
|
||||||
// Register the nodes
|
// Register the nodes
|
||||||
encoder := codec.NewEncoder(sink, structs.MsgpackHandle)
|
encoder := codec.NewEncoder(sink, msgpackHandle)
|
||||||
|
|
||||||
// Write the header
|
// Write the header
|
||||||
header := snapshotHeader{}
|
header := snapshotHeader{}
|
||||||
|
|
|
@ -86,7 +86,7 @@ func Job() *structs.Job {
|
||||||
Driver: "exec",
|
Driver: "exec",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/date",
|
"command": "/bin/date",
|
||||||
"args": []string{"+%s"},
|
"args": "+%s",
|
||||||
},
|
},
|
||||||
Env: map[string]string{
|
Env: map[string]string{
|
||||||
"FOO": "bar",
|
"FOO": "bar",
|
||||||
|
@ -151,7 +151,7 @@ func SystemJob() *structs.Job {
|
||||||
Driver: "exec",
|
Driver: "exec",
|
||||||
Config: map[string]interface{}{
|
Config: map[string]interface{}{
|
||||||
"command": "/bin/date",
|
"command": "/bin/date",
|
||||||
"args": []string{"+%s"},
|
"args": "+%s",
|
||||||
},
|
},
|
||||||
Resources: &structs.Resources{
|
Resources: &structs.Resources{
|
||||||
CPU: 500,
|
CPU: 500,
|
||||||
|
|
13
nomad/rpc.go
13
nomad/rpc.go
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/armon/go-metrics"
|
"github.com/armon/go-metrics"
|
||||||
|
"github.com/hashicorp/go-msgpack/codec"
|
||||||
"github.com/hashicorp/net-rpc-msgpackrpc"
|
"github.com/hashicorp/net-rpc-msgpackrpc"
|
||||||
"github.com/hashicorp/nomad/nomad/state"
|
"github.com/hashicorp/nomad/nomad/state"
|
||||||
"github.com/hashicorp/nomad/nomad/structs"
|
"github.com/hashicorp/nomad/nomad/structs"
|
||||||
|
@ -52,16 +53,24 @@ const (
|
||||||
enqueueLimit = 30 * time.Second
|
enqueueLimit = 30 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// rpcHandle is the MsgpackHandle to be used by both Client and Server codecs.
|
||||||
|
rpcHandle = &codec.MsgpackHandle{
|
||||||
|
// Enables proper encoding of strings within nil interfaces.
|
||||||
|
RawToString: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// NewClientCodec returns a new rpc.ClientCodec to be used to make RPC calls to
|
// NewClientCodec returns a new rpc.ClientCodec to be used to make RPC calls to
|
||||||
// the Nomad Server.
|
// the Nomad Server.
|
||||||
func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
|
func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
|
||||||
return msgpackrpc.NewCodecFromHandle(true, true, conn, structs.MsgpackHandle)
|
return msgpackrpc.NewCodecFromHandle(true, true, conn, rpcHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServerCodec returns a new rpc.ServerCodec to be used by the Nomad Server
|
// NewServerCodec returns a new rpc.ServerCodec to be used by the Nomad Server
|
||||||
// to handle rpcs.
|
// to handle rpcs.
|
||||||
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
|
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
|
||||||
return msgpackrpc.NewCodecFromHandle(true, true, conn, structs.MsgpackHandle)
|
return msgpackrpc.NewCodecFromHandle(true, true, conn, rpcHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// listen is used to listen for incoming RPC connections
|
// listen is used to listen for incoming RPC connections
|
||||||
|
|
|
@ -1704,26 +1704,25 @@ func (p *PlanResult) FullCommit(plan *Plan) (bool, int, int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// msgpackHandle is a shared handle for encoding/decoding of structs
|
// msgpackHandle is a shared handle for encoding/decoding of structs
|
||||||
var MsgpackHandle = func() *codec.MsgpackHandle {
|
var msgpackHandle = func() *codec.MsgpackHandle {
|
||||||
h := &codec.MsgpackHandle{RawToString: true}
|
h := &codec.MsgpackHandle{RawToString: true}
|
||||||
|
|
||||||
// Sets the default type for decoding a map into a nil interface{}.
|
// Sets the default type for decoding a map into a nil interface{}.
|
||||||
// This is necessary in particular because we store the driver configs as a
|
// This is necessary in particular because we store the driver configs as a
|
||||||
// nil interface{}.
|
// nil interface{}.
|
||||||
h.MapType = reflect.TypeOf(map[string]interface{}(nil))
|
h.MapType = reflect.TypeOf(map[string]interface{}(nil))
|
||||||
h.SliceType = reflect.TypeOf([]string{})
|
|
||||||
return h
|
return h
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Decode is used to decode a MsgPack encoded object
|
// Decode is used to decode a MsgPack encoded object
|
||||||
func Decode(buf []byte, out interface{}) error {
|
func Decode(buf []byte, out interface{}) error {
|
||||||
return codec.NewDecoder(bytes.NewReader(buf), MsgpackHandle).Decode(out)
|
return codec.NewDecoder(bytes.NewReader(buf), msgpackHandle).Decode(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode is used to encode a MsgPack object with type prefix
|
// Encode is used to encode a MsgPack object with type prefix
|
||||||
func Encode(t MessageType, msg interface{}) ([]byte, error) {
|
func Encode(t MessageType, msg interface{}) ([]byte, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteByte(uint8(t))
|
buf.WriteByte(uint8(t))
|
||||||
err := codec.NewEncoder(&buf, MsgpackHandle).Encode(msg)
|
err := codec.NewEncoder(&buf, msgpackHandle).Encode(msg)
|
||||||
return buf.Bytes(), err
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/go-msgpack/codec"
|
"github.com/hashicorp/go-msgpack/codec"
|
||||||
"github.com/hashicorp/nomad/nomad/structs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTimeTable(t *testing.T) {
|
func TestTimeTable(t *testing.T) {
|
||||||
|
@ -105,14 +104,14 @@ func TestTimeTable_SerializeDeserialize(t *testing.T) {
|
||||||
tt.Witness(50, plusHour)
|
tt.Witness(50, plusHour)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
enc := codec.NewEncoder(&buf, structs.MsgpackHandle)
|
enc := codec.NewEncoder(&buf, msgpackHandle)
|
||||||
|
|
||||||
err := tt.Serialize(enc)
|
err := tt.Serialize(enc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dec := codec.NewDecoder(&buf, structs.MsgpackHandle)
|
dec := codec.NewDecoder(&buf, msgpackHandle)
|
||||||
|
|
||||||
tt2 := NewTimeTable(time.Second, time.Minute)
|
tt2 := NewTimeTable(time.Second, time.Minute)
|
||||||
err = tt2.Deserialize(dec)
|
err = tt2.Deserialize(dec)
|
||||||
|
|
|
@ -19,13 +19,13 @@ and cleaning up after containers.
|
||||||
The `docker` driver supports the following configuration in the job
|
The `docker` driver supports the following configuration in the job
|
||||||
specification:
|
specification:
|
||||||
|
|
||||||
* `image` - The Docker image to run. The image may include a tag or
|
* `image` - (Required) The Docker image to run. The image may include a tag or
|
||||||
custom URL. By default it will be fetched from Docker Hub.
|
custom URL. By default it will be fetched from Docker Hub.
|
||||||
|
|
||||||
* `command` - (Optional) The command to run when starting the container.
|
* `command` - (Optional) The command to run when starting the container.
|
||||||
|
|
||||||
* `args` - (Optional) A list of arguments to the optional `command`. If no
|
* `args` - (Optional) Arguments to the optional `command`. If no `command` is
|
||||||
`command` is present, `args` are ignored.
|
present, `args` are ignored.
|
||||||
|
|
||||||
* `network_mode` - (Optional) The network mode to be used for the container. In
|
* `network_mode` - (Optional) The network mode to be used for the container. In
|
||||||
order to support userspace networking plugins in Docker 1.9 this accepts any
|
order to support userspace networking plugins in Docker 1.9 this accepts any
|
||||||
|
|
|
@ -20,19 +20,15 @@ scripts or other wrappers which provide higher level features.
|
||||||
|
|
||||||
The `exec` driver supports the following configuration in the job spec:
|
The `exec` driver supports the following configuration in the job spec:
|
||||||
|
|
||||||
* `command` - The command to execute. Must be provided.
|
* `command` - (Required) The command to execute. Must be provided.
|
||||||
|
* `artifact_source` – (Optional) Source location of an executable artifact. Must be accessible
|
||||||
* `artifact_source` – (Optional) Source location of an executable artifact. Must
|
from the Nomad client. If you specify an `artifact_source` to be executed, you
|
||||||
be accessible from the Nomad client. If you specify an `artifact_source` to be
|
must reference it in the `command` as show in the examples below
|
||||||
executed, you must reference it in the `command` as show in the examples below
|
* `checksum` - **(Optional)** The checksum type and value for the `artifact_source` image.
|
||||||
|
The format is `type:value`, where type is any of `md5`, `sha1`, `sha256`, or `sha512`,
|
||||||
* `checksum` - (Optional) The checksum type and value for the `artifact_source`
|
and the value is the computed checksum. If a checksum is supplied and does not
|
||||||
image. The format is `type:value`, where type is any of `md5`, `sha1`,
|
match the downloaded artifact, the driver will fail to start
|
||||||
`sha256`, or `sha512`, and the value is the computed checksum. If a checksum
|
* `args` - The argument list to the command, space seperated. Optional.
|
||||||
is supplied and does not match the downloaded artifact, the driver will fail
|
|
||||||
to start
|
|
||||||
|
|
||||||
* `args` - (Optional) A list of arguments to the `command`.
|
|
||||||
|
|
||||||
## Client Requirements
|
## Client Requirements
|
||||||
|
|
||||||
|
|
|
@ -18,19 +18,17 @@ HTTP from the Nomad client.
|
||||||
|
|
||||||
The `java` driver supports the following configuration in the job spec:
|
The `java` driver supports the following configuration in the job spec:
|
||||||
|
|
||||||
* `artifact_source` - The hosted location of the source Jar file. Must be
|
* `artifact_source` - **(Required)** The hosted location of the source Jar file. Must be accessible
|
||||||
accessible from the Nomad client
|
from the Nomad client
|
||||||
|
* `checksum` - **(Optional)** The checksum type and value for the `artifact_source` image.
|
||||||
|
The format is `type:value`, where type is any of `md5`, `sha1`, `sha256`, or `sha512`,
|
||||||
|
and the value is the computed checksum. If a checksum is supplied and does not
|
||||||
|
match the downloaded artifact, the driver will fail to start
|
||||||
|
|
||||||
* `checksum` - (Optional) The checksum type and value for the `artifact_source`
|
* `args` - **(Optional)** The argument list for the `java` command, space separated.
|
||||||
image. The format is `type:value`, where type is any of `md5`, `sha1`,
|
|
||||||
`sha256`, or `sha512`, and the value is the computed checksum. If a checksum
|
|
||||||
is supplied and does not match the downloaded artifact, the driver will fail
|
|
||||||
to start
|
|
||||||
|
|
||||||
* `args` - (Optional) A list of arguments to the `java` command.
|
* `jvm_options` - **(Optional)** JVM options to be passed while invoking java. These options
|
||||||
|
are passed not validated in any way in Nomad.
|
||||||
* `jvm_options` - (Optional) A list of JVM options to be passed while invoking
|
|
||||||
java. These options are passed not validated in any way in Nomad.
|
|
||||||
|
|
||||||
## Client Requirements
|
## Client Requirements
|
||||||
|
|
||||||
|
|
|
@ -23,19 +23,16 @@ The `Qemu` driver can execute any regular `qemu` image (e.g. `qcow`, `img`,
|
||||||
|
|
||||||
The `Qemu` driver supports the following configuration in the job spec:
|
The `Qemu` driver supports the following configuration in the job spec:
|
||||||
|
|
||||||
* `artifact_source` - The hosted location of the source Qemu image. Must be accessible
|
* `artifact_source` - **(Required)** The hosted location of the source Qemu image. Must be accessible
|
||||||
from the Nomad client, via HTTP.
|
from the Nomad client, via HTTP.
|
||||||
|
* `checksum` - **(Optional)** The checksum type and value for the `artifact_source` image.
|
||||||
* `checksum` - (Optional) The checksum type and value for the `artifact_source` image.
|
|
||||||
The format is `type:value`, where type is any of `md5`, `sha1`, `sha256`, or `sha512`,
|
The format is `type:value`, where type is any of `md5`, `sha1`, `sha256`, or `sha512`,
|
||||||
and the value is the computed checksum. If a checksum is supplied and does not
|
and the value is the computed checksum. If a checksum is supplied and does not
|
||||||
match the downloaded artifact, the driver will fail to start
|
match the downloaded artifact, the driver will fail to start
|
||||||
|
|
||||||
* `accelerator` - (Optional) The type of accelerator to use in the invocation.
|
* `accelerator` - (Optional) The type of accelerator to use in the invocation.
|
||||||
If the host machine has `Qemu` installed with KVM support, users can specify
|
If the host machine has `Qemu` installed with KVM support, users can specify
|
||||||
`kvm` for the `accelerator`. Default is `tcg`
|
`kvm` for the `accelerator`. Default is `tcg`
|
||||||
|
* `port_map` - **(Optional)** A `map[string]int` that maps port labels to ports
|
||||||
* `port_map` - (Optional) A `map[string]int` that maps port labels to ports
|
|
||||||
on the guest. This forwards the host port to the guest vm. For example,
|
on the guest. This forwards the host port to the guest vm. For example,
|
||||||
`port_map { db = 6539 }` would forward the host port with label `db` to the
|
`port_map { db = 6539 }` would forward the host port with label `db` to the
|
||||||
guest vm's port 6539.
|
guest vm's port 6539.
|
||||||
|
|
|
@ -18,19 +18,15 @@ As such, it should be used with extreme care and is disabled by default.
|
||||||
|
|
||||||
The `raw_exec` driver supports the following configuration in the job spec:
|
The `raw_exec` driver supports the following configuration in the job spec:
|
||||||
|
|
||||||
* `command` - The command to execute. Must be provided.
|
* `command` - (Required) The command to execute. Must be provided.
|
||||||
|
* `artifact_source` – (Optional) Source location of an executable artifact. Must be accessible
|
||||||
* `artifact_source` – (Optional) Source location of an executable artifact. Must
|
from the Nomad client. If you specify an `artifact_source` to be executed, you
|
||||||
be accessible from the Nomad client. If you specify an `artifact_source` to be
|
must reference it in the `command` as show in the examples below
|
||||||
executed, you must reference it in the `command` as show in the examples below
|
* `checksum` - **(Optional)** The checksum type and value for the `artifact_source` image.
|
||||||
|
The format is `type:value`, where type is any of `md5`, `sha1`, `sha256`, or `sha512`,
|
||||||
* `checksum` - (Optional) The checksum type and value for the `artifact_source`
|
and the value is the computed checksum. If a checksum is supplied and does not
|
||||||
image. The format is `type:value`, where type is any of `md5`, `sha1`,
|
match the downloaded artifact, the driver will fail to start
|
||||||
`sha256`, or `sha512`, and the value is the computed checksum. If a checksum
|
* `args` - The argument list to the command, space seperated. Optional.
|
||||||
is supplied and does not match the downloaded artifact, the driver will fail
|
|
||||||
to start
|
|
||||||
|
|
||||||
* `args` - (Optional) A list of arguments to the `command`.
|
|
||||||
|
|
||||||
## Client Requirements
|
## Client Requirements
|
||||||
|
|
||||||
|
|
|
@ -20,16 +20,13 @@ being marked as experimental and should be used with care.
|
||||||
|
|
||||||
The `rkt` driver supports the following configuration in the job spec:
|
The `rkt` driver supports the following configuration in the job spec:
|
||||||
|
|
||||||
* `image` - The image to run which may be specified by name, hash, ACI address
|
* `trust_prefix` - **(Optional)** The trust prefix to be passed to rkt. Must be reachable from
|
||||||
or docker registry.
|
the box running the nomad agent. If not specified, the image is run without
|
||||||
|
verifying the image signature.
|
||||||
* `command` - (Optional) A command to execute on the ACI.
|
* `image` - **(Required)** The image to run which may be specified by name,
|
||||||
|
hash, ACI address or docker registry.
|
||||||
* `args` - (Optional) A list of arguments to the image.
|
* `command` - **(Optional**) A command to execute on the ACI.
|
||||||
|
* `args` - **(Optional**) A string of args to pass into the image.
|
||||||
* `trust_prefix` - (Optional) The trust prefix to be passed to rkt. Must be
|
|
||||||
reachable from the box running the nomad agent. If not specified, the image is
|
|
||||||
run without verifying the image signature.
|
|
||||||
|
|
||||||
## Task Directories
|
## Task Directories
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue