github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/azure/storage_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azure_test 5 6 import ( 7 "fmt" 8 "net/http" 9 10 "github.com/Azure/azure-sdk-for-go/Godeps/_workspace/src/github.com/Azure/go-autorest/autorest/to" 11 "github.com/Azure/azure-sdk-for-go/arm/compute" 12 "github.com/Azure/azure-sdk-for-go/arm/network" 13 azurestorage "github.com/Azure/azure-sdk-for-go/storage" 14 "github.com/juju/errors" 15 "github.com/juju/names" 16 jc "github.com/juju/testing/checkers" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/instance" 20 "github.com/juju/juju/provider/azure" 21 "github.com/juju/juju/provider/azure/internal/azuretesting" 22 "github.com/juju/juju/storage" 23 "github.com/juju/juju/testing" 24 ) 25 26 type storageSuite struct { 27 testing.BaseSuite 28 29 storageClient azuretesting.MockStorageClient 30 provider storage.Provider 31 requests []*http.Request 32 sender azuretesting.Senders 33 } 34 35 var _ = gc.Suite(&storageSuite{}) 36 37 func (s *storageSuite) SetUpTest(c *gc.C) { 38 s.BaseSuite.SetUpTest(c) 39 s.storageClient = azuretesting.MockStorageClient{} 40 s.requests = nil 41 _, s.provider = newProviders(c, azure.ProviderConfig{ 42 Sender: &s.sender, 43 NewStorageClient: s.storageClient.NewClient, 44 RequestInspector: requestRecorder(&s.requests), 45 }) 46 s.sender = nil 47 } 48 49 func (s *storageSuite) volumeSource(c *gc.C, attrs ...testing.Attrs) storage.VolumeSource { 50 storageConfig, err := storage.NewConfig("azure", "azure", nil) 51 c.Assert(err, jc.ErrorIsNil) 52 53 attrs = append([]testing.Attrs{{ 54 "storage-account": fakeStorageAccount, 55 "storage-account-key": fakeStorageAccountKey, 56 }}, attrs...) 57 cfg := makeTestModelConfig(c, attrs...) 58 volumeSource, err := s.provider.VolumeSource(cfg, storageConfig) 59 c.Assert(err, jc.ErrorIsNil) 60 61 // Force an explicit refresh of the access token, so it isn't done 62 // implicitly during the tests. 63 s.sender = azuretesting.Senders{tokenRefreshSender()} 64 err = azure.ForceVolumeSourceTokenRefresh(volumeSource) 65 c.Assert(err, jc.ErrorIsNil) 66 return volumeSource 67 } 68 69 func (s *storageSuite) TestVolumeSource(c *gc.C) { 70 vs := s.volumeSource(c) 71 c.Assert(vs, gc.NotNil) 72 } 73 74 func (s *storageSuite) TestFilesystemSource(c *gc.C) { 75 storageConfig, err := storage.NewConfig("azure", "azure", nil) 76 c.Assert(err, jc.ErrorIsNil) 77 78 cfg := makeTestModelConfig(c) 79 _, err = s.provider.FilesystemSource(cfg, storageConfig) 80 c.Assert(err, gc.ErrorMatches, "filesystems not supported") 81 c.Assert(err, jc.Satisfies, errors.IsNotSupported) 82 } 83 84 func (s *storageSuite) TestSupports(c *gc.C) { 85 c.Assert(s.provider.Supports(storage.StorageKindBlock), jc.IsTrue) 86 c.Assert(s.provider.Supports(storage.StorageKindFilesystem), jc.IsFalse) 87 } 88 89 func (s *storageSuite) TestDynamic(c *gc.C) { 90 c.Assert(s.provider.Dynamic(), jc.IsTrue) 91 } 92 93 func (s *storageSuite) TestScope(c *gc.C) { 94 c.Assert(s.provider.Scope(), gc.Equals, storage.ScopeEnviron) 95 } 96 97 func (s *storageSuite) TestCreateVolumes(c *gc.C) { 98 // machine-1 has a single data disk with LUN 0. 99 machine1DataDisks := []compute.DataDisk{{Lun: to.IntPtr(0)}} 100 // machine-2 has 32 data disks; no LUNs free. 101 machine2DataDisks := make([]compute.DataDisk, 32) 102 for i := range machine2DataDisks { 103 machine2DataDisks[i].Lun = to.IntPtr(i) 104 } 105 106 // volume-0 and volume-2 are attached to machine-0 107 // volume-1 is attached to machine-1 108 // volume-3 is attached to machine-42, but machine-42 is missing 109 // volume-42 is attached to machine-2, but machine-2 has no free LUNs 110 makeVolumeParams := func(volume, machine string, size uint64) storage.VolumeParams { 111 return storage.VolumeParams{ 112 Tag: names.NewVolumeTag(volume), 113 Size: size, 114 Provider: "azure", 115 Attachment: &storage.VolumeAttachmentParams{ 116 AttachmentParams: storage.AttachmentParams{ 117 Provider: "azure", 118 Machine: names.NewMachineTag(machine), 119 InstanceId: instance.Id("machine-" + machine), 120 }, 121 Volume: names.NewVolumeTag(volume), 122 }, 123 } 124 } 125 params := []storage.VolumeParams{ 126 makeVolumeParams("0", "0", 1), 127 makeVolumeParams("1", "1", 1025), 128 makeVolumeParams("2", "0", 1024), 129 makeVolumeParams("3", "42", 40), 130 makeVolumeParams("42", "2", 50), 131 } 132 133 virtualMachines := []compute.VirtualMachine{{ 134 Name: to.StringPtr("machine-0"), 135 Properties: &compute.VirtualMachineProperties{ 136 StorageProfile: &compute.StorageProfile{}, 137 }, 138 }, { 139 Name: to.StringPtr("machine-1"), 140 Properties: &compute.VirtualMachineProperties{ 141 StorageProfile: &compute.StorageProfile{DataDisks: &machine1DataDisks}, 142 }, 143 }, { 144 Name: to.StringPtr("machine-2"), 145 Properties: &compute.VirtualMachineProperties{ 146 StorageProfile: &compute.StorageProfile{DataDisks: &machine2DataDisks}, 147 }, 148 }} 149 150 // There should be a couple of API calls to list instances, 151 // and one update per modified instance. 152 nics := []network.Interface{ 153 makeNetworkInterface("nic-0", "machine-0"), 154 makeNetworkInterface("nic-1", "machine-1"), 155 makeNetworkInterface("nic-2", "machine-2"), 156 } 157 nicsSender := azuretesting.NewSenderWithValue(network.InterfaceListResult{ 158 Value: &nics, 159 }) 160 nicsSender.PathPattern = `.*/Microsoft\.Network/networkInterfaces` 161 virtualMachinesSender := azuretesting.NewSenderWithValue(compute.VirtualMachineListResult{ 162 Value: &virtualMachines, 163 }) 164 virtualMachinesSender.PathPattern = `.*/Microsoft\.Compute/virtualMachines` 165 updateVirtualMachine0Sender := azuretesting.NewSenderWithValue(&compute.VirtualMachine{}) 166 updateVirtualMachine0Sender.PathPattern = `.*/Microsoft\.Compute/virtualMachines/machine-0` 167 updateVirtualMachine1Sender := azuretesting.NewSenderWithValue(&compute.VirtualMachine{}) 168 updateVirtualMachine1Sender.PathPattern = `.*/Microsoft\.Compute/virtualMachines/machine-1` 169 volumeSource := s.volumeSource(c) 170 s.sender = azuretesting.Senders{ 171 nicsSender, 172 virtualMachinesSender, 173 updateVirtualMachine0Sender, 174 updateVirtualMachine1Sender, 175 } 176 177 results, err := volumeSource.CreateVolumes(params) 178 c.Assert(err, jc.ErrorIsNil) 179 c.Assert(results, gc.HasLen, len(params)) 180 181 c.Check(results[0].Error, jc.ErrorIsNil) 182 c.Check(results[1].Error, jc.ErrorIsNil) 183 c.Check(results[2].Error, jc.ErrorIsNil) 184 c.Check(results[3].Error, gc.ErrorMatches, "instance machine-42 not found") 185 c.Check(results[4].Error, gc.ErrorMatches, "choosing LUN: all LUNs are in use") 186 187 // Validate HTTP request bodies. 188 c.Assert(s.requests, gc.HasLen, 4) 189 c.Assert(s.requests[0].Method, gc.Equals, "GET") // list NICs 190 c.Assert(s.requests[1].Method, gc.Equals, "GET") // list virtual machines 191 c.Assert(s.requests[2].Method, gc.Equals, "PUT") // update machine-0 192 c.Assert(s.requests[3].Method, gc.Equals, "PUT") // update machine-1 193 194 machine0DataDisks := []compute.DataDisk{{ 195 Lun: to.IntPtr(0), 196 DiskSizeGB: to.IntPtr(1), 197 Name: to.StringPtr("volume-0"), 198 Vhd: &compute.VirtualHardDisk{URI: to.StringPtr(fmt.Sprintf( 199 "https://%s.blob.storage.azurestack.local/datavhds/volume-0.vhd", 200 fakeStorageAccount, 201 ))}, 202 Caching: compute.ReadWrite, 203 CreateOption: compute.Empty, 204 }, { 205 Lun: to.IntPtr(1), 206 DiskSizeGB: to.IntPtr(1), 207 Name: to.StringPtr("volume-2"), 208 Vhd: &compute.VirtualHardDisk{URI: to.StringPtr(fmt.Sprintf( 209 "https://%s.blob.storage.azurestack.local/datavhds/volume-2.vhd", 210 fakeStorageAccount, 211 ))}, 212 Caching: compute.ReadWrite, 213 CreateOption: compute.Empty, 214 }} 215 virtualMachines[0].Properties.StorageProfile.DataDisks = &machine0DataDisks 216 assertRequestBody(c, s.requests[2], &virtualMachines[0]) 217 218 machine1DataDisks = append(machine1DataDisks, compute.DataDisk{ 219 Lun: to.IntPtr(1), 220 DiskSizeGB: to.IntPtr(2), 221 Name: to.StringPtr("volume-1"), 222 Vhd: &compute.VirtualHardDisk{URI: to.StringPtr(fmt.Sprintf( 223 "https://%s.blob.storage.azurestack.local/datavhds/volume-1.vhd", 224 fakeStorageAccount, 225 ))}, 226 Caching: compute.ReadWrite, 227 CreateOption: compute.Empty, 228 }) 229 assertRequestBody(c, s.requests[3], &virtualMachines[1]) 230 } 231 232 func (s *storageSuite) TestListVolumes(c *gc.C) { 233 s.storageClient.ListBlobsFunc = func( 234 container string, 235 params azurestorage.ListBlobsParameters, 236 ) (azurestorage.BlobListResponse, error) { 237 return azurestorage.BlobListResponse{ 238 Blobs: []azurestorage.Blob{{ 239 Name: "volume-1.vhd", 240 Properties: azurestorage.BlobProperties{ 241 ContentLength: 1024 * 1024, // 1MiB 242 }, 243 }, { 244 Name: "volume-0.vhd", 245 Properties: azurestorage.BlobProperties{ 246 ContentLength: 1024 * 1024 * 1024 * 1024, // 1TiB 247 }, 248 }, { 249 Name: "junk.vhd", 250 }, { 251 Name: "volume", 252 }}, 253 }, nil 254 } 255 256 volumeSource := s.volumeSource(c) 257 volumeIds, err := volumeSource.ListVolumes() 258 c.Assert(err, jc.ErrorIsNil) 259 s.storageClient.CheckCallNames(c, "NewClient", "ListBlobs") 260 s.storageClient.CheckCall( 261 c, 0, "NewClient", fakeStorageAccount, fakeStorageAccountKey, 262 "storage.azurestack.local", azurestorage.DefaultAPIVersion, true, 263 ) 264 s.storageClient.CheckCall(c, 1, "ListBlobs", "datavhds", azurestorage.ListBlobsParameters{}) 265 c.Assert(volumeIds, jc.DeepEquals, []string{"volume-1", "volume-0"}) 266 } 267 268 func (s *storageSuite) TestListVolumesErrors(c *gc.C) { 269 volumeSource := s.volumeSource(c) 270 s.storageClient.SetErrors(errors.New("no client for you")) 271 _, err := volumeSource.ListVolumes() 272 c.Assert(err, gc.ErrorMatches, "listing volumes: getting storage client: no client for you") 273 274 s.storageClient.SetErrors(nil, errors.New("no blobs for you")) 275 _, err = volumeSource.ListVolumes() 276 c.Assert(err, gc.ErrorMatches, "listing volumes: listing blobs: no blobs for you") 277 } 278 279 func (s *storageSuite) TestDescribeVolumes(c *gc.C) { 280 s.storageClient.ListBlobsFunc = func( 281 container string, 282 params azurestorage.ListBlobsParameters, 283 ) (azurestorage.BlobListResponse, error) { 284 return azurestorage.BlobListResponse{ 285 Blobs: []azurestorage.Blob{{ 286 Name: "volume-1.vhd", 287 Properties: azurestorage.BlobProperties{ 288 ContentLength: 1024 * 1024, // 1MiB 289 }, 290 }, { 291 Name: "volume-0.vhd", 292 Properties: azurestorage.BlobProperties{ 293 ContentLength: 1024 * 1024 * 1024 * 1024, // 1TiB 294 }, 295 }}, 296 }, nil 297 } 298 299 volumeSource := s.volumeSource(c) 300 results, err := volumeSource.DescribeVolumes([]string{"volume-0", "volume-1", "volume-0", "volume-42"}) 301 c.Assert(err, jc.ErrorIsNil) 302 s.storageClient.CheckCallNames(c, "NewClient", "ListBlobs") 303 s.storageClient.CheckCall( 304 c, 0, "NewClient", fakeStorageAccount, fakeStorageAccountKey, 305 "storage.azurestack.local", azurestorage.DefaultAPIVersion, true, 306 ) 307 c.Assert(results, gc.HasLen, 4) 308 c.Assert(results[:3], jc.DeepEquals, []storage.DescribeVolumesResult{{ 309 VolumeInfo: &storage.VolumeInfo{ 310 VolumeId: "volume-0", 311 Size: 1024 * 1024, 312 Persistent: true, 313 }, 314 }, { 315 VolumeInfo: &storage.VolumeInfo{ 316 VolumeId: "volume-1", 317 Size: 1, 318 Persistent: true, 319 }, 320 }, { 321 VolumeInfo: &storage.VolumeInfo{ 322 VolumeId: "volume-0", 323 Size: 1024 * 1024, 324 Persistent: true, 325 }, 326 }}) 327 c.Assert(results[3].Error, gc.ErrorMatches, "volume-42 not found") 328 } 329 330 func (s *storageSuite) TestDestroyVolumes(c *gc.C) { 331 volumeSource := s.volumeSource(c) 332 results, err := volumeSource.DestroyVolumes([]string{"volume-0", "volume-42"}) 333 c.Assert(err, jc.ErrorIsNil) 334 c.Assert(results, gc.HasLen, 2) 335 c.Assert(results[0], jc.ErrorIsNil) 336 c.Assert(results[1], jc.ErrorIsNil) 337 s.storageClient.CheckCallNames(c, "NewClient", "DeleteBlobIfExists", "DeleteBlobIfExists") 338 s.storageClient.CheckCall(c, 1, "DeleteBlobIfExists", "datavhds", "volume-0.vhd") 339 s.storageClient.CheckCall(c, 2, "DeleteBlobIfExists", "datavhds", "volume-42.vhd") 340 } 341 342 func (s *storageSuite) TestAttachVolumes(c *gc.C) { 343 // machine-1 has a single data disk with LUN 0. 344 machine1DataDisks := []compute.DataDisk{{ 345 Lun: to.IntPtr(0), 346 Name: to.StringPtr("volume-1"), 347 Vhd: &compute.VirtualHardDisk{ 348 URI: to.StringPtr(fmt.Sprintf( 349 "https://%s.blob.storage.azurestack.local/datavhds/volume-1.vhd", 350 fakeStorageAccount, 351 )), 352 }, 353 }} 354 // machine-2 has 32 data disks; no LUNs free. 355 machine2DataDisks := make([]compute.DataDisk, 32) 356 for i := range machine2DataDisks { 357 machine2DataDisks[i].Lun = to.IntPtr(i) 358 machine2DataDisks[i].Name = to.StringPtr(fmt.Sprintf("volume-%d", i)) 359 machine2DataDisks[i].Vhd = &compute.VirtualHardDisk{ 360 URI: to.StringPtr(fmt.Sprintf( 361 "https://%s.blob.storage.azurestack.local/datavhds/volume-%d.vhd", 362 fakeStorageAccount, i, 363 )), 364 } 365 } 366 367 // volume-0 and volume-2 are attached to machine-0 368 // volume-1 is attached to machine-1 369 // volume-3 is attached to machine-42, but machine-42 is missing 370 // volume-42 is attached to machine-2, but machine-2 has no free LUNs 371 makeParams := func(volume, machine string, size uint64) storage.VolumeAttachmentParams { 372 return storage.VolumeAttachmentParams{ 373 AttachmentParams: storage.AttachmentParams{ 374 Provider: "azure", 375 Machine: names.NewMachineTag(machine), 376 InstanceId: instance.Id("machine-" + machine), 377 }, 378 Volume: names.NewVolumeTag(volume), 379 VolumeId: "volume-" + volume, 380 } 381 } 382 params := []storage.VolumeAttachmentParams{ 383 makeParams("0", "0", 1), 384 makeParams("1", "1", 1025), 385 makeParams("2", "0", 1024), 386 makeParams("3", "42", 40), 387 makeParams("42", "2", 50), 388 } 389 390 virtualMachines := []compute.VirtualMachine{{ 391 Name: to.StringPtr("machine-0"), 392 Properties: &compute.VirtualMachineProperties{ 393 StorageProfile: &compute.StorageProfile{}, 394 }, 395 }, { 396 Name: to.StringPtr("machine-1"), 397 Properties: &compute.VirtualMachineProperties{ 398 StorageProfile: &compute.StorageProfile{DataDisks: &machine1DataDisks}, 399 }, 400 }, { 401 Name: to.StringPtr("machine-2"), 402 Properties: &compute.VirtualMachineProperties{ 403 StorageProfile: &compute.StorageProfile{DataDisks: &machine2DataDisks}, 404 }, 405 }} 406 407 // There should be a couple of API calls to list instances, 408 // and one update per modified instance. 409 nics := []network.Interface{ 410 makeNetworkInterface("nic-0", "machine-0"), 411 makeNetworkInterface("nic-1", "machine-1"), 412 makeNetworkInterface("nic-2", "machine-2"), 413 } 414 nicsSender := azuretesting.NewSenderWithValue(network.InterfaceListResult{ 415 Value: &nics, 416 }) 417 nicsSender.PathPattern = `.*/Microsoft\.Network/networkInterfaces` 418 virtualMachinesSender := azuretesting.NewSenderWithValue(compute.VirtualMachineListResult{ 419 Value: &virtualMachines, 420 }) 421 virtualMachinesSender.PathPattern = `.*/Microsoft\.Compute/virtualMachines` 422 updateVirtualMachine0Sender := azuretesting.NewSenderWithValue(&compute.VirtualMachine{}) 423 updateVirtualMachine0Sender.PathPattern = `.*/Microsoft\.Compute/virtualMachines/machine-0` 424 volumeSource := s.volumeSource(c) 425 s.sender = azuretesting.Senders{ 426 nicsSender, 427 virtualMachinesSender, 428 updateVirtualMachine0Sender, 429 } 430 431 results, err := volumeSource.AttachVolumes(params) 432 c.Assert(err, jc.ErrorIsNil) 433 c.Assert(results, gc.HasLen, len(params)) 434 435 c.Check(results[0].Error, jc.ErrorIsNil) 436 c.Check(results[1].Error, jc.ErrorIsNil) 437 c.Check(results[2].Error, jc.ErrorIsNil) 438 c.Check(results[3].Error, gc.ErrorMatches, "instance machine-42 not found") 439 c.Check(results[4].Error, gc.ErrorMatches, "choosing LUN: all LUNs are in use") 440 441 // Validate HTTP request bodies. 442 c.Assert(s.requests, gc.HasLen, 3) 443 c.Assert(s.requests[0].Method, gc.Equals, "GET") // list NICs 444 c.Assert(s.requests[1].Method, gc.Equals, "GET") // list virtual machines 445 c.Assert(s.requests[2].Method, gc.Equals, "PUT") // update machine-0 446 447 machine0DataDisks := []compute.DataDisk{{ 448 Lun: to.IntPtr(0), 449 Name: to.StringPtr("volume-0"), 450 Vhd: &compute.VirtualHardDisk{URI: to.StringPtr(fmt.Sprintf( 451 "https://%s.blob.storage.azurestack.local/datavhds/volume-0.vhd", 452 fakeStorageAccount, 453 ))}, 454 Caching: compute.ReadWrite, 455 CreateOption: compute.Attach, 456 }, { 457 Lun: to.IntPtr(1), 458 Name: to.StringPtr("volume-2"), 459 Vhd: &compute.VirtualHardDisk{URI: to.StringPtr(fmt.Sprintf( 460 "https://%s.blob.storage.azurestack.local/datavhds/volume-2.vhd", 461 fakeStorageAccount, 462 ))}, 463 Caching: compute.ReadWrite, 464 CreateOption: compute.Attach, 465 }} 466 virtualMachines[0].Properties.StorageProfile.DataDisks = &machine0DataDisks 467 assertRequestBody(c, s.requests[2], &virtualMachines[0]) 468 } 469 470 func (s *storageSuite) TestDetachVolumes(c *gc.C) { 471 // machine-0 has a three data disks: volume-0, volume-1 and volume-2 472 machine0DataDisks := []compute.DataDisk{{ 473 Lun: to.IntPtr(0), 474 Name: to.StringPtr("volume-0"), 475 Vhd: &compute.VirtualHardDisk{ 476 URI: to.StringPtr(fmt.Sprintf( 477 "https://%s.blob.storage.azurestack.local/datavhds/volume-0.vhd", 478 fakeStorageAccount, 479 )), 480 }, 481 }, { 482 Lun: to.IntPtr(1), 483 Name: to.StringPtr("volume-1"), 484 Vhd: &compute.VirtualHardDisk{ 485 URI: to.StringPtr(fmt.Sprintf( 486 "https://%s.blob.storage.azurestack.local/datavhds/volume-1.vhd", 487 fakeStorageAccount, 488 )), 489 }, 490 }, { 491 Lun: to.IntPtr(2), 492 Name: to.StringPtr("volume-2"), 493 Vhd: &compute.VirtualHardDisk{ 494 URI: to.StringPtr(fmt.Sprintf( 495 "https://%s.blob.storage.azurestack.local/datavhds/volume-2.vhd", 496 fakeStorageAccount, 497 )), 498 }, 499 }} 500 501 makeParams := func(volume, machine string) storage.VolumeAttachmentParams { 502 return storage.VolumeAttachmentParams{ 503 AttachmentParams: storage.AttachmentParams{ 504 Provider: "azure", 505 Machine: names.NewMachineTag(machine), 506 InstanceId: instance.Id("machine-" + machine), 507 }, 508 Volume: names.NewVolumeTag(volume), 509 VolumeId: "volume-" + volume, 510 } 511 } 512 params := []storage.VolumeAttachmentParams{ 513 makeParams("1", "0"), 514 makeParams("1", "0"), 515 makeParams("42", "1"), 516 makeParams("2", "42"), 517 } 518 519 virtualMachines := []compute.VirtualMachine{{ 520 Name: to.StringPtr("machine-0"), 521 Properties: &compute.VirtualMachineProperties{ 522 StorageProfile: &compute.StorageProfile{DataDisks: &machine0DataDisks}, 523 }, 524 }, { 525 Name: to.StringPtr("machine-1"), 526 Properties: &compute.VirtualMachineProperties{ 527 StorageProfile: &compute.StorageProfile{}, 528 }, 529 }} 530 531 // There should be a couple of API calls to list instances, 532 // and one update per modified instance. 533 nics := []network.Interface{ 534 makeNetworkInterface("nic-0", "machine-0"), 535 makeNetworkInterface("nic-1", "machine-1"), 536 } 537 nicsSender := azuretesting.NewSenderWithValue(network.InterfaceListResult{ 538 Value: &nics, 539 }) 540 nicsSender.PathPattern = `.*/Microsoft\.Network/networkInterfaces` 541 virtualMachinesSender := azuretesting.NewSenderWithValue(compute.VirtualMachineListResult{ 542 Value: &virtualMachines, 543 }) 544 virtualMachinesSender.PathPattern = `.*/Microsoft\.Compute/virtualMachines` 545 updateVirtualMachine0Sender := azuretesting.NewSenderWithValue(&compute.VirtualMachine{}) 546 updateVirtualMachine0Sender.PathPattern = `.*/Microsoft\.Compute/virtualMachines/machine-0` 547 volumeSource := s.volumeSource(c) 548 s.sender = azuretesting.Senders{ 549 nicsSender, 550 virtualMachinesSender, 551 updateVirtualMachine0Sender, 552 } 553 554 results, err := volumeSource.DetachVolumes(params) 555 c.Assert(err, jc.ErrorIsNil) 556 c.Assert(results, gc.HasLen, len(params)) 557 558 c.Check(results[0], jc.ErrorIsNil) 559 c.Check(results[1], jc.ErrorIsNil) 560 c.Check(results[2], jc.ErrorIsNil) 561 c.Check(results[3], gc.ErrorMatches, "instance machine-42 not found") 562 563 // Validate HTTP request bodies. 564 c.Assert(s.requests, gc.HasLen, 3) 565 c.Assert(s.requests[0].Method, gc.Equals, "GET") // list NICs 566 c.Assert(s.requests[1].Method, gc.Equals, "GET") // list virtual machines 567 c.Assert(s.requests[2].Method, gc.Equals, "PUT") // update machine-0 568 569 machine0DataDisks = []compute.DataDisk{ 570 machine0DataDisks[0], 571 machine0DataDisks[2], 572 } 573 virtualMachines[0].Properties.StorageProfile.DataDisks = &machine0DataDisks 574 assertRequestBody(c, s.requests[2], &virtualMachines[0]) 575 }