github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/provider/ec2/ebs_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package ec2_test 5 6 import ( 7 "fmt" 8 "sort" 9 "strconv" 10 "time" 11 12 "github.com/juju/errors" 13 "github.com/juju/names" 14 jc "github.com/juju/testing/checkers" 15 awsec2 "gopkg.in/amz.v3/ec2" 16 "gopkg.in/amz.v3/ec2/ec2test" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/constraints" 20 "github.com/juju/juju/environs/config" 21 "github.com/juju/juju/environs/jujutest" 22 "github.com/juju/juju/environs/tags" 23 "github.com/juju/juju/instance" 24 "github.com/juju/juju/juju/arch" 25 "github.com/juju/juju/provider/ec2" 26 "github.com/juju/juju/storage" 27 "github.com/juju/juju/testing" 28 "github.com/juju/juju/version" 29 ) 30 31 type storageSuite struct { 32 testing.BaseSuite 33 } 34 35 var _ = gc.Suite(&storageSuite{}) 36 37 func (*storageSuite) TestValidateConfigUnknownConfig(c *gc.C) { 38 p := ec2.EBSProvider() 39 cfg, err := storage.NewConfig("foo", ec2.EBS_ProviderType, map[string]interface{}{ 40 "unknown": "config", 41 }) 42 c.Assert(err, jc.ErrorIsNil) 43 err = p.ValidateConfig(cfg) 44 c.Assert(err, jc.ErrorIsNil) // unknown attrs ignored 45 } 46 47 func (s *storageSuite) TestSupports(c *gc.C) { 48 p := ec2.EBSProvider() 49 c.Assert(p.Supports(storage.StorageKindBlock), jc.IsTrue) 50 c.Assert(p.Supports(storage.StorageKindFilesystem), jc.IsFalse) 51 } 52 53 var _ = gc.Suite(&ebsVolumeSuite{}) 54 55 type ebsVolumeSuite struct { 56 testing.BaseSuite 57 jujutest.Tests 58 srv localServer 59 restoreEC2Patching func() 60 61 instanceId string 62 } 63 64 func (s *ebsVolumeSuite) SetUpSuite(c *gc.C) { 65 // Upload arches that ec2 supports; add to this 66 // as ec2 coverage expands. 67 s.UploadArches = []string{arch.AMD64, arch.I386} 68 s.TestConfig = localConfigAttrs 69 s.restoreEC2Patching = patchEC2ForTesting() 70 s.BaseSuite.SetUpSuite(c) 71 } 72 73 func (s *ebsVolumeSuite) TearDownSuite(c *gc.C) { 74 s.BaseSuite.TearDownSuite(c) 75 s.restoreEC2Patching() 76 } 77 78 func (s *ebsVolumeSuite) SetUpTest(c *gc.C) { 79 s.PatchValue(&version.Current, version.Binary{ 80 Number: testing.FakeVersionNumber, 81 Series: testing.FakeDefaultSeries, 82 Arch: arch.AMD64, 83 }) 84 s.BaseSuite.SetUpTest(c) 85 s.srv.startServer(c) 86 s.Tests.SetUpTest(c) 87 s.PatchValue(&ec2.DestroyVolumeAttempt.Delay, time.Duration(0)) 88 } 89 90 func (s *ebsVolumeSuite) TearDownTest(c *gc.C) { 91 s.Tests.TearDownTest(c) 92 s.srv.stopServer(c) 93 s.BaseSuite.TearDownTest(c) 94 } 95 96 func (s *ebsVolumeSuite) volumeSource(c *gc.C, cfg *storage.Config) storage.VolumeSource { 97 envCfg, err := config.New(config.NoDefaults, s.TestConfig) 98 c.Assert(err, jc.ErrorIsNil) 99 p := ec2.EBSProvider() 100 vs, err := p.VolumeSource(envCfg, cfg) 101 c.Assert(err, jc.ErrorIsNil) 102 return vs 103 } 104 105 func (s *ebsVolumeSuite) createVolumes(vs storage.VolumeSource, instanceId string) ([]storage.CreateVolumesResult, error) { 106 if instanceId == "" { 107 instanceId = s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Running, nil)[0] 108 } 109 volume0 := names.NewVolumeTag("0") 110 volume1 := names.NewVolumeTag("1") 111 volume2 := names.NewVolumeTag("2") 112 params := []storage.VolumeParams{{ 113 Tag: volume0, 114 Size: 10 * 1000, 115 Provider: ec2.EBS_ProviderType, 116 Attributes: map[string]interface{}{ 117 "volume-type": "io1", 118 "iops": 100, 119 }, 120 Attachment: &storage.VolumeAttachmentParams{ 121 AttachmentParams: storage.AttachmentParams{ 122 InstanceId: instance.Id(instanceId), 123 }, 124 }, 125 ResourceTags: map[string]string{ 126 tags.JujuEnv: s.TestConfig["uuid"].(string), 127 }, 128 }, { 129 Tag: volume1, 130 Size: 20 * 1000, 131 Provider: ec2.EBS_ProviderType, 132 Attachment: &storage.VolumeAttachmentParams{ 133 AttachmentParams: storage.AttachmentParams{ 134 InstanceId: instance.Id(instanceId), 135 }, 136 }, 137 ResourceTags: map[string]string{ 138 tags.JujuEnv: "something-else", 139 }, 140 }, { 141 Tag: volume2, 142 Size: 30 * 1000, 143 Provider: ec2.EBS_ProviderType, 144 ResourceTags: map[string]string{ 145 "abc": "123", 146 }, 147 Attachment: &storage.VolumeAttachmentParams{ 148 AttachmentParams: storage.AttachmentParams{ 149 InstanceId: instance.Id(instanceId), 150 }, 151 }, 152 }} 153 return vs.CreateVolumes(params) 154 } 155 156 func (s *ebsVolumeSuite) assertCreateVolumes(c *gc.C, vs storage.VolumeSource, instanceId string) { 157 results, err := s.createVolumes(vs, instanceId) 158 c.Assert(err, jc.ErrorIsNil) 159 c.Assert(results, gc.HasLen, 3) 160 c.Assert(results[0].Volume, jc.DeepEquals, &storage.Volume{ 161 names.NewVolumeTag("0"), 162 storage.VolumeInfo{ 163 Size: 10240, 164 VolumeId: "vol-0", 165 Persistent: true, 166 }, 167 }) 168 c.Assert(results[1].Volume, jc.DeepEquals, &storage.Volume{ 169 names.NewVolumeTag("1"), 170 storage.VolumeInfo{ 171 Size: 20480, 172 VolumeId: "vol-1", 173 Persistent: true, 174 }, 175 }) 176 c.Assert(results[2].Volume, jc.DeepEquals, &storage.Volume{ 177 names.NewVolumeTag("2"), 178 storage.VolumeInfo{ 179 Size: 30720, 180 VolumeId: "vol-2", 181 Persistent: true, 182 }, 183 }) 184 ec2Client := ec2.StorageEC2(vs) 185 ec2Vols, err := ec2Client.Volumes(nil, nil) 186 c.Assert(err, jc.ErrorIsNil) 187 c.Assert(ec2Vols.Volumes, gc.HasLen, 3) 188 sortBySize(ec2Vols.Volumes) 189 c.Assert(ec2Vols.Volumes[0].Size, gc.Equals, 10) 190 c.Assert(ec2Vols.Volumes[1].Size, gc.Equals, 20) 191 c.Assert(ec2Vols.Volumes[2].Size, gc.Equals, 30) 192 } 193 194 type volumeSorter struct { 195 vols []awsec2.Volume 196 less func(i, j awsec2.Volume) bool 197 } 198 199 func sortBySize(vols []awsec2.Volume) { 200 sort.Sort(volumeSorter{vols, func(i, j awsec2.Volume) bool { 201 return i.Size < j.Size 202 }}) 203 } 204 205 func (s volumeSorter) Len() int { 206 return len(s.vols) 207 } 208 209 func (s volumeSorter) Swap(i, j int) { 210 s.vols[i], s.vols[j] = s.vols[j], s.vols[i] 211 } 212 213 func (s volumeSorter) Less(i, j int) bool { 214 return s.less(s.vols[i], s.vols[j]) 215 } 216 217 func (s *ebsVolumeSuite) TestCreateVolumes(c *gc.C) { 218 vs := s.volumeSource(c, nil) 219 s.assertCreateVolumes(c, vs, "") 220 } 221 222 func (s *ebsVolumeSuite) TestVolumeTags(c *gc.C) { 223 vs := s.volumeSource(c, nil) 224 results, err := s.createVolumes(vs, "") 225 c.Assert(err, jc.ErrorIsNil) 226 c.Assert(results, gc.HasLen, 3) 227 c.Assert(results[0].Volume, jc.DeepEquals, &storage.Volume{ 228 names.NewVolumeTag("0"), 229 storage.VolumeInfo{ 230 Size: 10240, 231 VolumeId: "vol-0", 232 Persistent: true, 233 }, 234 }) 235 c.Assert(results[1].Volume, jc.DeepEquals, &storage.Volume{ 236 names.NewVolumeTag("1"), 237 storage.VolumeInfo{ 238 Size: 20480, 239 VolumeId: "vol-1", 240 Persistent: true, 241 }, 242 }) 243 c.Assert(results[2].Volume, jc.DeepEquals, &storage.Volume{ 244 names.NewVolumeTag("2"), 245 storage.VolumeInfo{ 246 Size: 30720, 247 VolumeId: "vol-2", 248 Persistent: true, 249 }, 250 }) 251 ec2Client := ec2.StorageEC2(vs) 252 ec2Vols, err := ec2Client.Volumes(nil, nil) 253 c.Assert(err, jc.ErrorIsNil) 254 c.Assert(ec2Vols.Volumes, gc.HasLen, 3) 255 sortBySize(ec2Vols.Volumes) 256 c.Assert(ec2Vols.Volumes[0].Tags, jc.SameContents, []awsec2.Tag{ 257 {"juju-env-uuid", "deadbeef-0bad-400d-8000-4b1d0d06f00d"}, 258 {"Name", "juju-sample-volume-0"}, 259 }) 260 c.Assert(ec2Vols.Volumes[1].Tags, jc.SameContents, []awsec2.Tag{ 261 {"juju-env-uuid", "something-else"}, 262 {"Name", "juju-sample-volume-1"}, 263 }) 264 c.Assert(ec2Vols.Volumes[2].Tags, jc.SameContents, []awsec2.Tag{ 265 {"Name", "juju-sample-volume-2"}, 266 {"abc", "123"}, 267 }) 268 } 269 270 func (s *ebsVolumeSuite) TestVolumeTypeAliases(c *gc.C) { 271 instanceIdRunning := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Running, nil)[0] 272 vs := s.volumeSource(c, nil) 273 ec2Client := ec2.StorageEC2(vs) 274 aliases := [][2]string{ 275 {"magnetic", "standard"}, 276 {"ssd", "gp2"}, 277 {"provisioned-iops", "io1"}, 278 } 279 for i, alias := range aliases { 280 params := []storage.VolumeParams{{ 281 Tag: names.NewVolumeTag("0"), 282 Size: 10 * 1000, 283 Provider: ec2.EBS_ProviderType, 284 Attributes: map[string]interface{}{ 285 "volume-type": alias[0], 286 }, 287 Attachment: &storage.VolumeAttachmentParams{ 288 AttachmentParams: storage.AttachmentParams{ 289 InstanceId: instance.Id(instanceIdRunning), 290 }, 291 }, 292 }} 293 if alias[1] == "io1" { 294 params[0].Attributes["iops"] = 100 295 } 296 results, err := vs.CreateVolumes(params) 297 c.Assert(err, jc.ErrorIsNil) 298 c.Assert(results, gc.HasLen, 1) 299 c.Assert(results[0].Volume.VolumeId, gc.Equals, fmt.Sprintf("vol-%d", i)) 300 } 301 ec2Vols, err := ec2Client.Volumes(nil, nil) 302 c.Assert(err, jc.ErrorIsNil) 303 c.Assert(ec2Vols.Volumes, gc.HasLen, len(aliases)) 304 sort.Sort(volumeSorter{ec2Vols.Volumes, func(i, j awsec2.Volume) bool { 305 return i.Id < j.Id 306 }}) 307 for i, alias := range aliases { 308 c.Assert(ec2Vols.Volumes[i].VolumeType, gc.Equals, alias[1]) 309 } 310 } 311 312 func (s *ebsVolumeSuite) TestDestroyVolumes(c *gc.C) { 313 vs := s.volumeSource(c, nil) 314 params := s.setupAttachVolumesTest(c, vs, ec2test.Running) 315 errs, err := vs.DetachVolumes(params) 316 c.Assert(err, jc.ErrorIsNil) 317 c.Assert(errs, jc.DeepEquals, []error{nil}) 318 errs, err = vs.DestroyVolumes([]string{"vol-0"}) 319 c.Assert(err, jc.ErrorIsNil) 320 c.Assert(errs, jc.DeepEquals, []error{nil}) 321 322 ec2Client := ec2.StorageEC2(vs) 323 ec2Vols, err := ec2Client.Volumes(nil, nil) 324 c.Assert(err, jc.ErrorIsNil) 325 c.Assert(ec2Vols.Volumes, gc.HasLen, 2) 326 sortBySize(ec2Vols.Volumes) 327 c.Assert(ec2Vols.Volumes[0].Size, gc.Equals, 20) 328 } 329 330 func (s *ebsVolumeSuite) TestDestroyVolumesStillAttached(c *gc.C) { 331 vs := s.volumeSource(c, nil) 332 s.setupAttachVolumesTest(c, vs, ec2test.Running) 333 errs, err := vs.DestroyVolumes([]string{"vol-0"}) 334 c.Assert(err, jc.ErrorIsNil) 335 c.Assert(errs, jc.DeepEquals, []error{nil}) 336 337 ec2Client := ec2.StorageEC2(vs) 338 ec2Vols, err := ec2Client.Volumes(nil, nil) 339 c.Assert(err, jc.ErrorIsNil) 340 c.Assert(ec2Vols.Volumes, gc.HasLen, 2) 341 sortBySize(ec2Vols.Volumes) 342 c.Assert(ec2Vols.Volumes[0].Size, gc.Equals, 20) 343 } 344 345 func (s *ebsVolumeSuite) TestDescribeVolumes(c *gc.C) { 346 vs := s.volumeSource(c, nil) 347 s.assertCreateVolumes(c, vs, "") 348 349 vols, err := vs.DescribeVolumes([]string{"vol-0", "vol-1"}) 350 c.Assert(err, jc.ErrorIsNil) 351 c.Assert(vols, jc.DeepEquals, []storage.DescribeVolumesResult{{ 352 VolumeInfo: &storage.VolumeInfo{ 353 Size: 10240, 354 VolumeId: "vol-0", 355 Persistent: true, 356 }, 357 }, { 358 VolumeInfo: &storage.VolumeInfo{ 359 Size: 20480, 360 VolumeId: "vol-1", 361 Persistent: true, 362 }, 363 }}) 364 } 365 366 func (s *ebsVolumeSuite) TestDescribeVolumesNotFound(c *gc.C) { 367 vs := s.volumeSource(c, nil) 368 vols, err := vs.DescribeVolumes([]string{"vol-42"}) 369 c.Assert(err, jc.ErrorIsNil) 370 c.Assert(vols, gc.HasLen, 1) 371 c.Assert(vols[0].Error, gc.ErrorMatches, "vol-42 not found") 372 } 373 374 func (s *ebsVolumeSuite) TestListVolumes(c *gc.C) { 375 vs := s.volumeSource(c, nil) 376 s.assertCreateVolumes(c, vs, "") 377 378 // Only one volume created by assertCreateVolumes has 379 // the env-uuid tag with the expected value. 380 volIds, err := vs.ListVolumes() 381 c.Assert(err, jc.ErrorIsNil) 382 c.Assert(volIds, jc.SameContents, []string{"vol-0"}) 383 } 384 385 func (s *ebsVolumeSuite) TestCreateVolumesErrors(c *gc.C) { 386 vs := s.volumeSource(c, nil) 387 volume0 := names.NewVolumeTag("0") 388 389 instanceIdPending := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Pending, nil)[0] 390 instanceIdRunning := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Running, nil)[0] 391 attachmentParams := storage.VolumeAttachmentParams{ 392 AttachmentParams: storage.AttachmentParams{ 393 InstanceId: instance.Id(instanceIdRunning), 394 }, 395 } 396 397 for _, test := range []struct { 398 params storage.VolumeParams 399 err string 400 }{{ 401 params: storage.VolumeParams{ 402 Provider: ec2.EBS_ProviderType, 403 Attachment: &storage.VolumeAttachmentParams{ 404 AttachmentParams: storage.AttachmentParams{ 405 InstanceId: "woat", 406 }, 407 }, 408 }, 409 err: `querying instance details: instance "woat" not found \(InvalidInstanceID.NotFound\)`, 410 }, { 411 params: storage.VolumeParams{ 412 Provider: ec2.EBS_ProviderType, 413 Attachment: &storage.VolumeAttachmentParams{ 414 AttachmentParams: storage.AttachmentParams{ 415 InstanceId: instance.Id(instanceIdPending), 416 }, 417 }, 418 }, 419 err: "cannot attach to non-running instance i-3", 420 }, { 421 params: storage.VolumeParams{ 422 Size: 100000000, 423 Provider: ec2.EBS_ProviderType, 424 Attributes: map[string]interface{}{}, 425 Attachment: &attachmentParams, 426 }, 427 err: "97657 GiB exceeds the maximum of 1024 GiB", 428 }, { 429 params: storage.VolumeParams{ 430 Tag: volume0, 431 Size: 1000, 432 Provider: ec2.EBS_ProviderType, 433 Attributes: map[string]interface{}{ 434 "volume-type": "io1", 435 "iops": "1234", 436 }, 437 Attachment: &attachmentParams, 438 }, 439 err: "volume size is 1 GiB, must be at least 10 GiB for provisioned IOPS", 440 }, { 441 params: storage.VolumeParams{ 442 Tag: volume0, 443 Size: 10000, 444 Provider: ec2.EBS_ProviderType, 445 Attributes: map[string]interface{}{ 446 "volume-type": "io1", 447 "iops": "1234", 448 }, 449 Attachment: &attachmentParams, 450 }, 451 err: "volume size is 10 GiB, must be at least 41 GiB to support 1234 IOPS", 452 }, { 453 params: storage.VolumeParams{ 454 Tag: volume0, 455 Size: 10000, 456 Provider: ec2.EBS_ProviderType, 457 Attributes: map[string]interface{}{ 458 "volume-type": "standard", 459 "iops": "1234", 460 }, 461 Attachment: &attachmentParams, 462 }, 463 err: `IOPS specified, but volume type is "standard"`, 464 }, { 465 params: storage.VolumeParams{ 466 Tag: volume0, 467 Size: 10000, 468 Provider: ec2.EBS_ProviderType, 469 Attributes: map[string]interface{}{ 470 "volume-type": "what", 471 }, 472 Attachment: &attachmentParams, 473 }, 474 err: "validating EBS storage config: volume-type: unexpected value \"what\"", 475 }} { 476 results, err := vs.CreateVolumes([]storage.VolumeParams{test.params}) 477 c.Assert(err, jc.ErrorIsNil) 478 c.Assert(results, gc.HasLen, 1) 479 c.Check(results[0].Error, gc.ErrorMatches, test.err) 480 } 481 } 482 483 var imageId = "ami-ccf405a5" // Ubuntu Maverick, i386, EBS store 484 485 func (s *ebsVolumeSuite) setupAttachVolumesTest( 486 c *gc.C, vs storage.VolumeSource, state awsec2.InstanceState, 487 ) []storage.VolumeAttachmentParams { 488 489 instanceId := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, state, nil)[0] 490 s.assertCreateVolumes(c, vs, instanceId) 491 492 return []storage.VolumeAttachmentParams{{ 493 Volume: names.NewVolumeTag("0"), 494 VolumeId: "vol-0", 495 AttachmentParams: storage.AttachmentParams{ 496 Machine: names.NewMachineTag("1"), 497 InstanceId: instance.Id(instanceId), 498 }, 499 }} 500 } 501 502 func (s *ebsVolumeSuite) TestAttachVolumesNotRunning(c *gc.C) { 503 vs := s.volumeSource(c, nil) 504 instanceId := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Pending, nil)[0] 505 results, err := s.createVolumes(vs, instanceId) 506 c.Assert(err, jc.ErrorIsNil) 507 c.Assert(results, gc.Not(gc.HasLen), 0) 508 for _, result := range results { 509 c.Check(errors.Cause(result.Error), gc.ErrorMatches, "cannot attach to non-running instance i-3") 510 } 511 } 512 513 func (s *ebsVolumeSuite) TestAttachVolumes(c *gc.C) { 514 vs := s.volumeSource(c, nil) 515 params := s.setupAttachVolumesTest(c, vs, ec2test.Running) 516 result, err := vs.AttachVolumes(params) 517 c.Assert(err, jc.ErrorIsNil) 518 c.Assert(result, gc.HasLen, 1) 519 c.Assert(result[0].Error, jc.ErrorIsNil) 520 c.Assert(result[0].VolumeAttachment, jc.DeepEquals, &storage.VolumeAttachment{ 521 names.NewVolumeTag("0"), 522 names.NewMachineTag("1"), 523 storage.VolumeAttachmentInfo{ 524 DeviceName: "xvdf", 525 ReadOnly: false, 526 }, 527 }) 528 529 ec2Client := ec2.StorageEC2(vs) 530 ec2Vols, err := ec2Client.Volumes(nil, nil) 531 c.Assert(err, jc.ErrorIsNil) 532 c.Assert(ec2Vols.Volumes, gc.HasLen, 3) 533 sortBySize(ec2Vols.Volumes) 534 c.Assert(ec2Vols.Volumes[0].Attachments, jc.DeepEquals, []awsec2.VolumeAttachment{{ 535 VolumeId: "vol-0", 536 InstanceId: "i-3", 537 Device: "/dev/sdf", 538 Status: "attached", 539 }}) 540 541 // Test idempotency. 542 result, err = vs.AttachVolumes(params) 543 c.Assert(err, jc.ErrorIsNil) 544 c.Assert(result, gc.HasLen, 1) 545 c.Assert(result[0].Error, jc.ErrorIsNil) 546 c.Assert(result[0].VolumeAttachment, jc.DeepEquals, &storage.VolumeAttachment{ 547 names.NewVolumeTag("0"), 548 names.NewMachineTag("1"), 549 storage.VolumeAttachmentInfo{ 550 DeviceName: "xvdf", 551 ReadOnly: false, 552 }, 553 }) 554 } 555 556 // TODO(axw) add tests for attempting to attach while 557 // a volume is still in the "creating" state. 558 559 func (s *ebsVolumeSuite) TestDetachVolumes(c *gc.C) { 560 vs := s.volumeSource(c, nil) 561 params := s.setupAttachVolumesTest(c, vs, ec2test.Running) 562 _, err := vs.AttachVolumes(params) 563 c.Assert(err, jc.ErrorIsNil) 564 errs, err := vs.DetachVolumes(params) 565 c.Assert(err, jc.ErrorIsNil) 566 c.Assert(errs, jc.DeepEquals, []error{nil}) 567 568 ec2Client := ec2.StorageEC2(vs) 569 ec2Vols, err := ec2Client.Volumes(nil, nil) 570 c.Assert(err, jc.ErrorIsNil) 571 c.Assert(ec2Vols.Volumes, gc.HasLen, 3) 572 sortBySize(ec2Vols.Volumes) 573 c.Assert(ec2Vols.Volumes[0].Attachments, gc.HasLen, 0) 574 575 // Test idempotent 576 errs, err = vs.DetachVolumes(params) 577 c.Assert(err, jc.ErrorIsNil) 578 c.Assert(errs, jc.DeepEquals, []error{nil}) 579 } 580 581 type blockDeviceMappingSuite struct { 582 testing.BaseSuite 583 } 584 585 var _ = gc.Suite(&blockDeviceMappingSuite{}) 586 587 func (*blockDeviceMappingSuite) TestBlockDeviceNamer(c *gc.C) { 588 var nextName func() (string, string, error) 589 expect := func(expectRequest, expectActual string) { 590 request, actual, err := nextName() 591 c.Assert(err, jc.ErrorIsNil) 592 c.Assert(request, gc.Equals, expectRequest) 593 c.Assert(actual, gc.Equals, expectActual) 594 } 595 expectN := func(expectRequest, expectActual string) { 596 for i := 1; i <= 6; i++ { 597 request, actual, err := nextName() 598 c.Assert(err, jc.ErrorIsNil) 599 c.Assert(request, gc.Equals, expectRequest+strconv.Itoa(i)) 600 c.Assert(actual, gc.Equals, expectActual+strconv.Itoa(i)) 601 } 602 } 603 expectErr := func(expectErr string) { 604 _, _, err := nextName() 605 c.Assert(err, gc.ErrorMatches, expectErr) 606 } 607 608 // First without numbers. 609 nextName = ec2.BlockDeviceNamer(awsec2.Instance{ 610 VirtType: "hvm", 611 }) 612 expect("/dev/sdf", "xvdf") 613 expect("/dev/sdg", "xvdg") 614 expect("/dev/sdh", "xvdh") 615 expect("/dev/sdi", "xvdi") 616 expect("/dev/sdj", "xvdj") 617 expect("/dev/sdk", "xvdk") 618 expect("/dev/sdl", "xvdl") 619 expect("/dev/sdm", "xvdm") 620 expect("/dev/sdn", "xvdn") 621 expect("/dev/sdo", "xvdo") 622 expect("/dev/sdp", "xvdp") 623 expectErr("too many EBS volumes to attach") 624 625 // Now with numbers. 626 nextName = ec2.BlockDeviceNamer(awsec2.Instance{ 627 VirtType: "paravirtual", 628 }) 629 expect("/dev/sdf1", "xvdf1") 630 expect("/dev/sdf2", "xvdf2") 631 expect("/dev/sdf3", "xvdf3") 632 expect("/dev/sdf4", "xvdf4") 633 expect("/dev/sdf5", "xvdf5") 634 expect("/dev/sdf6", "xvdf6") 635 expectN("/dev/sdg", "xvdg") 636 expectN("/dev/sdh", "xvdh") 637 expectN("/dev/sdi", "xvdi") 638 expectN("/dev/sdj", "xvdj") 639 expectN("/dev/sdk", "xvdk") 640 expectN("/dev/sdl", "xvdl") 641 expectN("/dev/sdm", "xvdm") 642 expectN("/dev/sdn", "xvdn") 643 expectN("/dev/sdo", "xvdo") 644 expectN("/dev/sdp", "xvdp") 645 expectErr("too many EBS volumes to attach") 646 } 647 648 func (*blockDeviceMappingSuite) TestGetBlockDeviceMappings(c *gc.C) { 649 mapping, err := ec2.GetBlockDeviceMappings(constraints.Value{}) 650 c.Assert(err, jc.ErrorIsNil) 651 c.Assert(mapping, gc.DeepEquals, []awsec2.BlockDeviceMapping{{ 652 VolumeSize: 8, 653 DeviceName: "/dev/sda1", 654 }, { 655 VirtualName: "ephemeral0", 656 DeviceName: "/dev/sdb", 657 }, { 658 VirtualName: "ephemeral1", 659 DeviceName: "/dev/sdc", 660 }, { 661 VirtualName: "ephemeral2", 662 DeviceName: "/dev/sdd", 663 }, { 664 VirtualName: "ephemeral3", 665 DeviceName: "/dev/sde", 666 }}) 667 }