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