Add Valid command to spawner and make executors check when opening

This commit is contained in:
Alex Dadgar 2015-11-06 11:23:27 -08:00
parent f36685c7d2
commit 2321bddf2e
6 changed files with 123 additions and 5 deletions

View file

@ -89,7 +89,7 @@ func (e *BasicExecutor) Open(id string) error {
// Setup the executor. // Setup the executor.
e.spawn = &spawn e.spawn = &spawn
return nil return e.spawn.Valid()
} }
func (e *BasicExecutor) Wait() error { func (e *BasicExecutor) Wait() error {

View file

@ -95,8 +95,7 @@ func (e *LinuxExecutor) Open(id string) error {
e.groups = execID.Groups e.groups = execID.Groups
e.spawn = execID.Spawn e.spawn = execID.Spawn
e.taskDir = execID.TaskDir e.taskDir = execID.TaskDir
return e.spawn.Valid()
return nil
} }
func (e *LinuxExecutor) ID() (string, error) { func (e *LinuxExecutor) ID() (string, error) {

View file

@ -229,3 +229,33 @@ func Executor_Open(t *testing.T, command buildExecCommand, newExecutor func() Ex
log.Panicf("Command output incorrectly: want %v; got %v", expected, act) log.Panicf("Command output incorrectly: want %v; got %v", expected, act)
} }
} }
func Executor_Open_Invalid(t *testing.T, command buildExecCommand, newExecutor func() Executor) {
task, alloc := mockAllocDir(t)
e := command("echo", "foo")
if err := e.Limit(constraint); err != nil {
log.Panicf("Limit() failed: %v", err)
}
if err := e.ConfigureTaskDir(task, alloc); err != nil {
log.Panicf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
}
if err := e.Start(); err != nil {
log.Panicf("Start() failed: %v", err)
}
id, err := e.ID()
if err != nil {
log.Panicf("ID() failed: %v", err)
}
// Destroy the allocdir which removes the exit code.
alloc.Destroy()
e2 := newExecutor()
if err := e2.Open(id); err == nil {
log.Panicf("Open(%v) should have failed", id)
}
}

View file

@ -285,3 +285,18 @@ func (s *Spawner) readExitCode() (int, error) {
return exitStatus.ExitCode, nil return exitStatus.ExitCode, nil
} }
// Valid checks that the state of the Spawner is valid and that a subsequent
// Wait could be called. This is useful to call when reopening a Spawner
// throught client restarts. If Valid a nil error is returned.
func (s *Spawner) Valid() error {
if s.Alive() {
return nil
}
if _, err := s.readExitCode(); err == nil {
return nil
}
return fmt.Errorf("Spawner not alive and exit code not written")
}

View file

@ -2,12 +2,18 @@
package spawn package spawn
import "syscall" import (
"os"
"syscall"
)
func (s *Spawner) Alive() bool { func (s *Spawner) Alive() bool {
if s.spawn == nil { if s.spawn == nil {
var err error
if s.spawn, err = os.FindProcess(s.SpawnPid); err != nil {
return false return false
} }
}
err := s.spawn.Signal(syscall.Signal(0)) err := s.spawn.Signal(syscall.Signal(0))
return err == nil return err == nil

View file

@ -298,3 +298,71 @@ func TestSpawn_DeadSpawnDaemon_NonParent(t *testing.T) {
t.Fatalf("Wait() should have failed: %v", err) t.Fatalf("Wait() should have failed: %v", err)
} }
} }
func TestSpawn_Valid_TaskRunning(t *testing.T) {
f, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("TempFile() failed")
}
defer os.Remove(f.Name())
spawn := NewSpawner(f.Name())
spawn.SetCommand(exec.Command("sleep", "2"))
if err := spawn.Spawn(nil); err != nil {
t.Fatalf("Spawn() failed %v", err)
}
if err := spawn.Valid(); err != nil {
t.Fatalf("Valid() failed: %v", err)
}
if _, err := spawn.Wait(); err != nil {
t.Fatalf("Wait() failed %v", err)
}
}
func TestSpawn_Valid_TaskExit_ExitCode(t *testing.T) {
f, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("TempFile() failed")
}
defer os.Remove(f.Name())
spawn := NewSpawner(f.Name())
spawn.SetCommand(exec.Command("echo", "foo"))
if err := spawn.Spawn(nil); err != nil {
t.Fatalf("Spawn() failed %v", err)
}
if _, err := spawn.Wait(); err != nil {
t.Fatalf("Wait() failed %v", err)
}
if err := spawn.Valid(); err != nil {
t.Fatalf("Valid() failed: %v", err)
}
}
func TestSpawn_Valid_TaskExit_NoExitCode(t *testing.T) {
f, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("TempFile() failed")
}
spawn := NewSpawner(f.Name())
spawn.SetCommand(exec.Command("echo", "foo"))
if err := spawn.Spawn(nil); err != nil {
t.Fatalf("Spawn() failed %v", err)
}
if _, err := spawn.Wait(); err != nil {
t.Fatalf("Wait() failed %v", err)
}
// Delete the file so that it can't find the exit code.
os.Remove(f.Name())
if err := spawn.Valid(); err == nil {
t.Fatalf("Valid() should have failed")
}
}