github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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 "github.com/juju/utils/arch" 16 awsec2 "gopkg.in/amz.v3/ec2" 17 "gopkg.in/amz.v3/ec2/ec2test" 18 gc "gopkg.in/check.v1" 19 20 "github.com/juju/juju/constraints" 21 "github.com/juju/juju/environs/config" 22 "github.com/juju/juju/environs/jujutest" 23 "github.com/juju/juju/environs/tags" 24 "github.com/juju/juju/instance" 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": 30, 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].Error, jc.ErrorIsNil) 228 c.Assert(results[0].Volume, jc.DeepEquals, &storage.Volume{ 229 names.NewVolumeTag("0"), 230 storage.VolumeInfo{ 231 Size: 10240, 232 VolumeId: "vol-0", 233 Persistent: true, 234 }, 235 }) 236 c.Assert(results[1].Error, jc.ErrorIsNil) 237 c.Assert(results[1].Volume, jc.DeepEquals, &storage.Volume{ 238 names.NewVolumeTag("1"), 239 storage.VolumeInfo{ 240 Size: 20480, 241 VolumeId: "vol-1", 242 Persistent: true, 243 }, 244 }) 245 c.Assert(results[2].Error, jc.ErrorIsNil) 246 c.Assert(results[2].Volume, jc.DeepEquals, &storage.Volume{ 247 names.NewVolumeTag("2"), 248 storage.VolumeInfo{ 249 Size: 30720, 250 VolumeId: "vol-2", 251 Persistent: true, 252 }, 253 }) 254 ec2Client := ec2.StorageEC2(vs) 255 ec2Vols, err := ec2Client.Volumes(nil, nil) 256 c.Assert(err, jc.ErrorIsNil) 257 c.Assert(ec2Vols.Volumes, gc.HasLen, 3) 258 sortBySize(ec2Vols.Volumes) 259 c.Assert(ec2Vols.Volumes[0].Tags, jc.SameContents, []awsec2.Tag{ 260 {"juju-env-uuid", "deadbeef-0bad-400d-8000-4b1d0d06f00d"}, 261 {"Name", "juju-sample-volume-0"}, 262 }) 263 c.Assert(ec2Vols.Volumes[1].Tags, jc.SameContents, []awsec2.Tag{ 264 {"juju-env-uuid", "something-else"}, 265 {"Name", "juju-sample-volume-1"}, 266 }) 267 c.Assert(ec2Vols.Volumes[2].Tags, jc.SameContents, []awsec2.Tag{ 268 {"Name", "juju-sample-volume-2"}, 269 {"abc", "123"}, 270 }) 271 } 272 273 func (s *ebsVolumeSuite) TestVolumeTypeAliases(c *gc.C) { 274 instanceIdRunning := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Running, nil)[0] 275 vs := s.volumeSource(c, nil) 276 ec2Client := ec2.StorageEC2(vs) 277 aliases := [][2]string{ 278 {"magnetic", "standard"}, 279 {"ssd", "gp2"}, 280 {"provisioned-iops", "io1"}, 281 } 282 for i, alias := range aliases { 283 params := []storage.VolumeParams{{ 284 Tag: names.NewVolumeTag("0"), 285 Size: 10 * 1000, 286 Provider: ec2.EBS_ProviderType, 287 Attributes: map[string]interface{}{ 288 "volume-type": alias[0], 289 }, 290 Attachment: &storage.VolumeAttachmentParams{ 291 AttachmentParams: storage.AttachmentParams{ 292 InstanceId: instance.Id(instanceIdRunning), 293 }, 294 }, 295 }} 296 if alias[1] == "io1" { 297 params[0].Attributes["iops"] = 30 298 } 299 results, err := vs.CreateVolumes(params) 300 c.Assert(err, jc.ErrorIsNil) 301 c.Assert(results, gc.HasLen, 1) 302 c.Assert(results[0].Error, jc.ErrorIsNil) 303 c.Assert(results[0].Volume.VolumeId, gc.Equals, fmt.Sprintf("vol-%d", i)) 304 } 305 ec2Vols, err := ec2Client.Volumes(nil, nil) 306 c.Assert(err, jc.ErrorIsNil) 307 c.Assert(ec2Vols.Volumes, gc.HasLen, len(aliases)) 308 sort.Sort(volumeSorter{ec2Vols.Volumes, func(i, j awsec2.Volume) bool { 309 return i.Id < j.Id 310 }}) 311 for i, alias := range aliases { 312 c.Assert(ec2Vols.Volumes[i].VolumeType, gc.Equals, alias[1]) 313 } 314 } 315 316 func (s *ebsVolumeSuite) TestDestroyVolumes(c *gc.C) { 317 vs := s.volumeSource(c, nil) 318 params := s.setupAttachVolumesTest(c, vs, ec2test.Running) 319 errs, err := vs.DetachVolumes(params) 320 c.Assert(err, jc.ErrorIsNil) 321 c.Assert(errs, jc.DeepEquals, []error{nil}) 322 errs, err = vs.DestroyVolumes([]string{"vol-0"}) 323 c.Assert(err, jc.ErrorIsNil) 324 c.Assert(errs, jc.DeepEquals, []error{nil}) 325 326 ec2Client := ec2.StorageEC2(vs) 327 ec2Vols, err := ec2Client.Volumes(nil, nil) 328 c.Assert(err, jc.ErrorIsNil) 329 c.Assert(ec2Vols.Volumes, gc.HasLen, 2) 330 sortBySize(ec2Vols.Volumes) 331 c.Assert(ec2Vols.Volumes[0].Size, gc.Equals, 20) 332 } 333 334 func (s *ebsVolumeSuite) TestDestroyVolumesStillAttached(c *gc.C) { 335 vs := s.volumeSource(c, nil) 336 s.setupAttachVolumesTest(c, vs, ec2test.Running) 337 errs, err := vs.DestroyVolumes([]string{"vol-0"}) 338 c.Assert(err, jc.ErrorIsNil) 339 c.Assert(errs, jc.DeepEquals, []error{nil}) 340 341 ec2Client := ec2.StorageEC2(vs) 342 ec2Vols, err := ec2Client.Volumes(nil, nil) 343 c.Assert(err, jc.ErrorIsNil) 344 c.Assert(ec2Vols.Volumes, gc.HasLen, 2) 345 sortBySize(ec2Vols.Volumes) 346 c.Assert(ec2Vols.Volumes[0].Size, gc.Equals, 20) 347 } 348 349 func (s *ebsVolumeSuite) TestDescribeVolumes(c *gc.C) { 350 vs := s.volumeSource(c, nil) 351 s.assertCreateVolumes(c, vs, "") 352 353 vols, err := vs.DescribeVolumes([]string{"vol-0", "vol-1"}) 354 c.Assert(err, jc.ErrorIsNil) 355 c.Assert(vols, jc.DeepEquals, []storage.DescribeVolumesResult{{ 356 VolumeInfo: &storage.VolumeInfo{ 357 Size: 10240, 358 VolumeId: "vol-0", 359 Persistent: true, 360 }, 361 }, { 362 VolumeInfo: &storage.VolumeInfo{ 363 Size: 20480, 364 VolumeId: "vol-1", 365 Persistent: true, 366 }, 367 }}) 368 } 369 370 func (s *ebsVolumeSuite) TestDescribeVolumesNotFound(c *gc.C) { 371 vs := s.volumeSource(c, nil) 372 vols, err := vs.DescribeVolumes([]string{"vol-42"}) 373 c.Assert(err, jc.ErrorIsNil) 374 c.Assert(vols, gc.HasLen, 1) 375 c.Assert(vols[0].Error, gc.ErrorMatches, "vol-42 not found") 376 } 377 378 func (s *ebsVolumeSuite) TestListVolumes(c *gc.C) { 379 vs := s.volumeSource(c, nil) 380 s.assertCreateVolumes(c, vs, "") 381 382 // Only one volume created by assertCreateVolumes has 383 // the env-uuid tag with the expected value. 384 volIds, err := vs.ListVolumes() 385 c.Assert(err, jc.ErrorIsNil) 386 c.Assert(volIds, jc.SameContents, []string{"vol-0"}) 387 } 388 389 func (s *ebsVolumeSuite) TestCreateVolumesErrors(c *gc.C) { 390 vs := s.volumeSource(c, nil) 391 volume0 := names.NewVolumeTag("0") 392 393 instanceIdPending := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Pending, nil)[0] 394 instanceIdRunning := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Running, nil)[0] 395 attachmentParams := storage.VolumeAttachmentParams{ 396 AttachmentParams: storage.AttachmentParams{ 397 InstanceId: instance.Id(instanceIdRunning), 398 }, 399 } 400 401 for _, test := range []struct { 402 params storage.VolumeParams 403 err string 404 }{{ 405 params: storage.VolumeParams{ 406 Size: 1024, 407 Provider: ec2.EBS_ProviderType, 408 Attachment: &storage.VolumeAttachmentParams{ 409 AttachmentParams: storage.AttachmentParams{ 410 InstanceId: "woat", 411 }, 412 }, 413 }, 414 err: `querying instance details: instance "woat" not found \(InvalidInstanceID.NotFound\)`, 415 }, { 416 params: storage.VolumeParams{ 417 Size: 1024, 418 Provider: ec2.EBS_ProviderType, 419 Attachment: &storage.VolumeAttachmentParams{ 420 AttachmentParams: storage.AttachmentParams{ 421 InstanceId: instance.Id(instanceIdPending), 422 }, 423 }, 424 }, 425 err: "cannot attach to non-running instance i-3", 426 }, { 427 params: storage.VolumeParams{ 428 Size: 100000000, 429 Provider: ec2.EBS_ProviderType, 430 Attributes: map[string]interface{}{}, 431 Attachment: &attachmentParams, 432 }, 433 err: "volume size 97657 GiB exceeds the maximum of 1024 GiB", 434 }, { 435 params: storage.VolumeParams{ 436 Size: 100000000, 437 Provider: ec2.EBS_ProviderType, 438 Attributes: map[string]interface{}{ 439 "volume-type": "gp2", 440 }, 441 Attachment: &attachmentParams, 442 }, 443 err: "volume size 97657 GiB exceeds the maximum of 16384 GiB", 444 }, { 445 params: storage.VolumeParams{ 446 Size: 100000000, 447 Provider: ec2.EBS_ProviderType, 448 Attributes: map[string]interface{}{ 449 "volume-type": "io1", 450 "iops": "30", 451 }, 452 Attachment: &attachmentParams, 453 }, 454 err: "volume size 97657 GiB exceeds the maximum of 16384 GiB", 455 }, { 456 params: storage.VolumeParams{ 457 Tag: volume0, 458 Size: 1000, 459 Provider: ec2.EBS_ProviderType, 460 Attributes: map[string]interface{}{ 461 "volume-type": "io1", 462 "iops": "30", 463 }, 464 Attachment: &attachmentParams, 465 }, 466 err: "volume size is 1 GiB, must be at least 4 GiB", 467 }, { 468 params: storage.VolumeParams{ 469 Tag: volume0, 470 Size: 10000, 471 Provider: ec2.EBS_ProviderType, 472 Attributes: map[string]interface{}{ 473 "volume-type": "io1", 474 "iops": "1234", 475 }, 476 Attachment: &attachmentParams, 477 }, 478 err: "specified IOPS ratio is 1234/GiB, maximum is 30/GiB", 479 }, { 480 params: storage.VolumeParams{ 481 Tag: volume0, 482 Size: 10000, 483 Provider: ec2.EBS_ProviderType, 484 Attributes: map[string]interface{}{ 485 "volume-type": "standard", 486 "iops": "30", 487 }, 488 Attachment: &attachmentParams, 489 }, 490 err: `IOPS specified, but volume type is "standard"`, 491 }, { 492 params: storage.VolumeParams{ 493 Tag: volume0, 494 Size: 10000, 495 Provider: ec2.EBS_ProviderType, 496 Attributes: map[string]interface{}{ 497 "volume-type": "what", 498 }, 499 Attachment: &attachmentParams, 500 }, 501 err: "validating EBS storage config: volume-type: unexpected value \"what\"", 502 }} { 503 results, err := vs.CreateVolumes([]storage.VolumeParams{test.params}) 504 c.Assert(err, jc.ErrorIsNil) 505 c.Assert(results, gc.HasLen, 1) 506 c.Check(results[0].Error, gc.ErrorMatches, test.err) 507 } 508 } 509 510 var imageId = "ami-ccf405a5" // Ubuntu Maverick, i386, EBS store 511 512 func (s *ebsVolumeSuite) setupAttachVolumesTest( 513 c *gc.C, vs storage.VolumeSource, state awsec2.InstanceState, 514 ) []storage.VolumeAttachmentParams { 515 516 instanceId := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, state, nil)[0] 517 s.assertCreateVolumes(c, vs, instanceId) 518 519 return []storage.VolumeAttachmentParams{{ 520 Volume: names.NewVolumeTag("0"), 521 VolumeId: "vol-0", 522 AttachmentParams: storage.AttachmentParams{ 523 Machine: names.NewMachineTag("1"), 524 InstanceId: instance.Id(instanceId), 525 }, 526 }} 527 } 528 529 func (s *ebsVolumeSuite) TestAttachVolumesNotRunning(c *gc.C) { 530 vs := s.volumeSource(c, nil) 531 instanceId := s.srv.ec2srv.NewInstances(1, "m1.medium", imageId, ec2test.Pending, nil)[0] 532 results, err := s.createVolumes(vs, instanceId) 533 c.Assert(err, jc.ErrorIsNil) 534 c.Assert(results, gc.Not(gc.HasLen), 0) 535 for _, result := range results { 536 c.Check(errors.Cause(result.Error), gc.ErrorMatches, "cannot attach to non-running instance i-3") 537 } 538 } 539 540 func (s *ebsVolumeSuite) TestAttachVolumes(c *gc.C) { 541 vs := s.volumeSource(c, nil) 542 params := s.setupAttachVolumesTest(c, vs, ec2test.Running) 543 result, err := vs.AttachVolumes(params) 544 c.Assert(err, jc.ErrorIsNil) 545 c.Assert(result, gc.HasLen, 1) 546 c.Assert(result[0].Error, jc.ErrorIsNil) 547 c.Assert(result[0].VolumeAttachment, jc.DeepEquals, &storage.VolumeAttachment{ 548 names.NewVolumeTag("0"), 549 names.NewMachineTag("1"), 550 storage.VolumeAttachmentInfo{ 551 DeviceName: "xvdf", 552 ReadOnly: false, 553 }, 554 }) 555 556 ec2Client := ec2.StorageEC2(vs) 557 ec2Vols, err := ec2Client.Volumes(nil, nil) 558 c.Assert(err, jc.ErrorIsNil) 559 c.Assert(ec2Vols.Volumes, gc.HasLen, 3) 560 sortBySize(ec2Vols.Volumes) 561 c.Assert(ec2Vols.Volumes[0].Attachments, jc.DeepEquals, []awsec2.VolumeAttachment{{ 562 VolumeId: "vol-0", 563 InstanceId: "i-3", 564 Device: "/dev/sdf", 565 Status: "attached", 566 }}) 567 568 // Test idempotency. 569 result, err = vs.AttachVolumes(params) 570 c.Assert(err, jc.ErrorIsNil) 571 c.Assert(result, gc.HasLen, 1) 572 c.Assert(result[0].Error, jc.ErrorIsNil) 573 c.Assert(result[0].VolumeAttachment, jc.DeepEquals, &storage.VolumeAttachment{ 574 names.NewVolumeTag("0"), 575 names.NewMachineTag("1"), 576 storage.VolumeAttachmentInfo{ 577 DeviceName: "xvdf", 578 ReadOnly: false, 579 }, 580 }) 581 } 582 583 // TODO(axw) add tests for attempting to attach while 584 // a volume is still in the "creating" state. 585 586 func (s *ebsVolumeSuite) TestDetachVolumes(c *gc.C) { 587 vs := s.volumeSource(c, nil) 588 params := s.setupAttachVolumesTest(c, vs, ec2test.Running) 589 _, err := vs.AttachVolumes(params) 590 c.Assert(err, jc.ErrorIsNil) 591 errs, err := vs.DetachVolumes(params) 592 c.Assert(err, jc.ErrorIsNil) 593 c.Assert(errs, jc.DeepEquals, []error{nil}) 594 595 ec2Client := ec2.StorageEC2(vs) 596 ec2Vols, err := ec2Client.Volumes(nil, nil) 597 c.Assert(err, jc.ErrorIsNil) 598 c.Assert(ec2Vols.Volumes, gc.HasLen, 3) 599 sortBySize(ec2Vols.Volumes) 600 c.Assert(ec2Vols.Volumes[0].Attachments, gc.HasLen, 0) 601 602 // Test idempotent 603 errs, err = vs.DetachVolumes(params) 604 c.Assert(err, jc.ErrorIsNil) 605 c.Assert(errs, jc.DeepEquals, []error{nil}) 606 } 607 608 type blockDeviceMappingSuite struct { 609 testing.BaseSuite 610 } 611 612 var _ = gc.Suite(&blockDeviceMappingSuite{}) 613 614 func (*blockDeviceMappingSuite) TestBlockDeviceNamer(c *gc.C) { 615 var nextName func() (string, string, error) 616 expect := func(expectRequest, expectActual string) { 617 request, actual, err := nextName() 618 c.Assert(err, jc.ErrorIsNil) 619 c.Assert(request, gc.Equals, expectRequest) 620 c.Assert(actual, gc.Equals, expectActual) 621 } 622 expectN := func(expectRequest, expectActual string) { 623 for i := 1; i <= 6; i++ { 624 request, actual, err := nextName() 625 c.Assert(err, jc.ErrorIsNil) 626 c.Assert(request, gc.Equals, expectRequest+strconv.Itoa(i)) 627 c.Assert(actual, gc.Equals, expectActual+strconv.Itoa(i)) 628 } 629 } 630 expectErr := func(expectErr string) { 631 _, _, err := nextName() 632 c.Assert(err, gc.ErrorMatches, expectErr) 633 } 634 635 // First without numbers. 636 nextName = ec2.BlockDeviceNamer(false) 637 expect("/dev/sdf", "xvdf") 638 expect("/dev/sdg", "xvdg") 639 expect("/dev/sdh", "xvdh") 640 expect("/dev/sdi", "xvdi") 641 expect("/dev/sdj", "xvdj") 642 expect("/dev/sdk", "xvdk") 643 expect("/dev/sdl", "xvdl") 644 expect("/dev/sdm", "xvdm") 645 expect("/dev/sdn", "xvdn") 646 expect("/dev/sdo", "xvdo") 647 expect("/dev/sdp", "xvdp") 648 expectErr("too many EBS volumes to attach") 649 650 // Now with numbers. 651 nextName = ec2.BlockDeviceNamer(true) 652 expect("/dev/sdf1", "xvdf1") 653 expect("/dev/sdf2", "xvdf2") 654 expect("/dev/sdf3", "xvdf3") 655 expect("/dev/sdf4", "xvdf4") 656 expect("/dev/sdf5", "xvdf5") 657 expect("/dev/sdf6", "xvdf6") 658 expectN("/dev/sdg", "xvdg") 659 expectN("/dev/sdh", "xvdh") 660 expectN("/dev/sdi", "xvdi") 661 expectN("/dev/sdj", "xvdj") 662 expectN("/dev/sdk", "xvdk") 663 expectN("/dev/sdl", "xvdl") 664 expectN("/dev/sdm", "xvdm") 665 expectN("/dev/sdn", "xvdn") 666 expectN("/dev/sdo", "xvdo") 667 expectN("/dev/sdp", "xvdp") 668 expectErr("too many EBS volumes to attach") 669 } 670 671 func (*blockDeviceMappingSuite) TestGetBlockDeviceMappings(c *gc.C) { 672 mapping, err := ec2.GetBlockDeviceMappings(constraints.Value{}) 673 c.Assert(err, jc.ErrorIsNil) 674 c.Assert(mapping, gc.DeepEquals, []awsec2.BlockDeviceMapping{{ 675 VolumeSize: 8, 676 DeviceName: "/dev/sda1", 677 }, { 678 VirtualName: "ephemeral0", 679 DeviceName: "/dev/sdb", 680 }, { 681 VirtualName: "ephemeral1", 682 DeviceName: "/dev/sdc", 683 }, { 684 VirtualName: "ephemeral2", 685 DeviceName: "/dev/sdd", 686 }, { 687 VirtualName: "ephemeral3", 688 DeviceName: "/dev/sde", 689 }}) 690 }