github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/client/driver/rkt_test.go (about) 1 package driver 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "reflect" 11 "strings" 12 "syscall" 13 "testing" 14 "time" 15 16 "github.com/hashicorp/nomad/client/config" 17 "github.com/hashicorp/nomad/nomad/structs" 18 "github.com/hashicorp/nomad/testutil" 19 20 ctestutils "github.com/hashicorp/nomad/client/testutil" 21 ) 22 23 func TestRktVersionRegex(t *testing.T) { 24 t.Parallel() 25 if os.Getenv("NOMAD_TEST_RKT") == "" { 26 t.Skip("NOMAD_TEST_RKT unset, skipping") 27 } 28 29 input_rkt := "rkt version 0.8.1" 30 input_appc := "appc version 1.2.0" 31 expected_rkt := "0.8.1" 32 expected_appc := "1.2.0" 33 rktMatches := reRktVersion.FindStringSubmatch(input_rkt) 34 appcMatches := reAppcVersion.FindStringSubmatch(input_appc) 35 if rktMatches[1] != expected_rkt { 36 fmt.Printf("Test failed; got %q; want %q\n", rktMatches[1], expected_rkt) 37 } 38 if appcMatches[1] != expected_appc { 39 fmt.Printf("Test failed; got %q; want %q\n", appcMatches[1], expected_appc) 40 } 41 } 42 43 // The fingerprinter test should always pass, even if rkt is not installed. 44 func TestRktDriver_Fingerprint(t *testing.T) { 45 t.Parallel() 46 if os.Getenv("NOMAD_TEST_RKT") == "" { 47 t.Skip("skipping rkt tests") 48 } 49 50 ctestutils.RktCompatible(t) 51 ctx := testDriverContexts(t, &structs.Task{Name: "foo", Driver: "rkt"}) 52 d := NewRktDriver(ctx.DriverCtx) 53 node := &structs.Node{ 54 Attributes: make(map[string]string), 55 } 56 apply, err := d.Fingerprint(&config.Config{}, node) 57 if err != nil { 58 t.Fatalf("err: %v", err) 59 } 60 if !apply { 61 t.Fatalf("should apply") 62 } 63 if node.Attributes["driver.rkt"] != "1" { 64 t.Fatalf("Missing Rkt driver") 65 } 66 if node.Attributes["driver.rkt.version"] == "" { 67 t.Fatalf("Missing Rkt driver version") 68 } 69 if node.Attributes["driver.rkt.appc.version"] == "" { 70 t.Fatalf("Missing appc version for the Rkt driver") 71 } 72 } 73 74 func TestRktDriver_Start_DNS(t *testing.T) { 75 if !testutil.IsTravis() { 76 t.Parallel() 77 } 78 if os.Getenv("NOMAD_TEST_RKT") == "" { 79 t.Skip("skipping rkt tests") 80 } 81 82 ctestutils.RktCompatible(t) 83 // TODO: use test server to load from a fixture 84 task := &structs.Task{ 85 Name: "etcd", 86 Driver: "rkt", 87 Config: map[string]interface{}{ 88 "trust_prefix": "coreos.com/etcd", 89 "image": "coreos.com/etcd:v2.0.4", 90 "command": "/etcd", 91 "dns_servers": []string{"8.8.8.8", "8.8.4.4"}, 92 "dns_search_domains": []string{"example.com", "example.org", "example.net"}, 93 }, 94 LogConfig: &structs.LogConfig{ 95 MaxFiles: 10, 96 MaxFileSizeMB: 10, 97 }, 98 Resources: &structs.Resources{ 99 MemoryMB: 128, 100 CPU: 100, 101 }, 102 } 103 104 ctx := testDriverContexts(t, task) 105 defer ctx.AllocDir.Destroy() 106 d := NewRktDriver(ctx.DriverCtx) 107 108 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 109 t.Fatalf("error in prestart: %v", err) 110 } 111 resp, err := d.Start(ctx.ExecCtx, task) 112 if err != nil { 113 t.Fatalf("err: %v", err) 114 } 115 defer resp.Handle.Kill() 116 117 // Attempt to open 118 handle2, err := d.Open(ctx.ExecCtx, resp.Handle.ID()) 119 if err != nil { 120 t.Fatalf("err: %v", err) 121 } 122 if handle2 == nil { 123 t.Fatalf("missing handle") 124 } 125 handle2.Kill() 126 } 127 128 func TestRktDriver_Start_Wait(t *testing.T) { 129 if !testutil.IsTravis() { 130 t.Parallel() 131 } 132 if os.Getenv("NOMAD_TEST_RKT") == "" { 133 t.Skip("skipping rkt tests") 134 } 135 136 ctestutils.RktCompatible(t) 137 task := &structs.Task{ 138 Name: "etcd", 139 Driver: "rkt", 140 Config: map[string]interface{}{ 141 "trust_prefix": "coreos.com/etcd", 142 "image": "coreos.com/etcd:v2.0.4", 143 "command": "/etcd", 144 "args": []string{"--version"}, 145 }, 146 LogConfig: &structs.LogConfig{ 147 MaxFiles: 10, 148 MaxFileSizeMB: 10, 149 }, 150 Resources: &structs.Resources{ 151 MemoryMB: 128, 152 CPU: 100, 153 }, 154 } 155 156 ctx := testDriverContexts(t, task) 157 defer ctx.AllocDir.Destroy() 158 d := NewRktDriver(ctx.DriverCtx) 159 160 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 161 t.Fatalf("error in prestart: %v", err) 162 } 163 resp, err := d.Start(ctx.ExecCtx, task) 164 if err != nil { 165 t.Fatalf("err: %v", err) 166 } 167 defer resp.Handle.Kill() 168 169 // Update should be a no-op 170 err = resp.Handle.Update(task) 171 if err != nil { 172 t.Fatalf("err: %v", err) 173 } 174 175 // Signal should be an error 176 if err = resp.Handle.Signal(syscall.SIGTERM); err == nil { 177 t.Fatalf("err: %v", err) 178 } 179 180 select { 181 case res := <-resp.Handle.WaitCh(): 182 if !res.Successful() { 183 t.Fatalf("err: %v", res) 184 } 185 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 186 t.Fatalf("timeout") 187 } 188 } 189 190 func TestRktDriver_Start_Wait_Skip_Trust(t *testing.T) { 191 if !testutil.IsTravis() { 192 t.Parallel() 193 } 194 if os.Getenv("NOMAD_TEST_RKT") == "" { 195 t.Skip("skipping rkt tests") 196 } 197 198 ctestutils.RktCompatible(t) 199 task := &structs.Task{ 200 Name: "etcd", 201 Driver: "rkt", 202 Config: map[string]interface{}{ 203 "image": "coreos.com/etcd:v2.0.4", 204 "command": "/etcd", 205 "args": []string{"--version"}, 206 }, 207 LogConfig: &structs.LogConfig{ 208 MaxFiles: 10, 209 MaxFileSizeMB: 10, 210 }, 211 Resources: &structs.Resources{ 212 MemoryMB: 128, 213 CPU: 100, 214 }, 215 } 216 217 ctx := testDriverContexts(t, task) 218 defer ctx.AllocDir.Destroy() 219 d := NewRktDriver(ctx.DriverCtx) 220 221 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 222 t.Fatalf("error in prestart: %v", err) 223 } 224 resp, err := d.Start(ctx.ExecCtx, task) 225 if err != nil { 226 t.Fatalf("err: %v", err) 227 } 228 defer resp.Handle.Kill() 229 230 // Update should be a no-op 231 err = resp.Handle.Update(task) 232 if err != nil { 233 t.Fatalf("err: %v", err) 234 } 235 236 select { 237 case res := <-resp.Handle.WaitCh(): 238 if !res.Successful() { 239 t.Fatalf("err: %v", res) 240 } 241 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 242 t.Fatalf("timeout") 243 } 244 } 245 246 func TestRktDriver_Start_Wait_AllocDir(t *testing.T) { 247 if !testutil.IsTravis() { 248 t.Parallel() 249 } 250 if os.Getenv("NOMAD_TEST_RKT") == "" { 251 t.Skip("skipping rkt tests") 252 } 253 254 ctestutils.RktCompatible(t) 255 256 exp := []byte{'w', 'i', 'n'} 257 file := "output.txt" 258 tmpvol, err := ioutil.TempDir("", "nomadtest_rktdriver_volumes") 259 if err != nil { 260 t.Fatalf("error creating temporary dir: %v", err) 261 } 262 defer os.RemoveAll(tmpvol) 263 hostpath := filepath.Join(tmpvol, file) 264 265 task := &structs.Task{ 266 Name: "rkttest_alpine", 267 Driver: "rkt", 268 Config: map[string]interface{}{ 269 "image": "docker://alpine", 270 "command": "/bin/sh", 271 "args": []string{ 272 "-c", 273 fmt.Sprintf(`echo -n %s > foo/%s`, string(exp), file), 274 }, 275 "net": []string{"none"}, 276 "volumes": []string{fmt.Sprintf("%s:/foo", tmpvol)}, 277 }, 278 LogConfig: &structs.LogConfig{ 279 MaxFiles: 10, 280 MaxFileSizeMB: 10, 281 }, 282 Resources: &structs.Resources{ 283 MemoryMB: 128, 284 CPU: 100, 285 }, 286 } 287 288 ctx := testDriverContexts(t, task) 289 defer ctx.AllocDir.Destroy() 290 d := NewRktDriver(ctx.DriverCtx) 291 292 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 293 t.Fatalf("error in prestart: %v", err) 294 } 295 resp, err := d.Start(ctx.ExecCtx, task) 296 if err != nil { 297 t.Fatalf("err: %v", err) 298 } 299 defer resp.Handle.Kill() 300 301 select { 302 case res := <-resp.Handle.WaitCh(): 303 if !res.Successful() { 304 t.Fatalf("err: %v", res) 305 } 306 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 307 t.Fatalf("timeout") 308 } 309 310 // Check that data was written to the shared alloc directory. 311 act, err := ioutil.ReadFile(hostpath) 312 if err != nil { 313 t.Fatalf("Couldn't read expected output: %v", err) 314 } 315 316 if !reflect.DeepEqual(act, exp) { 317 t.Fatalf("Command output is %v; expected %v", act, exp) 318 } 319 } 320 321 func TestRktDriverUser(t *testing.T) { 322 if !testutil.IsTravis() { 323 t.Parallel() 324 } 325 if os.Getenv("NOMAD_TEST_RKT") == "" { 326 t.Skip("skipping rkt tests") 327 } 328 329 ctestutils.RktCompatible(t) 330 task := &structs.Task{ 331 Name: "etcd", 332 Driver: "rkt", 333 User: "alice", 334 Config: map[string]interface{}{ 335 "trust_prefix": "coreos.com/etcd", 336 "image": "coreos.com/etcd:v2.0.4", 337 "command": "/etcd", 338 "args": []string{"--version"}, 339 }, 340 LogConfig: &structs.LogConfig{ 341 MaxFiles: 10, 342 MaxFileSizeMB: 10, 343 }, 344 Resources: &structs.Resources{ 345 MemoryMB: 128, 346 CPU: 100, 347 }, 348 } 349 350 ctx := testDriverContexts(t, task) 351 defer ctx.AllocDir.Destroy() 352 d := NewRktDriver(ctx.DriverCtx) 353 354 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 355 t.Fatalf("error in prestart: %v", err) 356 } 357 resp, err := d.Start(ctx.ExecCtx, task) 358 if err == nil { 359 resp.Handle.Kill() 360 t.Fatalf("Should've failed") 361 } 362 msg := "unknown user alice" 363 if !strings.Contains(err.Error(), msg) { 364 t.Fatalf("Expecting '%v' in '%v'", msg, err) 365 } 366 } 367 368 func TestRktTrustPrefix(t *testing.T) { 369 if !testutil.IsTravis() { 370 t.Parallel() 371 } 372 if os.Getenv("NOMAD_TEST_RKT") == "" { 373 t.Skip("skipping rkt tests") 374 } 375 ctestutils.RktCompatible(t) 376 task := &structs.Task{ 377 Name: "etcd", 378 Driver: "rkt", 379 Config: map[string]interface{}{ 380 "trust_prefix": "example.com/invalid", 381 "image": "coreos.com/etcd:v2.0.4", 382 "command": "/etcd", 383 "args": []string{"--version"}, 384 }, 385 LogConfig: &structs.LogConfig{ 386 MaxFiles: 10, 387 MaxFileSizeMB: 10, 388 }, 389 Resources: &structs.Resources{ 390 MemoryMB: 128, 391 CPU: 100, 392 }, 393 } 394 ctx := testDriverContexts(t, task) 395 defer ctx.AllocDir.Destroy() 396 d := NewRktDriver(ctx.DriverCtx) 397 398 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 399 t.Fatalf("error in prestart: %v", err) 400 } 401 resp, err := d.Start(ctx.ExecCtx, task) 402 if err == nil { 403 resp.Handle.Kill() 404 t.Fatalf("Should've failed") 405 } 406 msg := "Error running rkt trust" 407 if !strings.Contains(err.Error(), msg) { 408 t.Fatalf("Expecting '%v' in '%v'", msg, err) 409 } 410 } 411 412 func TestRktTaskValidate(t *testing.T) { 413 t.Parallel() 414 ctestutils.RktCompatible(t) 415 task := &structs.Task{ 416 Name: "etcd", 417 Driver: "rkt", 418 Config: map[string]interface{}{ 419 "trust_prefix": "coreos.com/etcd", 420 "image": "coreos.com/etcd:v2.0.4", 421 "command": "/etcd", 422 "args": []string{"--version"}, 423 "dns_servers": []string{"8.8.8.8", "8.8.4.4"}, 424 "dns_search_domains": []string{"example.com", "example.org", "example.net"}, 425 }, 426 Resources: basicResources, 427 } 428 ctx := testDriverContexts(t, task) 429 defer ctx.AllocDir.Destroy() 430 d := NewRktDriver(ctx.DriverCtx) 431 432 if err := d.Validate(task.Config); err != nil { 433 t.Fatalf("Validation error in TaskConfig : '%v'", err) 434 } 435 } 436 437 // TODO: Port Mapping test should be ran with proper ACI image and test the port access. 438 func TestRktDriver_PortsMapping(t *testing.T) { 439 if !testutil.IsTravis() { 440 t.Parallel() 441 } 442 if os.Getenv("NOMAD_TEST_RKT") == "" { 443 t.Skip("skipping rkt tests") 444 } 445 446 ctestutils.RktCompatible(t) 447 task := &structs.Task{ 448 Name: "etcd", 449 Driver: "rkt", 450 Config: map[string]interface{}{ 451 "image": "docker://redis:latest", 452 "args": []string{"--version"}, 453 "port_map": []map[string]string{ 454 map[string]string{ 455 "main": "6379-tcp", 456 }, 457 }, 458 "debug": "true", 459 }, 460 LogConfig: &structs.LogConfig{ 461 MaxFiles: 10, 462 MaxFileSizeMB: 10, 463 }, 464 Resources: &structs.Resources{ 465 MemoryMB: 256, 466 CPU: 512, 467 Networks: []*structs.NetworkResource{ 468 &structs.NetworkResource{ 469 IP: "127.0.0.1", 470 ReservedPorts: []structs.Port{{Label: "main", Value: 8080}}, 471 }, 472 }, 473 }, 474 } 475 476 ctx := testDriverContexts(t, task) 477 defer ctx.AllocDir.Destroy() 478 d := NewRktDriver(ctx.DriverCtx) 479 480 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 481 t.Fatalf("error in prestart: %v", err) 482 } 483 resp, err := d.Start(ctx.ExecCtx, task) 484 if err != nil { 485 t.Fatalf("err: %v", err) 486 } 487 488 failCh := make(chan error, 1) 489 go func() { 490 time.Sleep(1 * time.Second) 491 if err := resp.Handle.Kill(); err != nil { 492 failCh <- err 493 } 494 }() 495 496 select { 497 case err := <-failCh: 498 t.Fatalf("failed to kill handle: %v", err) 499 case <-resp.Handle.WaitCh(): 500 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 501 t.Fatalf("timeout") 502 } 503 } 504 505 func TestRktDriver_HandlerExec(t *testing.T) { 506 if !testutil.IsTravis() { 507 t.Parallel() 508 } 509 if os.Getenv("NOMAD_TEST_RKT") == "" { 510 t.Skip("skipping rkt tests") 511 } 512 513 ctestutils.RktCompatible(t) 514 task := &structs.Task{ 515 Name: "etcd", 516 Driver: "rkt", 517 Config: map[string]interface{}{ 518 "trust_prefix": "coreos.com/etcd", 519 "image": "coreos.com/etcd:v2.0.4", 520 "command": "/etcd", 521 }, 522 LogConfig: &structs.LogConfig{ 523 MaxFiles: 10, 524 MaxFileSizeMB: 10, 525 }, 526 Resources: &structs.Resources{ 527 MemoryMB: 128, 528 CPU: 100, 529 }, 530 } 531 532 ctx := testDriverContexts(t, task) 533 defer ctx.AllocDir.Destroy() 534 d := NewRktDriver(ctx.DriverCtx) 535 536 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 537 t.Fatalf("error in prestart: %v", err) 538 } 539 resp, err := d.Start(ctx.ExecCtx, task) 540 if err != nil { 541 t.Fatalf("err: %v", err) 542 } 543 544 // Give the pod a second to start 545 time.Sleep(time.Second) 546 547 // Exec a command that should work 548 out, code, err := resp.Handle.Exec(context.TODO(), "/etcd", []string{"--version"}) 549 if err != nil { 550 t.Fatalf("error exec'ing etcd --version: %v", err) 551 } 552 if code != 0 { 553 t.Fatalf("expected `etcd --version` to succeed but exit code was: %d\n%s", code, string(out)) 554 } 555 if expected := []byte("etcd version "); !bytes.HasPrefix(out, expected) { 556 t.Fatalf("expected output to start with %q but found:\n%q", expected, out) 557 } 558 559 // Exec a command that should fail 560 out, code, err = resp.Handle.Exec(context.TODO(), "/etcd", []string{"--kaljdshf"}) 561 if err != nil { 562 t.Fatalf("error exec'ing bad command: %v", err) 563 } 564 if code == 0 { 565 t.Fatalf("expected `stat` to fail but exit code was: %d", code) 566 } 567 if expected := "flag provided but not defined"; !bytes.Contains(out, []byte(expected)) { 568 t.Fatalf("expected output to contain %q but found: %q", expected, out) 569 } 570 571 if err := resp.Handle.Kill(); err != nil { 572 t.Fatalf("error killing handle: %v", err) 573 } 574 }