github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/client/driver/raw_exec_test.go (about) 1 package driver 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "path/filepath" 7 "reflect" 8 "strings" 9 "syscall" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/nomad/client/config" 14 "github.com/hashicorp/nomad/client/driver/env" 15 "github.com/hashicorp/nomad/helper/testtask" 16 "github.com/hashicorp/nomad/nomad/structs" 17 "github.com/hashicorp/nomad/testutil" 18 ) 19 20 func TestRawExecDriver_Fingerprint(t *testing.T) { 21 task := &structs.Task{ 22 Name: "foo", 23 Resources: structs.DefaultResources(), 24 } 25 driverCtx, execCtx := testDriverContexts(task) 26 defer execCtx.AllocDir.Destroy() 27 d := NewRawExecDriver(driverCtx) 28 node := &structs.Node{ 29 Attributes: make(map[string]string), 30 } 31 32 // Disable raw exec. 33 cfg := &config.Config{Options: map[string]string{rawExecConfigOption: "false"}} 34 35 apply, err := d.Fingerprint(cfg, node) 36 if err != nil { 37 t.Fatalf("err: %v", err) 38 } 39 if apply { 40 t.Fatalf("should not apply") 41 } 42 if node.Attributes["driver.raw_exec"] != "" { 43 t.Fatalf("driver incorrectly enabled") 44 } 45 46 // Enable raw exec. 47 cfg.Options[rawExecConfigOption] = "true" 48 apply, err = d.Fingerprint(cfg, node) 49 if err != nil { 50 t.Fatalf("err: %v", err) 51 } 52 if !apply { 53 t.Fatalf("should apply") 54 } 55 if node.Attributes["driver.raw_exec"] != "1" { 56 t.Fatalf("driver not enabled") 57 } 58 } 59 60 func TestRawExecDriver_StartOpen_Wait(t *testing.T) { 61 task := &structs.Task{ 62 Name: "sleep", 63 Config: map[string]interface{}{ 64 "command": testtask.Path(), 65 "args": []string{"sleep", "1s"}, 66 }, 67 LogConfig: &structs.LogConfig{ 68 MaxFiles: 10, 69 MaxFileSizeMB: 10, 70 }, 71 Resources: basicResources, 72 } 73 testtask.SetTaskEnv(task) 74 driverCtx, execCtx := testDriverContexts(task) 75 defer execCtx.AllocDir.Destroy() 76 d := NewRawExecDriver(driverCtx) 77 78 handle, err := d.Start(execCtx, task) 79 if err != nil { 80 t.Fatalf("err: %v", err) 81 } 82 if handle == nil { 83 t.Fatalf("missing handle") 84 } 85 86 // Attempt to open 87 handle2, err := d.Open(execCtx, handle.ID()) 88 if err != nil { 89 t.Fatalf("err: %v", err) 90 } 91 if handle2 == nil { 92 t.Fatalf("missing handle") 93 } 94 95 // Task should terminate quickly 96 select { 97 case <-handle2.WaitCh(): 98 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 99 t.Fatalf("timeout") 100 } 101 handle.Kill() 102 handle2.Kill() 103 } 104 105 func TestRawExecDriver_Start_Wait(t *testing.T) { 106 task := &structs.Task{ 107 Name: "sleep", 108 Config: map[string]interface{}{ 109 "command": testtask.Path(), 110 "args": []string{"sleep", "1s"}, 111 }, 112 LogConfig: &structs.LogConfig{ 113 MaxFiles: 10, 114 MaxFileSizeMB: 10, 115 }, 116 Resources: basicResources, 117 } 118 testtask.SetTaskEnv(task) 119 driverCtx, execCtx := testDriverContexts(task) 120 defer execCtx.AllocDir.Destroy() 121 d := NewRawExecDriver(driverCtx) 122 123 handle, err := d.Start(execCtx, task) 124 if err != nil { 125 t.Fatalf("err: %v", err) 126 } 127 if handle == nil { 128 t.Fatalf("missing handle") 129 } 130 131 // Update should be a no-op 132 err = handle.Update(task) 133 if err != nil { 134 t.Fatalf("err: %v", err) 135 } 136 137 // Task should terminate quickly 138 select { 139 case res := <-handle.WaitCh(): 140 if !res.Successful() { 141 t.Fatalf("err: %v", res) 142 } 143 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 144 t.Fatalf("timeout") 145 } 146 } 147 148 func TestRawExecDriver_Start_Wait_AllocDir(t *testing.T) { 149 exp := []byte{'w', 'i', 'n'} 150 file := "output.txt" 151 outPath := fmt.Sprintf(`${%s}/%s`, env.AllocDir, file) 152 task := &structs.Task{ 153 Name: "sleep", 154 Config: map[string]interface{}{ 155 "command": testtask.Path(), 156 "args": []string{ 157 "sleep", "1s", 158 "write", string(exp), outPath, 159 }, 160 }, 161 LogConfig: &structs.LogConfig{ 162 MaxFiles: 10, 163 MaxFileSizeMB: 10, 164 }, 165 Resources: basicResources, 166 } 167 testtask.SetTaskEnv(task) 168 169 driverCtx, execCtx := testDriverContexts(task) 170 defer execCtx.AllocDir.Destroy() 171 d := NewRawExecDriver(driverCtx) 172 173 handle, err := d.Start(execCtx, task) 174 if err != nil { 175 t.Fatalf("err: %v", err) 176 } 177 if handle == nil { 178 t.Fatalf("missing handle") 179 } 180 181 // Task should terminate quickly 182 select { 183 case res := <-handle.WaitCh(): 184 if !res.Successful() { 185 t.Fatalf("err: %v", res) 186 } 187 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 188 t.Fatalf("timeout") 189 } 190 191 // Check that data was written to the shared alloc directory. 192 outputFile := filepath.Join(execCtx.AllocDir.SharedDir, file) 193 act, err := ioutil.ReadFile(outputFile) 194 if err != nil { 195 t.Fatalf("Couldn't read expected output: %v", err) 196 } 197 198 if !reflect.DeepEqual(act, exp) { 199 t.Fatalf("Command outputted %v; want %v", act, exp) 200 } 201 } 202 203 func TestRawExecDriver_Start_Kill_Wait(t *testing.T) { 204 task := &structs.Task{ 205 Name: "sleep", 206 Config: map[string]interface{}{ 207 "command": testtask.Path(), 208 "args": []string{"sleep", "45s"}, 209 }, 210 LogConfig: &structs.LogConfig{ 211 MaxFiles: 10, 212 MaxFileSizeMB: 10, 213 }, 214 Resources: basicResources, 215 } 216 testtask.SetTaskEnv(task) 217 218 driverCtx, execCtx := testDriverContexts(task) 219 defer execCtx.AllocDir.Destroy() 220 d := NewRawExecDriver(driverCtx) 221 222 handle, err := d.Start(execCtx, task) 223 if err != nil { 224 t.Fatalf("err: %v", err) 225 } 226 if handle == nil { 227 t.Fatalf("missing handle") 228 } 229 230 go func() { 231 time.Sleep(1 * time.Second) 232 err := handle.Kill() 233 234 // Can't rely on the ordering between wait and kill on travis... 235 if !testutil.IsTravis() && err != nil { 236 t.Fatalf("err: %v", err) 237 } 238 }() 239 240 // Task should terminate quickly 241 select { 242 case res := <-handle.WaitCh(): 243 if res.Successful() { 244 t.Fatal("should err") 245 } 246 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 247 t.Fatalf("timeout") 248 } 249 } 250 251 func TestRawExecDriverUser(t *testing.T) { 252 task := &structs.Task{ 253 Name: "sleep", 254 User: "alice", 255 Config: map[string]interface{}{ 256 "command": testtask.Path(), 257 "args": []string{"sleep", "45s"}, 258 }, 259 LogConfig: &structs.LogConfig{ 260 MaxFiles: 10, 261 MaxFileSizeMB: 10, 262 }, 263 Resources: basicResources, 264 } 265 testtask.SetTaskEnv(task) 266 267 driverCtx, execCtx := testDriverContexts(task) 268 defer execCtx.AllocDir.Destroy() 269 d := NewRawExecDriver(driverCtx) 270 271 handle, err := d.Start(execCtx, task) 272 if err == nil { 273 handle.Kill() 274 t.Fatalf("Should've failed") 275 } 276 msg := "unknown user alice" 277 if !strings.Contains(err.Error(), msg) { 278 t.Fatalf("Expecting '%v' in '%v'", msg, err) 279 } 280 } 281 282 func TestRawExecDriver_Signal(t *testing.T) { 283 task := &structs.Task{ 284 Name: "signal", 285 Config: map[string]interface{}{ 286 "command": "/bin/bash", 287 "args": []string{"test.sh"}, 288 }, 289 LogConfig: &structs.LogConfig{ 290 MaxFiles: 10, 291 MaxFileSizeMB: 10, 292 }, 293 Resources: basicResources, 294 KillTimeout: 10 * time.Second, 295 } 296 297 driverCtx, execCtx := testDriverContexts(task) 298 defer execCtx.AllocDir.Destroy() 299 d := NewExecDriver(driverCtx) 300 301 testFile := filepath.Join(execCtx.AllocDir.TaskDirs["signal"], "test.sh") 302 testData := []byte(` 303 at_term() { 304 echo 'Terminated.' 305 exit 3 306 } 307 trap at_term USR1 308 while true; do 309 sleep 1 310 done 311 `) 312 if err := ioutil.WriteFile(testFile, testData, 0777); err != nil { 313 fmt.Errorf("Failed to write data") 314 } 315 316 handle, err := d.Start(execCtx, task) 317 if err != nil { 318 t.Fatalf("err: %v", err) 319 } 320 if handle == nil { 321 t.Fatalf("missing handle") 322 } 323 324 go func() { 325 time.Sleep(100 * time.Millisecond) 326 err := handle.Signal(syscall.SIGUSR1) 327 if err != nil { 328 t.Fatalf("err: %v", err) 329 } 330 }() 331 332 // Task should terminate quickly 333 select { 334 case res := <-handle.WaitCh(): 335 if res.Successful() { 336 t.Fatal("should err") 337 } 338 case <-time.After(time.Duration(testutil.TestMultiplier()*6) * time.Second): 339 t.Fatalf("timeout") 340 } 341 342 // Check the log file to see it exited because of the signal 343 outputFile := filepath.Join(execCtx.AllocDir.LogDir(), "signal.stdout.0") 344 act, err := ioutil.ReadFile(outputFile) 345 if err != nil { 346 t.Fatalf("Couldn't read expected output: %v", err) 347 } 348 349 exp := "Terminated." 350 if strings.TrimSpace(string(act)) != exp { 351 t.Logf("Read from %v", outputFile) 352 t.Fatalf("Command outputted %v; want %v", act, exp) 353 } 354 }