github.com/smithx10/nomad@v0.9.1-rc1/client/allocrunner/taskrunner/logmon_hook_unix_test.go (about) 1 // +build !windows 2 3 package taskrunner 4 5 import ( 6 "context" 7 "encoding/json" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "syscall" 12 "testing" 13 14 "github.com/hashicorp/nomad/client/allocrunner/interfaces" 15 "github.com/hashicorp/nomad/helper/testlog" 16 "github.com/hashicorp/nomad/nomad/mock" 17 "github.com/hashicorp/nomad/testutil" 18 "github.com/stretchr/testify/require" 19 ) 20 21 // TestTaskRunner_LogmonHook_StartCrashStop simulates logmon crashing while the 22 // Nomad client is restarting and asserts failing to reattach to logmon causes 23 // nomad to spawn a new logmon. 24 func TestTaskRunner_LogmonHook_StartCrashStop(t *testing.T) { 25 t.Parallel() 26 27 alloc := mock.BatchAlloc() 28 task := alloc.Job.TaskGroups[0].Tasks[0] 29 30 dir, err := ioutil.TempDir("", "nomadtest") 31 require.NoError(t, err) 32 defer func() { 33 require.NoError(t, os.RemoveAll(dir)) 34 }() 35 36 hookConf := newLogMonHookConfig(task.Name, dir) 37 hook := newLogMonHook(hookConf, testlog.HCLogger(t)) 38 39 req := interfaces.TaskPrestartRequest{ 40 Task: task, 41 } 42 resp := interfaces.TaskPrestartResponse{} 43 44 // First start 45 require.NoError(t, hook.Prestart(context.Background(), &req, &resp)) 46 defer hook.Stop(context.Background(), nil, nil) 47 48 origState := resp.State 49 origHookData := resp.State[logmonReattachKey] 50 require.NotEmpty(t, origHookData) 51 52 // Pluck PID out of reattach synthesize a crash 53 reattach := struct { 54 Pid int 55 }{} 56 require.NoError(t, json.Unmarshal([]byte(origHookData), &reattach)) 57 pid := reattach.Pid 58 require.NotZero(t, pid) 59 60 proc, _ := os.FindProcess(pid) 61 62 // Assert logmon is running 63 require.NoError(t, proc.Signal(syscall.Signal(0))) 64 65 // Kill it 66 require.NoError(t, proc.Signal(os.Kill)) 67 68 // Since signals are asynchronous wait for the process to die 69 testutil.WaitForResult(func() (bool, error) { 70 err := proc.Signal(syscall.Signal(0)) 71 return err != nil, fmt.Errorf("pid %d still running", pid) 72 }, func(err error) { 73 require.NoError(t, err) 74 }) 75 76 // Running prestart again should return a recoverable error with no 77 // reattach config to cause the task to be restarted with a new logmon. 78 req.PreviousState = map[string]string{ 79 logmonReattachKey: origHookData, 80 } 81 resp = interfaces.TaskPrestartResponse{} 82 err = hook.Prestart(context.Background(), &req, &resp) 83 require.NoError(t, err) 84 require.NotEqual(t, origState, resp.State) 85 86 // Running stop should shutdown logmon 87 require.NoError(t, hook.Stop(context.Background(), nil, nil)) 88 }