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