github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/client/driver/exec_unix_test.go (about) 1 // +build !windows 2 3 package driver 4 5 import ( 6 "encoding/json" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strings" 11 "syscall" 12 "testing" 13 "time" 14 15 "github.com/hashicorp/nomad/nomad/structs" 16 "github.com/hashicorp/nomad/testutil" 17 18 ctestutils "github.com/hashicorp/nomad/client/testutil" 19 ) 20 21 func TestExecDriver_KillUserPid_OnPluginReconnectFailure(t *testing.T) { 22 if !testutil.IsTravis() { 23 t.Parallel() 24 } 25 ctestutils.ExecCompatible(t) 26 task := &structs.Task{ 27 Name: "sleep", 28 Driver: "exec", 29 Config: map[string]interface{}{ 30 "command": "/bin/sleep", 31 "args": []string{"1000000"}, 32 }, 33 LogConfig: &structs.LogConfig{ 34 MaxFiles: 10, 35 MaxFileSizeMB: 10, 36 }, 37 Resources: basicResources, 38 } 39 40 ctx := testDriverContexts(t, task) 41 defer ctx.AllocDir.Destroy() 42 d := NewExecDriver(ctx.DriverCtx) 43 44 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 45 t.Fatalf("prestart err: %v", err) 46 } 47 resp, err := d.Start(ctx.ExecCtx, task) 48 if err != nil { 49 t.Fatalf("err: %v", err) 50 } 51 defer resp.Handle.Kill() 52 53 id := &execId{} 54 if err := json.Unmarshal([]byte(resp.Handle.ID()), id); err != nil { 55 t.Fatalf("Failed to parse handle '%s': %v", resp.Handle.ID(), err) 56 } 57 pluginPid := id.PluginConfig.Pid 58 proc, err := os.FindProcess(pluginPid) 59 if err != nil { 60 t.Fatalf("can't find plugin pid: %v", pluginPid) 61 } 62 if err := proc.Kill(); err != nil { 63 t.Fatalf("can't kill plugin pid: %v", err) 64 } 65 66 // Attempt to open 67 handle2, err := d.Open(ctx.ExecCtx, resp.Handle.ID()) 68 if err == nil { 69 t.Fatalf("expected error") 70 } 71 if handle2 != nil { 72 handle2.Kill() 73 t.Fatalf("expected handle2 to be nil") 74 } 75 76 // Test if the userpid is still present 77 userProc, _ := os.FindProcess(id.UserPid) 78 79 for retry := 3; retry > 0; retry-- { 80 if err = userProc.Signal(syscall.Signal(0)); err != nil { 81 // Process is gone as expected; exit 82 return 83 } 84 85 // Killing processes is async; wait and check again 86 time.Sleep(time.Second) 87 } 88 if err = userProc.Signal(syscall.Signal(0)); err == nil { 89 t.Fatalf("expected user process to die") 90 } 91 } 92 93 func TestExecDriver_Signal(t *testing.T) { 94 if !testutil.IsTravis() { 95 t.Parallel() 96 } 97 ctestutils.ExecCompatible(t) 98 task := &structs.Task{ 99 Name: "signal", 100 Driver: "exec", 101 Config: map[string]interface{}{ 102 "command": "/bin/bash", 103 "args": []string{"test.sh"}, 104 }, 105 LogConfig: &structs.LogConfig{ 106 MaxFiles: 10, 107 MaxFileSizeMB: 10, 108 }, 109 Resources: basicResources, 110 KillTimeout: 10 * time.Second, 111 } 112 113 ctx := testDriverContexts(t, task) 114 defer ctx.AllocDir.Destroy() 115 d := NewExecDriver(ctx.DriverCtx) 116 117 testFile := filepath.Join(ctx.ExecCtx.TaskDir.Dir, "test.sh") 118 testData := []byte(` 119 at_term() { 120 echo 'Terminated.' 121 exit 3 122 } 123 trap at_term USR1 124 while true; do 125 sleep 1 126 done 127 `) 128 if err := ioutil.WriteFile(testFile, testData, 0777); err != nil { 129 t.Fatalf("Failed to write data: %v", err) 130 } 131 132 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 133 t.Fatalf("prestart err: %v", err) 134 } 135 resp, err := d.Start(ctx.ExecCtx, task) 136 if err != nil { 137 t.Fatalf("err: %v", err) 138 } 139 140 go func() { 141 time.Sleep(100 * time.Millisecond) 142 err := resp.Handle.Signal(syscall.SIGUSR1) 143 if err != nil { 144 t.Fatalf("err: %v", err) 145 } 146 }() 147 148 // Task should terminate quickly 149 select { 150 case res := <-resp.Handle.WaitCh(): 151 if res.Successful() { 152 t.Fatal("should err") 153 } 154 case <-time.After(time.Duration(testutil.TestMultiplier()*6) * time.Second): 155 t.Fatalf("timeout") 156 } 157 158 // Check the log file to see it exited because of the signal 159 outputFile := filepath.Join(ctx.ExecCtx.TaskDir.LogDir, "signal.stdout.0") 160 act, err := ioutil.ReadFile(outputFile) 161 if err != nil { 162 t.Fatalf("Couldn't read expected output: %v", err) 163 } 164 165 exp := "Terminated." 166 if strings.TrimSpace(string(act)) != exp { 167 t.Logf("Read from %v", outputFile) 168 t.Fatalf("Command outputted %v; want %v", act, exp) 169 } 170 }