github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/azure/disks_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azure 5 6 import ( 7 "encoding/xml" 8 "fmt" 9 "net/http" 10 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 "launchpad.net/gwacl" 15 16 "github.com/juju/juju/storage" 17 "github.com/juju/juju/testing" 18 ) 19 20 var mediaLinkPrefix = fmt.Sprintf( 21 "https://account-name.blob.core.windows.net/vhds/%s/", 22 testing.EnvironmentTag.Id(), 23 ) 24 25 type storageProviderSuite struct { 26 testing.BaseSuite 27 } 28 29 var _ = gc.Suite(&storageSuite{}) 30 31 func (*storageProviderSuite) TestValidateConfigUnknownConfig(c *gc.C) { 32 p := azureStorageProvider{} 33 cfg, err := storage.NewConfig("foo", storageProviderType, map[string]interface{}{ 34 "unknown": "config", 35 }) 36 c.Assert(err, jc.ErrorIsNil) 37 err = p.ValidateConfig(cfg) 38 c.Assert(err, jc.ErrorIsNil) // unknown attrs ignored 39 } 40 41 func (s *storageProviderSuite) TestSupports(c *gc.C) { 42 p := azureStorageProvider{} 43 c.Assert(p.Supports(storage.StorageKindBlock), jc.IsTrue) 44 c.Assert(p.Supports(storage.StorageKindFilesystem), jc.IsFalse) 45 } 46 47 var _ = gc.Suite(&azureVolumeSuite{}) 48 49 type azureVolumeSuite struct { 50 testing.BaseSuite 51 } 52 53 func (s *azureVolumeSuite) volumeSource(c *gc.C, cfg *storage.Config) storage.VolumeSource { 54 envCfg := makeEnviron(c).Config() 55 p := azureStorageProvider{} 56 vs, err := p.VolumeSource(envCfg, cfg) 57 c.Assert(err, jc.ErrorIsNil) 58 return vs 59 } 60 61 func (s *azureVolumeSuite) TestCreateVolumes(c *gc.C) { 62 vs := s.volumeSource(c, nil) 63 64 machine := names.NewMachineTag("123") 65 volume0 := names.NewVolumeTag("0") 66 volume1 := names.NewVolumeTag("1") 67 68 env := makeEnviron(c) 69 prefix := env.getEnvPrefix() 70 serviceName := "service" 71 service := makeDeployment(c, env, prefix+serviceName) 72 73 roleName := service.Deployments[0].RoleList[0].RoleName 74 inst, err := env.getInstance(service, roleName) 75 c.Assert(err, jc.ErrorIsNil) 76 77 params := []storage.VolumeParams{{ 78 Tag: volume0, 79 Size: 10 * 1000, 80 Provider: storageProviderType, 81 Attachment: &storage.VolumeAttachmentParams{ 82 AttachmentParams: storage.AttachmentParams{ 83 Machine: machine, 84 InstanceId: inst.Id(), 85 }, 86 }, 87 }, { 88 Tag: volume1, 89 Size: 20 * 1000, 90 Provider: storageProviderType, 91 Attachment: &storage.VolumeAttachmentParams{ 92 AttachmentParams: storage.AttachmentParams{ 93 Machine: machine, 94 InstanceId: inst.Id(), 95 }, 96 }, 97 }} 98 99 getRoleResponse0, err := xml.Marshal(&gwacl.PersistentVMRole{}) 100 c.Assert(err, jc.ErrorIsNil) 101 102 // Second time, respond saying LUN 0 is in use; this should 103 // cause LUN 1 to be assigned. 104 dataVirtualHardDisks := []gwacl.DataVirtualHardDisk{ 105 {LUN: 0}, 106 } 107 getRoleResponse1, err := xml.Marshal(&gwacl.PersistentVMRole{ 108 DataVirtualHardDisks: &dataVirtualHardDisks, 109 }) 110 c.Assert(err, jc.ErrorIsNil) 111 112 gwacl.PatchManagementAPIResponses([]gwacl.DispatcherResponse{ 113 gwacl.NewDispatcherResponse(getRoleResponse0, http.StatusOK, nil), 114 gwacl.NewDispatcherResponse(nil, http.StatusOK, nil), // AddDataDisk 115 gwacl.NewDispatcherResponse(getRoleResponse1, http.StatusOK, nil), 116 gwacl.NewDispatcherResponse(nil, http.StatusOK, nil), // AddDataDisk 117 }) 118 119 results, err := vs.CreateVolumes(params) 120 c.Assert(err, jc.ErrorIsNil) 121 122 c.Assert(results, gc.HasLen, 2) 123 c.Assert(results[0], jc.DeepEquals, storage.CreateVolumesResult{ 124 Volume: &storage.Volume{ 125 Tag: volume0, 126 VolumeInfo: storage.VolumeInfo{ 127 VolumeId: "volume-0.vhd", 128 Size: 10 * 1024, // rounded up 129 }, 130 }, 131 VolumeAttachment: &storage.VolumeAttachment{ 132 Volume: volume0, 133 Machine: machine, 134 VolumeAttachmentInfo: storage.VolumeAttachmentInfo{ 135 BusAddress: "scsi@5:0.0.0", 136 }, 137 }}, 138 ) 139 c.Assert(results[1], jc.DeepEquals, storage.CreateVolumesResult{ 140 Volume: &storage.Volume{ 141 Tag: volume1, 142 VolumeInfo: storage.VolumeInfo{ 143 VolumeId: "volume-1.vhd", 144 Size: 20 * 1024, // rounded up 145 }, 146 }, 147 VolumeAttachment: &storage.VolumeAttachment{ 148 Volume: volume1, 149 Machine: machine, 150 VolumeAttachmentInfo: storage.VolumeAttachmentInfo{ 151 BusAddress: "scsi@5:0.0.1", 152 }, 153 }}, 154 ) 155 } 156 157 func (s *azureVolumeSuite) TestCreateVolumesInvalidVolumeParams(c *gc.C) { 158 vs := s.volumeSource(c, nil) 159 160 args := storage.VolumeParams{ 161 Tag: names.NewVolumeTag("0"), 162 Size: 1023 * 1024, 163 Provider: storageProviderType, 164 } 165 err := vs.ValidateVolumeParams(args) 166 c.Assert(err, jc.ErrorIsNil) 167 168 args.Size++ // One more MiB and we're out 169 170 results, err := vs.CreateVolumes([]storage.VolumeParams{args}) 171 c.Assert(err, jc.ErrorIsNil) 172 c.Assert(results[0].Error, gc.ErrorMatches, "1024 GiB exceeds the maximum of 1023 GiB") 173 } 174 175 func (s *azureVolumeSuite) TestCreateVolumesNoLuns(c *gc.C) { 176 vs := s.volumeSource(c, nil) 177 178 machine := names.NewMachineTag("123") 179 volume := names.NewVolumeTag("0") 180 181 env := makeEnviron(c) 182 prefix := env.getEnvPrefix() 183 serviceName := "service" 184 service := makeDeployment(c, env, prefix+serviceName) 185 roleName := service.Deployments[0].RoleList[0].RoleName 186 inst, err := env.getInstance(service, roleName) 187 c.Assert(err, jc.ErrorIsNil) 188 189 params := []storage.VolumeParams{{ 190 Tag: volume, 191 Size: 10 * 1000, 192 Provider: storageProviderType, 193 Attachment: &storage.VolumeAttachmentParams{ 194 AttachmentParams: storage.AttachmentParams{ 195 Machine: machine, 196 InstanceId: inst.Id(), 197 }, 198 }, 199 }} 200 201 dataVirtualHardDisks := make([]gwacl.DataVirtualHardDisk, 32) 202 for i := range dataVirtualHardDisks { 203 dataVirtualHardDisks[i].LUN = i 204 } 205 getRoleResponse, err := xml.Marshal(&gwacl.PersistentVMRole{ 206 DataVirtualHardDisks: &dataVirtualHardDisks, 207 }) 208 c.Assert(err, jc.ErrorIsNil) 209 210 gwacl.PatchManagementAPIResponses([]gwacl.DispatcherResponse{ 211 gwacl.NewDispatcherResponse(getRoleResponse, http.StatusOK, nil), 212 }) 213 214 results, err := vs.CreateVolumes(params) 215 c.Assert(err, jc.ErrorIsNil) 216 c.Assert(results, gc.HasLen, 1) 217 c.Assert(results[0].Error, gc.ErrorMatches, "choosing LUN: all LUNs are in use") 218 } 219 220 func (s *azureVolumeSuite) TestCreateVolumesLegacyInstance(c *gc.C) { 221 vs := s.volumeSource(c, nil) 222 223 machine := names.NewMachineTag("123") 224 volume := names.NewVolumeTag("0") 225 226 env := makeEnviron(c) 227 prefix := env.getEnvPrefix() 228 serviceName := "service" 229 service := makeLegacyDeployment(c, env, prefix+serviceName) 230 inst, err := env.getInstance(service, "") 231 c.Assert(err, jc.ErrorIsNil) 232 233 params := []storage.VolumeParams{{ 234 Tag: volume, 235 Size: 10 * 1000, 236 Provider: storageProviderType, 237 Attachment: &storage.VolumeAttachmentParams{ 238 AttachmentParams: storage.AttachmentParams{ 239 Machine: machine, 240 InstanceId: inst.Id(), 241 }, 242 }, 243 }} 244 245 results, err := vs.CreateVolumes(params) 246 c.Assert(err, jc.ErrorIsNil) 247 248 c.Assert(results, gc.HasLen, 1) 249 c.Assert(results[0].Error, gc.ErrorMatches, "attaching disks to legacy instances not supported") 250 } 251 252 func (s *azureVolumeSuite) TestDestroyVolumes(c *gc.C) { 253 vs := s.volumeSource(c, nil) 254 results, err := vs.DestroyVolumes([]string{"volume-0.vhd", "volume-1.vhd"}) 255 c.Assert(err, gc.ErrorMatches, "DestroyVolumes not supported") 256 c.Assert(results, gc.HasLen, 0) 257 } 258 259 func (s *azureVolumeSuite) TestDescribeVolumes(c *gc.C) { 260 vs := s.volumeSource(c, nil) 261 262 type disks struct { 263 Disks []gwacl.Disk `xml:"Disk"` 264 } 265 266 listDisksResponse, err := xml.Marshal(&disks{Disks: []gwacl.Disk{{ 267 MediaLink: mediaLinkPrefix + "volume-1.vhd", 268 LogicalSizeInGB: 22, 269 }, { 270 MediaLink: mediaLinkPrefix + "volume-0.vhd", 271 LogicalSizeInGB: 11, 272 }, { 273 MediaLink: "someOtherJunk.vhd", 274 LogicalSizeInGB: 33, 275 }}}) 276 c.Assert(err, jc.ErrorIsNil) 277 278 gwacl.PatchManagementAPIResponses([]gwacl.DispatcherResponse{ 279 gwacl.NewDispatcherResponse(listDisksResponse, http.StatusOK, nil), 280 }) 281 282 volumes, err := vs.DescribeVolumes([]string{"volume-0.vhd", "volume-1.vhd"}) 283 c.Assert(err, jc.ErrorIsNil) 284 c.Assert(volumes, gc.HasLen, 2) 285 c.Assert(volumes, jc.DeepEquals, []storage.DescribeVolumesResult{{ 286 VolumeInfo: &storage.VolumeInfo{ 287 Size: 11 * 1024, 288 VolumeId: "volume-0.vhd", 289 }, 290 }, { 291 VolumeInfo: &storage.VolumeInfo{ 292 Size: 22 * 1024, 293 VolumeId: "volume-1.vhd", 294 }, 295 }}) 296 } 297 298 func (s *azureVolumeSuite) TestDescribeVolumesNotFound(c *gc.C) { 299 vs := s.volumeSource(c, nil) 300 301 type disks struct { 302 Disks []gwacl.Disk `xml:"Disk"` 303 } 304 305 listDisksResponse, err := xml.Marshal(&disks{Disks: []gwacl.Disk{{ 306 MediaLink: mediaLinkPrefix + "volume-0.vhd", 307 LogicalSizeInGB: 11, 308 }}}) 309 c.Assert(err, jc.ErrorIsNil) 310 311 gwacl.PatchManagementAPIResponses([]gwacl.DispatcherResponse{ 312 gwacl.NewDispatcherResponse(listDisksResponse, http.StatusOK, nil), 313 }) 314 315 volumes, err := vs.DescribeVolumes([]string{"volume-0.vhd", "volume-1.vhd"}) 316 c.Assert(err, jc.ErrorIsNil) 317 c.Assert(volumes, gc.HasLen, 2) 318 c.Assert(volumes[0].Error, gc.IsNil) 319 c.Assert(volumes[1].Error, gc.ErrorMatches, "volume volume-1.vhd not found") 320 } 321 322 func (s *azureVolumeSuite) TestListVolumes(c *gc.C) { 323 vs := s.volumeSource(c, nil) 324 325 type disks struct { 326 Disks []gwacl.Disk `xml:"Disk"` 327 } 328 329 listDisksResponse, err := xml.Marshal(&disks{Disks: []gwacl.Disk{{ 330 MediaLink: mediaLinkPrefix + "volume-1.vhd", 331 LogicalSizeInGB: 22, 332 }, { 333 MediaLink: mediaLinkPrefix + "volume-0.vhd", 334 LogicalSizeInGB: 11, 335 }, { 336 MediaLink: "someOtherJunk.vhd", 337 LogicalSizeInGB: 33, 338 }}}) 339 c.Assert(err, jc.ErrorIsNil) 340 341 gwacl.PatchManagementAPIResponses([]gwacl.DispatcherResponse{ 342 gwacl.NewDispatcherResponse(listDisksResponse, http.StatusOK, nil), 343 }) 344 345 volIds, err := vs.ListVolumes() 346 c.Assert(err, jc.ErrorIsNil) 347 c.Assert(volIds, jc.SameContents, []string{"volume-0.vhd", "volume-1.vhd"}) 348 } 349 350 func (s *azureVolumeSuite) TestAttachVolumesAlreadyAttached(c *gc.C) { 351 vs := s.volumeSource(c, nil) 352 353 machine0 := names.NewMachineTag("0") 354 machine1 := names.NewMachineTag("1") 355 volume0 := names.NewVolumeTag("0") 356 volume1 := names.NewVolumeTag("1") 357 volume2 := names.NewVolumeTag("2") 358 359 env := makeEnviron(c) 360 prefix := env.getEnvPrefix() 361 service := makeDeployment(c, env, prefix+"service") 362 roleName0 := service.Deployments[0].RoleList[0].RoleName 363 roleName1 := service.Deployments[0].RoleList[1].RoleName 364 inst0, err := env.getInstance(service, roleName0) 365 c.Assert(err, jc.ErrorIsNil) 366 inst1, err := env.getInstance(service, roleName1) 367 c.Assert(err, jc.ErrorIsNil) 368 369 // First VM. 370 dataVirtualHardDisks0 := []gwacl.DataVirtualHardDisk{{ 371 MediaLink: mediaLinkPrefix + "volume-0.vhd", 372 LUN: 0, 373 LogicalDiskSizeInGB: 1, 374 }, { 375 MediaLink: mediaLinkPrefix + "volume-1.vhd", 376 LUN: 1, 377 LogicalDiskSizeInGB: 2, 378 }} 379 getRoleResponse0, err := xml.Marshal(&gwacl.PersistentVMRole{ 380 DataVirtualHardDisks: &dataVirtualHardDisks0, 381 }) 382 c.Assert(err, jc.ErrorIsNil) 383 384 // Second VM. 385 dataVirtualHardDisks1 := []gwacl.DataVirtualHardDisk{{ 386 MediaLink: mediaLinkPrefix + "volume-2.vhd", 387 LUN: 0, 388 LogicalDiskSizeInGB: 3, 389 }} 390 getRoleResponse1, err := xml.Marshal(&gwacl.PersistentVMRole{ 391 DataVirtualHardDisks: &dataVirtualHardDisks1, 392 }) 393 c.Assert(err, jc.ErrorIsNil) 394 395 gwacl.PatchManagementAPIResponses([]gwacl.DispatcherResponse{ 396 gwacl.NewDispatcherResponse(getRoleResponse0, http.StatusOK, nil), 397 gwacl.NewDispatcherResponse(getRoleResponse1, http.StatusOK, nil), 398 }) 399 400 results, err := vs.AttachVolumes([]storage.VolumeAttachmentParams{{ 401 Volume: volume0, 402 VolumeId: "volume-0.vhd", 403 AttachmentParams: storage.AttachmentParams{ 404 Machine: machine0, 405 InstanceId: inst0.Id(), 406 }, 407 }, { 408 Volume: volume1, 409 VolumeId: "volume-1.vhd", 410 AttachmentParams: storage.AttachmentParams{ 411 Machine: machine0, 412 InstanceId: inst0.Id(), 413 }, 414 }, { 415 Volume: volume2, 416 VolumeId: "volume-2.vhd", 417 AttachmentParams: storage.AttachmentParams{ 418 Machine: machine1, 419 InstanceId: inst1.Id(), 420 }, 421 }}) 422 c.Assert(err, jc.ErrorIsNil) 423 c.Assert(results, jc.DeepEquals, []storage.AttachVolumesResult{{ 424 VolumeAttachment: &storage.VolumeAttachment{ 425 Volume: volume0, 426 Machine: machine0, 427 VolumeAttachmentInfo: storage.VolumeAttachmentInfo{ 428 BusAddress: "scsi@5:0.0.0", 429 }, 430 }, 431 }, { 432 VolumeAttachment: &storage.VolumeAttachment{ 433 Volume: volume1, 434 Machine: machine0, 435 VolumeAttachmentInfo: storage.VolumeAttachmentInfo{ 436 BusAddress: "scsi@5:0.0.1", 437 }, 438 }, 439 }, { 440 VolumeAttachment: &storage.VolumeAttachment{ 441 Volume: volume2, 442 Machine: machine1, 443 VolumeAttachmentInfo: storage.VolumeAttachmentInfo{ 444 BusAddress: "scsi@5:0.0.0", 445 }, 446 }, 447 }}) 448 } 449 450 func (s *azureVolumeSuite) TestAttachVolumesNotAttached(c *gc.C) { 451 vs := s.volumeSource(c, nil) 452 453 machine := names.NewMachineTag("0") 454 volume := names.NewVolumeTag("0") 455 456 env := makeEnviron(c) 457 prefix := env.getEnvPrefix() 458 service := makeDeployment(c, env, prefix+"service") 459 roleName := service.Deployments[0].RoleList[0].RoleName 460 inst, err := env.getInstance(service, roleName) 461 c.Assert(err, jc.ErrorIsNil) 462 463 getRoleResponse, err := xml.Marshal(&gwacl.PersistentVMRole{}) 464 c.Assert(err, jc.ErrorIsNil) 465 466 gwacl.PatchManagementAPIResponses([]gwacl.DispatcherResponse{ 467 gwacl.NewDispatcherResponse(getRoleResponse, http.StatusOK, nil), 468 }) 469 470 results, err := vs.AttachVolumes([]storage.VolumeAttachmentParams{{ 471 Volume: volume, 472 VolumeId: "volume-0.vhd", 473 AttachmentParams: storage.AttachmentParams{ 474 Machine: machine, 475 InstanceId: inst.Id(), 476 }, 477 }}) 478 c.Assert(err, jc.ErrorIsNil) 479 c.Assert(results, gc.HasLen, 1) 480 c.Assert(results[0].Error, gc.ErrorMatches, "attaching volumes not supported") 481 } 482 483 func (s *azureVolumeSuite) TestAttachVolumesGetRoleError(c *gc.C) { 484 vs := s.volumeSource(c, nil) 485 486 machine := names.NewMachineTag("0") 487 volume := names.NewVolumeTag("0") 488 489 env := makeEnviron(c) 490 prefix := env.getEnvPrefix() 491 service := makeLegacyDeployment(c, env, prefix+"service") 492 inst, err := env.getInstance(service, "") 493 c.Assert(err, jc.ErrorIsNil) 494 495 results, err := vs.AttachVolumes([]storage.VolumeAttachmentParams{{ 496 Volume: volume, 497 VolumeId: "volume-0.vhd", 498 AttachmentParams: storage.AttachmentParams{ 499 Machine: machine, 500 InstanceId: inst.Id(), 501 }, 502 }}) 503 c.Assert(err, jc.ErrorIsNil) 504 c.Assert(results, gc.HasLen, 1) 505 c.Assert(results[0].Error, gc.ErrorMatches, "attaching disks to legacy instances not supported") 506 } 507 508 func (s *azureVolumeSuite) TestDetachVolumes(c *gc.C) { 509 vs := s.volumeSource(c, nil) 510 _, err := vs.DetachVolumes([]storage.VolumeAttachmentParams{{}}) 511 c.Assert(err, gc.ErrorMatches, "detaching volumes not supported") 512 }