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