2015-11-23 16:34:37 +00:00
|
|
|
// Package testtask implements a portable set of commands useful as stand-ins
|
|
|
|
// for user tasks.
|
|
|
|
package testtask
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2018-05-30 17:02:30 +00:00
|
|
|
"strconv"
|
|
|
|
"syscall"
|
2015-11-23 16:34:37 +00:00
|
|
|
"time"
|
|
|
|
|
2015-11-24 20:11:26 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
2018-09-26 14:42:02 +00:00
|
|
|
"github.com/hashicorp/nomad/plugins/drivers"
|
2015-11-23 16:34:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Path returns the path to the currently running executable.
|
|
|
|
func Path() string {
|
2018-07-05 15:04:12 +00:00
|
|
|
path, err := os.Executable()
|
2015-11-23 16:34:37 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
2015-11-24 20:11:26 +00:00
|
|
|
// SetCmdEnv configures the environment of cmd so that Run executes a testtask
|
|
|
|
// script when called from within cmd.
|
|
|
|
func SetCmdEnv(cmd *exec.Cmd) {
|
2015-11-23 16:34:37 +00:00
|
|
|
cmd.Env = append(os.Environ(), "TEST_TASK=execute")
|
|
|
|
}
|
|
|
|
|
2015-11-24 20:11:26 +00:00
|
|
|
// SetTaskEnv configures the environment of t so that Run executes a testtask
|
|
|
|
// script when called from within t.
|
|
|
|
func SetTaskEnv(t *structs.Task) {
|
|
|
|
if t.Env == nil {
|
|
|
|
t.Env = map[string]string{}
|
|
|
|
}
|
|
|
|
t.Env["TEST_TASK"] = "execute"
|
|
|
|
}
|
|
|
|
|
2018-09-26 05:18:03 +00:00
|
|
|
// SetTaskConfigEnv configures the environment of t so that Run executes a testtask
|
|
|
|
// script when called from within t.
|
2018-09-26 14:42:02 +00:00
|
|
|
func SetTaskConfigEnv(t *drivers.TaskConfig) {
|
2018-09-26 05:18:03 +00:00
|
|
|
if t.Env == nil {
|
|
|
|
t.Env = map[string]string{}
|
|
|
|
}
|
|
|
|
t.Env["TEST_TASK"] = "execute"
|
|
|
|
}
|
|
|
|
|
2015-11-23 16:34:37 +00:00
|
|
|
// Run interprets os.Args as a testtask script if the current program was
|
2015-11-24 20:11:26 +00:00
|
|
|
// launched with an environment configured by SetCmdEnv or SetTaskEnv. It
|
|
|
|
// returns false if the environment was not set by this package.
|
2015-11-23 16:34:37 +00:00
|
|
|
func Run() bool {
|
|
|
|
switch tm := os.Getenv("TEST_TASK"); tm {
|
|
|
|
case "":
|
|
|
|
return false
|
|
|
|
case "execute":
|
|
|
|
execute()
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
fmt.Fprintf(os.Stderr, "unexpected value for TEST_TASK, \"%s\"\n", tm)
|
|
|
|
os.Exit(1)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func execute() {
|
|
|
|
if len(os.Args) < 2 {
|
|
|
|
fmt.Fprintln(os.Stderr, "no command provided")
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
args := os.Args[1:]
|
|
|
|
|
|
|
|
// popArg removes the first argument from args and returns it.
|
|
|
|
popArg := func() string {
|
|
|
|
s := args[0]
|
|
|
|
args = args[1:]
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
// execute a sequence of operations from args
|
|
|
|
for len(args) > 0 {
|
|
|
|
switch cmd := popArg(); cmd {
|
|
|
|
|
|
|
|
case "sleep":
|
|
|
|
// sleep <dur>: sleep for a duration indicated by the first
|
|
|
|
// argument
|
|
|
|
if len(args) < 1 {
|
|
|
|
fmt.Fprintln(os.Stderr, "expected arg for sleep")
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
dur, err := time.ParseDuration(popArg())
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "could not parse sleep time: %v", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
time.Sleep(dur)
|
|
|
|
|
|
|
|
case "echo":
|
|
|
|
// echo <msg>: write the msg followed by a newline to stdout.
|
|
|
|
fmt.Println(popArg())
|
|
|
|
|
|
|
|
case "write":
|
|
|
|
// write <msg> <file>: write a message to a file. The first
|
|
|
|
// argument is the msg. The second argument is the path to the
|
|
|
|
// target file.
|
|
|
|
if len(args) < 2 {
|
|
|
|
fmt.Fprintln(os.Stderr, "expected two args for write")
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
msg := popArg()
|
|
|
|
file := popArg()
|
|
|
|
ioutil.WriteFile(file, []byte(msg), 0666)
|
|
|
|
|
2018-05-30 17:02:30 +00:00
|
|
|
case "pgrp":
|
|
|
|
// pgrp <group_int> puts the pid in a new process group
|
|
|
|
if len(args) < 1 {
|
|
|
|
fmt.Fprintln(os.Stderr, "expected process group number for pgrp")
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
num := popArg()
|
|
|
|
grp, err := strconv.Atoi(num)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "failed to convert process group number %q: %v\n", num, err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
if err := syscall.Setpgid(0, grp); err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "failed to set process group: %v\n", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
case "fork/exec":
|
|
|
|
// fork/exec <pid_file> <args> forks execs the helper process
|
|
|
|
if len(args) < 2 {
|
|
|
|
fmt.Fprintln(os.Stderr, "expect pid file and remaining args to fork exec")
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
pidFile := popArg()
|
|
|
|
|
|
|
|
cmd := exec.Command(Path(), args...)
|
|
|
|
SetCmdEnv(cmd)
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "failed to fork/exec: %v\n", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ioutil.WriteFile(pidFile, []byte(fmt.Sprintf("%d", cmd.Process.Pid)), 777); err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "failed to write pid file: %v\n", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "wait failed: %v\n", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
|
2015-11-23 16:34:37 +00:00
|
|
|
default:
|
|
|
|
fmt.Fprintln(os.Stderr, "unknown command:", cmd)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|