github.com/bigcommerce/nomad@v0.9.3-bc/drivers/rawexec/driver_unix_test.go (about) 1 // +build !windows 2 3 package rawexec 4 5 import ( 6 "context" 7 "runtime" 8 "testing" 9 10 "fmt" 11 "io/ioutil" 12 "path/filepath" 13 "strings" 14 "time" 15 16 "github.com/hashicorp/nomad/helper/testlog" 17 "github.com/hashicorp/nomad/helper/testtask" 18 "github.com/hashicorp/nomad/helper/uuid" 19 basePlug "github.com/hashicorp/nomad/plugins/base" 20 "github.com/hashicorp/nomad/plugins/drivers" 21 dtestutil "github.com/hashicorp/nomad/plugins/drivers/testutils" 22 "github.com/hashicorp/nomad/testutil" 23 "github.com/stretchr/testify/require" 24 "golang.org/x/sys/unix" 25 ) 26 27 func TestRawExecDriver_User(t *testing.T) { 28 t.Parallel() 29 if runtime.GOOS != "linux" { 30 t.Skip("Linux only test") 31 } 32 require := require.New(t) 33 34 d := NewRawExecDriver(testlog.HCLogger(t)) 35 harness := dtestutil.NewDriverHarness(t, d) 36 37 task := &drivers.TaskConfig{ 38 ID: uuid.Generate(), 39 Name: "sleep", 40 User: "alice", 41 } 42 43 cleanup := harness.MkAllocDir(task, false) 44 defer cleanup() 45 46 tc := &TaskConfig{ 47 Command: testtask.Path(), 48 Args: []string{"sleep", "45s"}, 49 } 50 require.NoError(task.EncodeConcreteDriverConfig(&tc)) 51 testtask.SetTaskConfigEnv(task) 52 53 _, _, err := harness.StartTask(task) 54 require.Error(err) 55 msg := "unknown user alice" 56 require.Contains(err.Error(), msg) 57 } 58 59 func TestRawExecDriver_Signal(t *testing.T) { 60 t.Parallel() 61 if runtime.GOOS != "linux" { 62 t.Skip("Linux only test") 63 } 64 require := require.New(t) 65 66 d := NewRawExecDriver(testlog.HCLogger(t)) 67 harness := dtestutil.NewDriverHarness(t, d) 68 69 task := &drivers.TaskConfig{ 70 ID: uuid.Generate(), 71 Name: "signal", 72 } 73 74 cleanup := harness.MkAllocDir(task, true) 75 defer cleanup() 76 77 tc := &TaskConfig{ 78 Command: "/bin/bash", 79 Args: []string{"test.sh"}, 80 } 81 require.NoError(task.EncodeConcreteDriverConfig(&tc)) 82 testtask.SetTaskConfigEnv(task) 83 84 testFile := filepath.Join(task.TaskDir().Dir, "test.sh") 85 testData := []byte(` 86 at_term() { 87 echo 'Terminated.' 88 exit 3 89 } 90 trap at_term USR1 91 while true; do 92 sleep 1 93 done 94 `) 95 require.NoError(ioutil.WriteFile(testFile, testData, 0777)) 96 97 _, _, err := harness.StartTask(task) 98 require.NoError(err) 99 100 go func() { 101 time.Sleep(100 * time.Millisecond) 102 require.NoError(harness.SignalTask(task.ID, "SIGUSR1")) 103 }() 104 105 // Task should terminate quickly 106 waitCh, err := harness.WaitTask(context.Background(), task.ID) 107 require.NoError(err) 108 select { 109 case res := <-waitCh: 110 require.False(res.Successful()) 111 require.Equal(3, res.ExitCode) 112 case <-time.After(time.Duration(testutil.TestMultiplier()*6) * time.Second): 113 require.Fail("WaitTask timeout") 114 } 115 116 // Check the log file to see it exited because of the signal 117 outputFile := filepath.Join(task.TaskDir().LogDir, "signal.stdout.0") 118 exp := "Terminated." 119 testutil.WaitForResult(func() (bool, error) { 120 act, err := ioutil.ReadFile(outputFile) 121 if err != nil { 122 return false, fmt.Errorf("Couldn't read expected output: %v", err) 123 } 124 125 if strings.TrimSpace(string(act)) != exp { 126 t.Logf("Read from %v", outputFile) 127 return false, fmt.Errorf("Command outputted %v; want %v", act, exp) 128 } 129 return true, nil 130 }, func(err error) { require.NoError(err) }) 131 } 132 133 func TestRawExecDriver_StartWaitStop(t *testing.T) { 134 t.Parallel() 135 require := require.New(t) 136 137 d := NewRawExecDriver(testlog.HCLogger(t)) 138 harness := dtestutil.NewDriverHarness(t, d) 139 defer harness.Kill() 140 141 // Disable cgroups so test works without root 142 config := &Config{NoCgroups: true} 143 var data []byte 144 require.NoError(basePlug.MsgPackEncode(&data, config)) 145 bconfig := &basePlug.Config{PluginConfig: data} 146 require.NoError(harness.SetConfig(bconfig)) 147 148 task := &drivers.TaskConfig{ 149 ID: uuid.Generate(), 150 Name: "test", 151 } 152 153 taskConfig := map[string]interface{}{} 154 taskConfig["command"] = testtask.Path() 155 taskConfig["args"] = []string{"sleep", "100s"} 156 157 require.NoError(task.EncodeConcreteDriverConfig(&taskConfig)) 158 159 cleanup := harness.MkAllocDir(task, false) 160 defer cleanup() 161 162 handle, _, err := harness.StartTask(task) 163 require.NoError(err) 164 165 ch, err := harness.WaitTask(context.Background(), handle.Config.ID) 166 require.NoError(err) 167 168 require.NoError(harness.WaitUntilStarted(task.ID, 1*time.Second)) 169 170 go func() { 171 harness.StopTask(task.ID, 2*time.Second, "SIGINT") 172 }() 173 174 select { 175 case result := <-ch: 176 require.Equal(int(unix.SIGINT), result.Signal) 177 case <-time.After(10 * time.Second): 178 require.Fail("timeout waiting for task to shutdown") 179 } 180 181 // Ensure that the task is marked as dead, but account 182 // for WaitTask() closing channel before internal state is updated 183 testutil.WaitForResult(func() (bool, error) { 184 status, err := harness.InspectTask(task.ID) 185 if err != nil { 186 return false, fmt.Errorf("inspecting task failed: %v", err) 187 } 188 if status.State != drivers.TaskStateExited { 189 return false, fmt.Errorf("task hasn't exited yet; status: %v", status.State) 190 } 191 192 return true, nil 193 }, func(err error) { 194 require.NoError(err) 195 }) 196 197 require.NoError(harness.DestroyTask(task.ID, true)) 198 } 199 200 func TestRawExec_ExecTaskStreaming(t *testing.T) { 201 t.Parallel() 202 if runtime.GOOS == "darwin" { 203 t.Skip("skip running exec tasks on darwin as darwin has restrictions on starting tty shells") 204 } 205 require := require.New(t) 206 207 d := NewRawExecDriver(testlog.HCLogger(t)) 208 harness := dtestutil.NewDriverHarness(t, d) 209 defer harness.Kill() 210 211 task := &drivers.TaskConfig{ 212 ID: uuid.Generate(), 213 Name: "sleep", 214 } 215 216 cleanup := harness.MkAllocDir(task, false) 217 defer cleanup() 218 219 tc := &TaskConfig{ 220 Command: testtask.Path(), 221 Args: []string{"sleep", "9000s"}, 222 } 223 require.NoError(task.EncodeConcreteDriverConfig(&tc)) 224 testtask.SetTaskConfigEnv(task) 225 226 _, _, err := harness.StartTask(task) 227 require.NoError(err) 228 defer d.DestroyTask(task.ID, true) 229 230 dtestutil.ExecTaskStreamingConformanceTests(t, harness, task.ID) 231 232 }