github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/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/hashicorp/nomad/client/config" 15 "github.com/hashicorp/nomad/nomad/structs" 16 "github.com/hashicorp/nomad/testutil" 17 18 ctestutils "github.com/hashicorp/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 driverCtx, _ := testDriverContexts(&structs.Task{Name: "foo"}) 48 d := NewRktDriver(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 Config: map[string]interface{}{ 80 "trust_prefix": "coreos.com/etcd", 81 "image": "coreos.com/etcd:v2.0.4", 82 "command": "/etcd", 83 "dns_servers": []string{"8.8.8.8", "8.8.4.4"}, 84 "dns_search_domains": []string{"example.com", "example.org", "example.net"}, 85 }, 86 LogConfig: &structs.LogConfig{ 87 MaxFiles: 10, 88 MaxFileSizeMB: 10, 89 }, 90 Resources: &structs.Resources{ 91 MemoryMB: 128, 92 CPU: 100, 93 }, 94 } 95 96 driverCtx, execCtx := testDriverContexts(task) 97 defer execCtx.AllocDir.Destroy() 98 99 d := NewRktDriver(driverCtx) 100 101 handle, err := d.Start(execCtx, task) 102 if err != nil { 103 t.Fatalf("err: %v", err) 104 } 105 if handle == nil { 106 t.Fatalf("missing handle") 107 } 108 defer handle.Kill() 109 110 // Attempt to open 111 handle2, err := d.Open(execCtx, handle.ID()) 112 if err != nil { 113 t.Fatalf("err: %v", err) 114 } 115 if handle2 == nil { 116 t.Fatalf("missing handle") 117 } 118 } 119 120 func TestRktDriver_Start_Wait(t *testing.T) { 121 if os.Getenv("NOMAD_TEST_RKT") == "" { 122 t.Skip("skipping rkt tests") 123 } 124 125 ctestutils.RktCompatible(t) 126 task := &structs.Task{ 127 Name: "etcd", 128 Config: map[string]interface{}{ 129 "trust_prefix": "coreos.com/etcd", 130 "image": "coreos.com/etcd:v2.0.4", 131 "command": "/etcd", 132 "args": []string{"--version"}, 133 }, 134 LogConfig: &structs.LogConfig{ 135 MaxFiles: 10, 136 MaxFileSizeMB: 10, 137 }, 138 Resources: &structs.Resources{ 139 MemoryMB: 128, 140 CPU: 100, 141 }, 142 } 143 144 driverCtx, execCtx := testDriverContexts(task) 145 defer execCtx.AllocDir.Destroy() 146 d := NewRktDriver(driverCtx) 147 148 handle, err := d.Start(execCtx, task) 149 if err != nil { 150 t.Fatalf("err: %v", err) 151 } 152 if handle == nil { 153 t.Fatalf("missing handle") 154 } 155 defer handle.Kill() 156 157 // Update should be a no-op 158 err = handle.Update(task) 159 if err != nil { 160 t.Fatalf("err: %v", err) 161 } 162 163 // Signal should be an error 164 if err = handle.Signal(syscall.SIGTERM); err == nil { 165 t.Fatalf("err: %v", err) 166 } 167 168 select { 169 case res := <-handle.WaitCh(): 170 if !res.Successful() { 171 t.Fatalf("err: %v", res) 172 } 173 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 174 t.Fatalf("timeout") 175 } 176 } 177 178 func TestRktDriver_Start_Wait_Skip_Trust(t *testing.T) { 179 if os.Getenv("NOMAD_TEST_RKT") == "" { 180 t.Skip("skipping rkt tests") 181 } 182 183 ctestutils.RktCompatible(t) 184 task := &structs.Task{ 185 Name: "etcd", 186 Config: map[string]interface{}{ 187 "image": "coreos.com/etcd:v2.0.4", 188 "command": "/etcd", 189 "args": []string{"--version"}, 190 }, 191 LogConfig: &structs.LogConfig{ 192 MaxFiles: 10, 193 MaxFileSizeMB: 10, 194 }, 195 Resources: &structs.Resources{ 196 MemoryMB: 128, 197 CPU: 100, 198 }, 199 } 200 201 driverCtx, execCtx := testDriverContexts(task) 202 defer execCtx.AllocDir.Destroy() 203 d := NewRktDriver(driverCtx) 204 205 handle, err := d.Start(execCtx, task) 206 if err != nil { 207 t.Fatalf("err: %v", err) 208 } 209 if handle == nil { 210 t.Fatalf("missing handle") 211 } 212 defer handle.Kill() 213 214 // Update should be a no-op 215 err = handle.Update(task) 216 if err != nil { 217 t.Fatalf("err: %v", err) 218 } 219 220 select { 221 case res := <-handle.WaitCh(): 222 if !res.Successful() { 223 t.Fatalf("err: %v", res) 224 } 225 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 226 t.Fatalf("timeout") 227 } 228 } 229 230 func TestRktDriver_Start_Wait_AllocDir(t *testing.T) { 231 if os.Getenv("NOMAD_TEST_RKT") == "" { 232 t.Skip("skipping rkt tests") 233 } 234 235 ctestutils.RktCompatible(t) 236 237 exp := []byte{'w', 'i', 'n'} 238 file := "output.txt" 239 tmpvol, err := ioutil.TempDir("", "nomadtest_rktdriver_volumes") 240 if err != nil { 241 t.Fatalf("error creating temporary dir: %v", err) 242 } 243 defer os.RemoveAll(tmpvol) 244 hostpath := filepath.Join(tmpvol, file) 245 246 task := &structs.Task{ 247 Name: "alpine", 248 Config: map[string]interface{}{ 249 "image": "docker://alpine", 250 "command": "/bin/sh", 251 "args": []string{ 252 "-c", 253 fmt.Sprintf(`echo -n %s > foo/%s`, string(exp), file), 254 }, 255 "volumes": []string{fmt.Sprintf("%s:/foo", tmpvol)}, 256 }, 257 LogConfig: &structs.LogConfig{ 258 MaxFiles: 10, 259 MaxFileSizeMB: 10, 260 }, 261 Resources: &structs.Resources{ 262 MemoryMB: 128, 263 CPU: 100, 264 }, 265 } 266 267 driverCtx, execCtx := testDriverContexts(task) 268 defer execCtx.AllocDir.Destroy() 269 d := NewRktDriver(driverCtx) 270 271 handle, err := d.Start(execCtx, task) 272 if err != nil { 273 t.Fatalf("err: %v", err) 274 } 275 if handle == nil { 276 t.Fatalf("missing handle") 277 } 278 defer handle.Kill() 279 280 select { 281 case res := <-handle.WaitCh(): 282 if !res.Successful() { 283 t.Fatalf("err: %v", res) 284 } 285 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 286 t.Fatalf("timeout") 287 } 288 289 // Check that data was written to the shared alloc directory. 290 act, err := ioutil.ReadFile(hostpath) 291 if err != nil { 292 t.Fatalf("Couldn't read expected output: %v", err) 293 } 294 295 if !reflect.DeepEqual(act, exp) { 296 t.Fatalf("Command output is %v; expected %v", act, exp) 297 } 298 } 299 300 func TestRktDriverUser(t *testing.T) { 301 if os.Getenv("NOMAD_TEST_RKT") == "" { 302 t.Skip("skipping rkt tests") 303 } 304 305 ctestutils.RktCompatible(t) 306 task := &structs.Task{ 307 Name: "etcd", 308 User: "alice", 309 Config: map[string]interface{}{ 310 "trust_prefix": "coreos.com/etcd", 311 "image": "coreos.com/etcd:v2.0.4", 312 "command": "/etcd", 313 "args": []string{"--version"}, 314 }, 315 LogConfig: &structs.LogConfig{ 316 MaxFiles: 10, 317 MaxFileSizeMB: 10, 318 }, 319 Resources: &structs.Resources{ 320 MemoryMB: 128, 321 CPU: 100, 322 }, 323 } 324 325 driverCtx, execCtx := testDriverContexts(task) 326 defer execCtx.AllocDir.Destroy() 327 d := NewRktDriver(driverCtx) 328 329 handle, err := d.Start(execCtx, task) 330 if err == nil { 331 handle.Kill() 332 t.Fatalf("Should've failed") 333 } 334 msg := "unknown user alice" 335 if !strings.Contains(err.Error(), msg) { 336 t.Fatalf("Expecting '%v' in '%v'", msg, err) 337 } 338 } 339 340 func TestRktTrustPrefix(t *testing.T) { 341 if os.Getenv("NOMAD_TEST_RKT") == "" { 342 t.Skip("skipping rkt tests") 343 } 344 ctestutils.RktCompatible(t) 345 task := &structs.Task{ 346 Name: "etcd", 347 Config: map[string]interface{}{ 348 "trust_prefix": "example.com/invalid", 349 "image": "coreos.com/etcd:v2.0.4", 350 "command": "/etcd", 351 "args": []string{"--version"}, 352 }, 353 LogConfig: &structs.LogConfig{ 354 MaxFiles: 10, 355 MaxFileSizeMB: 10, 356 }, 357 Resources: &structs.Resources{ 358 MemoryMB: 128, 359 CPU: 100, 360 }, 361 } 362 driverCtx, execCtx := testDriverContexts(task) 363 defer execCtx.AllocDir.Destroy() 364 365 d := NewRktDriver(driverCtx) 366 367 handle, err := d.Start(execCtx, task) 368 if err == nil { 369 handle.Kill() 370 t.Fatalf("Should've failed") 371 } 372 msg := "Error running rkt trust" 373 if !strings.Contains(err.Error(), msg) { 374 t.Fatalf("Expecting '%v' in '%v'", msg, err) 375 } 376 } 377 378 func TestRktTaskValidate(t *testing.T) { 379 ctestutils.RktCompatible(t) 380 task := &structs.Task{ 381 Name: "etcd", 382 Config: map[string]interface{}{ 383 "trust_prefix": "coreos.com/etcd", 384 "image": "coreos.com/etcd:v2.0.4", 385 "command": "/etcd", 386 "args": []string{"--version"}, 387 "dns_servers": []string{"8.8.8.8", "8.8.4.4"}, 388 "dns_search_domains": []string{"example.com", "example.org", "example.net"}, 389 }, 390 Resources: basicResources, 391 } 392 driverCtx, execCtx := testDriverContexts(task) 393 defer execCtx.AllocDir.Destroy() 394 395 d := NewRktDriver(driverCtx) 396 if err := d.Validate(task.Config); err != nil { 397 t.Fatalf("Validation error in TaskConfig : '%v'", err) 398 } 399 } 400 401 // TODO: Port Mapping test should be ran with proper ACI image and test the port access. 402 func TestRktDriver_PortsMapping(t *testing.T) { 403 if os.Getenv("NOMAD_TEST_RKT") == "" { 404 t.Skip("skipping rkt tests") 405 } 406 407 ctestutils.RktCompatible(t) 408 task := &structs.Task{ 409 Name: "etcd", 410 Config: map[string]interface{}{ 411 "image": "docker://redis:latest", 412 "args": []string{"--version"}, 413 "port_map": []map[string]string{ 414 map[string]string{ 415 "main": "6379-tcp", 416 }, 417 }, 418 "debug": "true", 419 }, 420 LogConfig: &structs.LogConfig{ 421 MaxFiles: 10, 422 MaxFileSizeMB: 10, 423 }, 424 Resources: &structs.Resources{ 425 MemoryMB: 256, 426 CPU: 512, 427 Networks: []*structs.NetworkResource{ 428 &structs.NetworkResource{ 429 IP: "127.0.0.1", 430 ReservedPorts: []structs.Port{{"main", 8080}}, 431 }, 432 }, 433 }, 434 } 435 436 driverCtx, execCtx := testDriverContexts(task) 437 defer execCtx.AllocDir.Destroy() 438 439 d := NewRktDriver(driverCtx) 440 441 handle, err := d.Start(execCtx, task) 442 if err != nil { 443 t.Fatalf("err: %v", err) 444 } 445 if handle == nil { 446 t.Fatalf("missing handle") 447 } 448 defer handle.Kill() 449 450 select { 451 case res := <-handle.WaitCh(): 452 if !res.Successful() { 453 t.Fatalf("err: %v", res) 454 } 455 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 456 t.Fatalf("timeout") 457 } 458 }