github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/azurerm/resource_arm_virtual_machine.go (about) 1 package azurerm 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "net/http" 8 "net/url" 9 "strings" 10 11 "github.com/Azure/azure-sdk-for-go/arm/compute" 12 "github.com/hashicorp/terraform/helper/hashcode" 13 "github.com/hashicorp/terraform/helper/schema" 14 riviera "github.com/jen20/riviera/azure" 15 ) 16 17 func resourceArmVirtualMachine() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceArmVirtualMachineCreate, 20 Read: resourceArmVirtualMachineRead, 21 Update: resourceArmVirtualMachineCreate, 22 Delete: resourceArmVirtualMachineDelete, 23 24 Schema: map[string]*schema.Schema{ 25 "name": { 26 Type: schema.TypeString, 27 Required: true, 28 ForceNew: true, 29 }, 30 31 "location": { 32 Type: schema.TypeString, 33 Required: true, 34 ForceNew: true, 35 StateFunc: azureRMNormalizeLocation, 36 }, 37 38 "resource_group_name": { 39 Type: schema.TypeString, 40 Required: true, 41 ForceNew: true, 42 }, 43 44 "plan": { 45 Type: schema.TypeSet, 46 Optional: true, 47 Computed: true, 48 MaxItems: 1, 49 Elem: &schema.Resource{ 50 Schema: map[string]*schema.Schema{ 51 "name": { 52 Type: schema.TypeString, 53 Required: true, 54 }, 55 56 "publisher": { 57 Type: schema.TypeString, 58 Required: true, 59 }, 60 61 "product": { 62 Type: schema.TypeString, 63 Required: true, 64 }, 65 }, 66 }, 67 Set: resourceArmVirtualMachinePlanHash, 68 }, 69 70 "availability_set_id": { 71 Type: schema.TypeString, 72 Optional: true, 73 Computed: true, 74 ForceNew: true, 75 StateFunc: func(id interface{}) string { 76 return strings.ToLower(id.(string)) 77 }, 78 }, 79 80 "license_type": { 81 Type: schema.TypeString, 82 Optional: true, 83 Computed: true, 84 }, 85 86 "vm_size": { 87 Type: schema.TypeString, 88 Required: true, 89 }, 90 91 "storage_image_reference": { 92 Type: schema.TypeSet, 93 Optional: true, 94 Computed: true, 95 MaxItems: 1, 96 Elem: &schema.Resource{ 97 Schema: map[string]*schema.Schema{ 98 "publisher": { 99 Type: schema.TypeString, 100 Required: true, 101 }, 102 103 "offer": { 104 Type: schema.TypeString, 105 Required: true, 106 }, 107 108 "sku": { 109 Type: schema.TypeString, 110 Required: true, 111 }, 112 113 "version": { 114 Type: schema.TypeString, 115 Optional: true, 116 Computed: true, 117 }, 118 }, 119 }, 120 Set: resourceArmVirtualMachineStorageImageReferenceHash, 121 }, 122 123 "storage_os_disk": { 124 Type: schema.TypeSet, 125 Required: true, 126 MaxItems: 1, 127 Elem: &schema.Resource{ 128 Schema: map[string]*schema.Schema{ 129 "os_type": { 130 Type: schema.TypeString, 131 Optional: true, 132 }, 133 134 "name": { 135 Type: schema.TypeString, 136 Required: true, 137 }, 138 139 "vhd_uri": { 140 Type: schema.TypeString, 141 Required: true, 142 }, 143 144 "image_uri": { 145 Type: schema.TypeString, 146 Optional: true, 147 }, 148 149 "caching": { 150 Type: schema.TypeString, 151 Optional: true, 152 Computed: true, 153 }, 154 155 "create_option": { 156 Type: schema.TypeString, 157 Required: true, 158 }, 159 160 "disk_size_gb": { 161 Type: schema.TypeInt, 162 Optional: true, 163 ValidateFunc: validateDiskSizeGB, 164 }, 165 }, 166 }, 167 Set: resourceArmVirtualMachineStorageOsDiskHash, 168 }, 169 170 "delete_os_disk_on_termination": { 171 Type: schema.TypeBool, 172 Optional: true, 173 Default: false, 174 }, 175 176 "storage_data_disk": { 177 Type: schema.TypeList, 178 Optional: true, 179 Elem: &schema.Resource{ 180 Schema: map[string]*schema.Schema{ 181 "name": { 182 Type: schema.TypeString, 183 Required: true, 184 }, 185 186 "vhd_uri": { 187 Type: schema.TypeString, 188 Required: true, 189 }, 190 191 "create_option": { 192 Type: schema.TypeString, 193 Required: true, 194 }, 195 196 "disk_size_gb": { 197 Type: schema.TypeInt, 198 Required: true, 199 ValidateFunc: validateDiskSizeGB, 200 }, 201 202 "lun": { 203 Type: schema.TypeInt, 204 Required: true, 205 }, 206 }, 207 }, 208 }, 209 210 "delete_data_disks_on_termination": { 211 Type: schema.TypeBool, 212 Optional: true, 213 Default: false, 214 }, 215 216 "diagnostics_profile": { 217 Type: schema.TypeSet, 218 Optional: true, 219 MaxItems: 1, 220 ConflictsWith: []string{"boot_diagnostics"}, 221 Deprecated: "Use field boot_diagnostics instead", 222 Elem: &schema.Resource{ 223 Schema: map[string]*schema.Schema{ 224 "boot_diagnostics": { 225 Type: schema.TypeSet, 226 Required: true, 227 MaxItems: 1, 228 Elem: &schema.Resource{ 229 Schema: map[string]*schema.Schema{ 230 "enabled": { 231 Type: schema.TypeBool, 232 Required: true, 233 }, 234 235 "storage_uri": { 236 Type: schema.TypeString, 237 Required: true, 238 }, 239 }, 240 }, 241 }, 242 }, 243 }, 244 }, 245 246 "boot_diagnostics": { 247 Type: schema.TypeList, 248 Optional: true, 249 MaxItems: 1, 250 Elem: &schema.Resource{ 251 Schema: map[string]*schema.Schema{ 252 "enabled": { 253 Type: schema.TypeBool, 254 Required: true, 255 }, 256 257 "storage_uri": { 258 Type: schema.TypeString, 259 Required: true, 260 }, 261 }, 262 }, 263 }, 264 265 "os_profile": { 266 Type: schema.TypeSet, 267 Required: true, 268 MaxItems: 1, 269 Elem: &schema.Resource{ 270 Schema: map[string]*schema.Schema{ 271 "computer_name": { 272 Type: schema.TypeString, 273 ForceNew: true, 274 Required: true, 275 }, 276 277 "admin_username": { 278 Type: schema.TypeString, 279 Required: true, 280 }, 281 282 "admin_password": { 283 Type: schema.TypeString, 284 Required: true, 285 }, 286 287 "custom_data": { 288 Type: schema.TypeString, 289 Optional: true, 290 Computed: true, 291 }, 292 }, 293 }, 294 Set: resourceArmVirtualMachineStorageOsProfileHash, 295 }, 296 297 "os_profile_windows_config": { 298 Type: schema.TypeSet, 299 Optional: true, 300 MaxItems: 1, 301 Elem: &schema.Resource{ 302 Schema: map[string]*schema.Schema{ 303 "provision_vm_agent": { 304 Type: schema.TypeBool, 305 Optional: true, 306 }, 307 "enable_automatic_upgrades": { 308 Type: schema.TypeBool, 309 Optional: true, 310 }, 311 "winrm": { 312 Type: schema.TypeList, 313 Optional: true, 314 Elem: &schema.Resource{ 315 Schema: map[string]*schema.Schema{ 316 "protocol": { 317 Type: schema.TypeString, 318 Required: true, 319 }, 320 "certificate_url": { 321 Type: schema.TypeString, 322 Optional: true, 323 }, 324 }, 325 }, 326 }, 327 "additional_unattend_config": { 328 Type: schema.TypeList, 329 Optional: true, 330 Elem: &schema.Resource{ 331 Schema: map[string]*schema.Schema{ 332 "pass": { 333 Type: schema.TypeString, 334 Required: true, 335 }, 336 "component": { 337 Type: schema.TypeString, 338 Required: true, 339 }, 340 "setting_name": { 341 Type: schema.TypeString, 342 Required: true, 343 }, 344 "content": { 345 Type: schema.TypeString, 346 Required: true, 347 }, 348 }, 349 }, 350 }, 351 }, 352 }, 353 Set: resourceArmVirtualMachineStorageOsProfileWindowsConfigHash, 354 }, 355 356 "os_profile_linux_config": { 357 Type: schema.TypeSet, 358 Optional: true, 359 MaxItems: 1, 360 Elem: &schema.Resource{ 361 Schema: map[string]*schema.Schema{ 362 "disable_password_authentication": { 363 Type: schema.TypeBool, 364 Required: true, 365 }, 366 "ssh_keys": { 367 Type: schema.TypeList, 368 Optional: true, 369 Elem: &schema.Resource{ 370 Schema: map[string]*schema.Schema{ 371 "path": { 372 Type: schema.TypeString, 373 Required: true, 374 }, 375 "key_data": { 376 Type: schema.TypeString, 377 Optional: true, 378 }, 379 }, 380 }, 381 }, 382 }, 383 }, 384 Set: resourceArmVirtualMachineStorageOsProfileLinuxConfigHash, 385 }, 386 387 "os_profile_secrets": { 388 Type: schema.TypeSet, 389 Optional: true, 390 Elem: &schema.Resource{ 391 Schema: map[string]*schema.Schema{ 392 "source_vault_id": { 393 Type: schema.TypeString, 394 Required: true, 395 }, 396 397 "vault_certificates": { 398 Type: schema.TypeList, 399 Optional: true, 400 Elem: &schema.Resource{ 401 Schema: map[string]*schema.Schema{ 402 "certificate_url": { 403 Type: schema.TypeString, 404 Required: true, 405 }, 406 "certificate_store": { 407 Type: schema.TypeString, 408 Optional: true, 409 }, 410 }, 411 }, 412 }, 413 }, 414 }, 415 }, 416 417 "network_interface_ids": { 418 Type: schema.TypeSet, 419 Required: true, 420 Elem: &schema.Schema{ 421 Type: schema.TypeString, 422 }, 423 Set: schema.HashString, 424 }, 425 426 "tags": tagsSchema(), 427 }, 428 } 429 } 430 431 func validateDiskSizeGB(v interface{}, k string) (ws []string, errors []error) { 432 value := v.(int) 433 if value < 1 || value > 1023 { 434 errors = append(errors, fmt.Errorf( 435 "The `disk_size_gb` can only be between 1 and 1023")) 436 } 437 return 438 } 439 440 func resourceArmVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error { 441 client := meta.(*ArmClient) 442 vmClient := client.vmClient 443 444 log.Printf("[INFO] preparing arguments for Azure ARM Virtual Machine creation.") 445 446 name := d.Get("name").(string) 447 location := d.Get("location").(string) 448 resGroup := d.Get("resource_group_name").(string) 449 tags := d.Get("tags").(map[string]interface{}) 450 expandedTags := expandTags(tags) 451 452 osDisk, err := expandAzureRmVirtualMachineOsDisk(d) 453 if err != nil { 454 return err 455 } 456 storageProfile := compute.StorageProfile{ 457 OsDisk: osDisk, 458 } 459 460 if _, ok := d.GetOk("storage_image_reference"); ok { 461 imageRef, err := expandAzureRmVirtualMachineImageReference(d) 462 if err != nil { 463 return err 464 } 465 storageProfile.ImageReference = imageRef 466 } 467 468 if _, ok := d.GetOk("storage_data_disk"); ok { 469 dataDisks, err := expandAzureRmVirtualMachineDataDisk(d) 470 if err != nil { 471 return err 472 } 473 storageProfile.DataDisks = &dataDisks 474 } 475 476 networkProfile := expandAzureRmVirtualMachineNetworkProfile(d) 477 vmSize := d.Get("vm_size").(string) 478 properties := compute.VirtualMachineProperties{ 479 NetworkProfile: &networkProfile, 480 HardwareProfile: &compute.HardwareProfile{ 481 VMSize: compute.VirtualMachineSizeTypes(vmSize), 482 }, 483 StorageProfile: &storageProfile, 484 } 485 486 if _, ok := d.GetOk("boot_diagnostics"); ok { 487 diagnosticsProfile := expandAzureRmVirtualMachineDiagnosticsProfile(d) 488 if diagnosticsProfile != nil { 489 properties.DiagnosticsProfile = diagnosticsProfile 490 } 491 } 492 493 osProfile, err := expandAzureRmVirtualMachineOsProfile(d) 494 if err != nil { 495 return err 496 } 497 properties.OsProfile = osProfile 498 499 if v, ok := d.GetOk("availability_set_id"); ok { 500 availabilitySet := v.(string) 501 availSet := compute.SubResource{ 502 ID: &availabilitySet, 503 } 504 505 properties.AvailabilitySet = &availSet 506 } 507 508 vm := compute.VirtualMachine{ 509 Name: &name, 510 Location: &location, 511 Properties: &properties, 512 Tags: expandedTags, 513 } 514 515 if _, ok := d.GetOk("plan"); ok { 516 plan, err := expandAzureRmVirtualMachinePlan(d) 517 if err != nil { 518 return err 519 } 520 521 vm.Plan = plan 522 } 523 524 _, vmErr := vmClient.CreateOrUpdate(resGroup, name, vm, make(chan struct{})) 525 if vmErr != nil { 526 return vmErr 527 } 528 529 read, err := vmClient.Get(resGroup, name, "") 530 if err != nil { 531 return err 532 } 533 if read.ID == nil { 534 return fmt.Errorf("Cannot read Virtual Machine %s (resource group %s) ID", name, resGroup) 535 } 536 537 d.SetId(*read.ID) 538 539 return resourceArmVirtualMachineRead(d, meta) 540 } 541 542 func resourceArmVirtualMachineRead(d *schema.ResourceData, meta interface{}) error { 543 vmClient := meta.(*ArmClient).vmClient 544 545 id, err := parseAzureResourceID(d.Id()) 546 if err != nil { 547 return err 548 } 549 resGroup := id.ResourceGroup 550 name := id.Path["virtualMachines"] 551 552 resp, err := vmClient.Get(resGroup, name, "") 553 554 if err != nil { 555 if resp.StatusCode == http.StatusNotFound { 556 d.SetId("") 557 return nil 558 } 559 return fmt.Errorf("Error making Read request on Azure Virtual Machine %s: %s", name, err) 560 } 561 562 if resp.Plan != nil { 563 if err := d.Set("plan", flattenAzureRmVirtualMachinePlan(resp.Plan)); err != nil { 564 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Plan error: %#v", err) 565 } 566 } 567 568 if resp.Properties.AvailabilitySet != nil { 569 d.Set("availability_set_id", strings.ToLower(*resp.Properties.AvailabilitySet.ID)) 570 } 571 572 d.Set("vm_size", resp.Properties.HardwareProfile.VMSize) 573 574 if resp.Properties.StorageProfile.ImageReference != nil { 575 if err := d.Set("storage_image_reference", schema.NewSet(resourceArmVirtualMachineStorageImageReferenceHash, flattenAzureRmVirtualMachineImageReference(resp.Properties.StorageProfile.ImageReference))); err != nil { 576 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage Image Reference error: %#v", err) 577 } 578 } 579 580 if err := d.Set("storage_os_disk", schema.NewSet(resourceArmVirtualMachineStorageOsDiskHash, flattenAzureRmVirtualMachineOsDisk(resp.Properties.StorageProfile.OsDisk))); err != nil { 581 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Disk error: %#v", err) 582 } 583 584 if resp.Properties.StorageProfile.DataDisks != nil { 585 if err := d.Set("storage_data_disk", flattenAzureRmVirtualMachineDataDisk(resp.Properties.StorageProfile.DataDisks)); err != nil { 586 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage Data Disks error: %#v", err) 587 } 588 } 589 590 if err := d.Set("os_profile", schema.NewSet(resourceArmVirtualMachineStorageOsProfileHash, flattenAzureRmVirtualMachineOsProfile(resp.Properties.OsProfile))); err != nil { 591 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile: %#v", err) 592 } 593 594 if resp.Properties.OsProfile.WindowsConfiguration != nil { 595 if err := d.Set("os_profile_windows_config", flattenAzureRmVirtualMachineOsProfileWindowsConfiguration(resp.Properties.OsProfile.WindowsConfiguration)); err != nil { 596 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile Windows Configuration: %#v", err) 597 } 598 } 599 600 if resp.Properties.OsProfile.LinuxConfiguration != nil { 601 if err := d.Set("os_profile_linux_config", flattenAzureRmVirtualMachineOsProfileLinuxConfiguration(resp.Properties.OsProfile.LinuxConfiguration)); err != nil { 602 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile Linux Configuration: %#v", err) 603 } 604 } 605 606 if resp.Properties.OsProfile.Secrets != nil { 607 if err := d.Set("os_profile_secrets", flattenAzureRmVirtualMachineOsProfileSecrets(resp.Properties.OsProfile.Secrets)); err != nil { 608 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile Secrets: %#v", err) 609 } 610 } 611 612 if resp.Properties.DiagnosticsProfile != nil && resp.Properties.DiagnosticsProfile.BootDiagnostics != nil { 613 if err := d.Set("boot_diagnostics", flattenAzureRmVirtualMachineDiagnosticsProfile(resp.Properties.DiagnosticsProfile.BootDiagnostics)); err != nil { 614 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Diagnostics Profile: %#v", err) 615 } 616 } 617 618 if resp.Properties.NetworkProfile != nil { 619 if err := d.Set("network_interface_ids", flattenAzureRmVirtualMachineNetworkInterfaces(resp.Properties.NetworkProfile)); err != nil { 620 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage Network Interfaces: %#v", err) 621 } 622 } 623 624 flattenAndSetTags(d, resp.Tags) 625 626 return nil 627 } 628 629 func resourceArmVirtualMachineDelete(d *schema.ResourceData, meta interface{}) error { 630 vmClient := meta.(*ArmClient).vmClient 631 632 id, err := parseAzureResourceID(d.Id()) 633 if err != nil { 634 return err 635 } 636 resGroup := id.ResourceGroup 637 name := id.Path["virtualMachines"] 638 639 if _, err = vmClient.Delete(resGroup, name, make(chan struct{})); err != nil { 640 return err 641 } 642 643 // delete OS Disk if opted in 644 if deleteOsDisk := d.Get("delete_os_disk_on_termination").(bool); deleteOsDisk { 645 log.Printf("[INFO] delete_os_disk_on_termination is enabled, deleting") 646 647 osDisk, err := expandAzureRmVirtualMachineOsDisk(d) 648 if err != nil { 649 return fmt.Errorf("Error expanding OS Disk: %s", err) 650 } 651 652 if err = resourceArmVirtualMachineDeleteVhd(*osDisk.Vhd.URI, meta); err != nil { 653 return fmt.Errorf("Error deleting OS Disk VHD: %s", err) 654 } 655 } 656 657 // delete Data disks if opted in 658 if deleteDataDisks := d.Get("delete_data_disks_on_termination").(bool); deleteDataDisks { 659 log.Printf("[INFO] delete_data_disks_on_termination is enabled, deleting each data disk") 660 661 disks, err := expandAzureRmVirtualMachineDataDisk(d) 662 if err != nil { 663 return fmt.Errorf("Error expanding Data Disks: %s", err) 664 } 665 666 for _, disk := range disks { 667 if err = resourceArmVirtualMachineDeleteVhd(*disk.Vhd.URI, meta); err != nil { 668 return fmt.Errorf("Error deleting Data Disk VHD: %s", err) 669 } 670 } 671 } 672 673 return nil 674 } 675 676 func resourceArmVirtualMachineDeleteVhd(uri string, meta interface{}) error { 677 vhdURL, err := url.Parse(uri) 678 if err != nil { 679 return fmt.Errorf("Cannot parse Disk VHD URI: %s", err) 680 } 681 682 // VHD URI is in the form: https://storageAccountName.blob.core.windows.net/containerName/blobName 683 storageAccountName := strings.Split(vhdURL.Host, ".")[0] 684 path := strings.Split(strings.TrimPrefix(vhdURL.Path, "/"), "/") 685 containerName := path[0] 686 blobName := path[1] 687 688 storageAccountResourceGroupName, err := findStorageAccountResourceGroup(meta, storageAccountName) 689 if err != nil { 690 return fmt.Errorf("Error finding resource group for storage account %s: %s", storageAccountName, err) 691 } 692 693 blobClient, saExists, err := meta.(*ArmClient).getBlobStorageClientForStorageAccount(storageAccountResourceGroupName, storageAccountName) 694 if err != nil { 695 return fmt.Errorf("Error creating blob store client for VHD deletion: %s", err) 696 } 697 698 if !saExists { 699 log.Printf("[INFO] Storage Account %q in resource group %q doesn't exist so the VHD blob won't exist", storageAccountName, storageAccountResourceGroupName) 700 return nil 701 } 702 703 log.Printf("[INFO] Deleting VHD blob %s", blobName) 704 _, err = blobClient.DeleteBlobIfExists(containerName, blobName, nil) 705 if err != nil { 706 return fmt.Errorf("Error deleting VHD blob: %s", err) 707 } 708 709 return nil 710 } 711 712 func resourceArmVirtualMachinePlanHash(v interface{}) int { 713 var buf bytes.Buffer 714 m := v.(map[string]interface{}) 715 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 716 buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string))) 717 buf.WriteString(fmt.Sprintf("%s-", m["product"].(string))) 718 719 return hashcode.String(buf.String()) 720 } 721 722 func resourceArmVirtualMachineStorageImageReferenceHash(v interface{}) int { 723 var buf bytes.Buffer 724 m := v.(map[string]interface{}) 725 buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string))) 726 buf.WriteString(fmt.Sprintf("%s-", m["offer"].(string))) 727 buf.WriteString(fmt.Sprintf("%s-", m["sku"].(string))) 728 729 return hashcode.String(buf.String()) 730 } 731 732 func resourceArmVirtualMachineStorageOsProfileHash(v interface{}) int { 733 var buf bytes.Buffer 734 m := v.(map[string]interface{}) 735 buf.WriteString(fmt.Sprintf("%s-", m["admin_username"].(string))) 736 buf.WriteString(fmt.Sprintf("%s-", m["computer_name"].(string))) 737 return hashcode.String(buf.String()) 738 } 739 740 func resourceArmVirtualMachineStorageOsDiskHash(v interface{}) int { 741 var buf bytes.Buffer 742 m := v.(map[string]interface{}) 743 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 744 buf.WriteString(fmt.Sprintf("%s-", m["vhd_uri"].(string))) 745 746 return hashcode.String(buf.String()) 747 } 748 749 func resourceArmVirtualMachineStorageOsProfileLinuxConfigHash(v interface{}) int { 750 var buf bytes.Buffer 751 m := v.(map[string]interface{}) 752 buf.WriteString(fmt.Sprintf("%t-", m["disable_password_authentication"].(bool))) 753 754 return hashcode.String(buf.String()) 755 } 756 757 func resourceArmVirtualMachineStorageOsProfileWindowsConfigHash(v interface{}) int { 758 var buf bytes.Buffer 759 m := v.(map[string]interface{}) 760 if m["provision_vm_agent"] != nil { 761 buf.WriteString(fmt.Sprintf("%t-", m["provision_vm_agent"].(bool))) 762 } 763 if m["enable_automatic_upgrades"] != nil { 764 buf.WriteString(fmt.Sprintf("%t-", m["enable_automatic_upgrades"].(bool))) 765 } 766 return hashcode.String(buf.String()) 767 } 768 769 func flattenAzureRmVirtualMachinePlan(plan *compute.Plan) map[string]interface{} { 770 result := make(map[string]interface{}) 771 result["name"] = *plan.Name 772 result["publisher"] = *plan.Publisher 773 result["product"] = *plan.Product 774 775 return result 776 } 777 778 func flattenAzureRmVirtualMachineImageReference(image *compute.ImageReference) []interface{} { 779 result := make(map[string]interface{}) 780 result["offer"] = *image.Offer 781 result["publisher"] = *image.Publisher 782 result["sku"] = *image.Sku 783 784 if image.Version != nil { 785 result["version"] = *image.Version 786 } 787 788 return []interface{}{result} 789 } 790 791 func flattenAzureRmVirtualMachineDiagnosticsProfile(profile *compute.BootDiagnostics) []interface{} { 792 result := make(map[string]interface{}) 793 794 result["enabled"] = *profile.Enabled 795 result["storage_uri"] = *profile.StorageURI 796 797 return []interface{}{result} 798 } 799 800 func flattenAzureRmVirtualMachineNetworkInterfaces(profile *compute.NetworkProfile) []string { 801 result := make([]string, 0, len(*profile.NetworkInterfaces)) 802 for _, nic := range *profile.NetworkInterfaces { 803 result = append(result, *nic.ID) 804 } 805 return result 806 } 807 808 func flattenAzureRmVirtualMachineOsProfileSecrets(secrets *[]compute.VaultSecretGroup) []map[string]interface{} { 809 result := make([]map[string]interface{}, 0, len(*secrets)) 810 for _, secret := range *secrets { 811 s := map[string]interface{}{ 812 "source_vault_id": *secret.SourceVault.ID, 813 } 814 815 if secret.VaultCertificates != nil { 816 certs := make([]map[string]interface{}, 0, len(*secret.VaultCertificates)) 817 for _, cert := range *secret.VaultCertificates { 818 vaultCert := make(map[string]interface{}) 819 vaultCert["certificate_url"] = *cert.CertificateURL 820 821 if cert.CertificateStore != nil { 822 vaultCert["certificate_store"] = *cert.CertificateStore 823 } 824 825 certs = append(certs, vaultCert) 826 } 827 828 s["vault_certificates"] = certs 829 } 830 831 result = append(result, s) 832 } 833 return result 834 } 835 836 func flattenAzureRmVirtualMachineDataDisk(disks *[]compute.DataDisk) interface{} { 837 result := make([]interface{}, len(*disks)) 838 for i, disk := range *disks { 839 l := make(map[string]interface{}) 840 l["name"] = *disk.Name 841 l["vhd_uri"] = *disk.Vhd.URI 842 l["create_option"] = disk.CreateOption 843 l["disk_size_gb"] = *disk.DiskSizeGB 844 l["lun"] = *disk.Lun 845 846 result[i] = l 847 } 848 return result 849 } 850 851 func flattenAzureRmVirtualMachineOsProfile(osProfile *compute.OSProfile) []interface{} { 852 result := make(map[string]interface{}) 853 result["computer_name"] = *osProfile.ComputerName 854 result["admin_username"] = *osProfile.AdminUsername 855 if osProfile.CustomData != nil { 856 result["custom_data"] = *osProfile.CustomData 857 } 858 859 return []interface{}{result} 860 } 861 862 func flattenAzureRmVirtualMachineOsProfileWindowsConfiguration(config *compute.WindowsConfiguration) []interface{} { 863 result := make(map[string]interface{}) 864 865 if config.ProvisionVMAgent != nil { 866 result["provision_vm_agent"] = *config.ProvisionVMAgent 867 } 868 869 if config.EnableAutomaticUpdates != nil { 870 result["enable_automatic_upgrades"] = *config.EnableAutomaticUpdates 871 } 872 873 if config.WinRM != nil { 874 listeners := make([]map[string]interface{}, 0, len(*config.WinRM.Listeners)) 875 for _, i := range *config.WinRM.Listeners { 876 listener := make(map[string]interface{}) 877 listener["protocol"] = i.Protocol 878 879 if i.CertificateURL != nil { 880 listener["certificate_url"] = *i.CertificateURL 881 } 882 883 listeners = append(listeners, listener) 884 } 885 886 result["winrm"] = listeners 887 } 888 889 if config.AdditionalUnattendContent != nil { 890 content := make([]map[string]interface{}, 0, len(*config.AdditionalUnattendContent)) 891 for _, i := range *config.AdditionalUnattendContent { 892 c := make(map[string]interface{}) 893 c["pass"] = i.PassName 894 c["component"] = i.ComponentName 895 c["setting_name"] = i.SettingName 896 897 if i.Content != nil { 898 c["content"] = *i.Content 899 } 900 901 content = append(content, c) 902 } 903 904 result["additional_unattend_config"] = content 905 } 906 907 return []interface{}{result} 908 } 909 910 func flattenAzureRmVirtualMachineOsProfileLinuxConfiguration(config *compute.LinuxConfiguration) []interface{} { 911 912 result := make(map[string]interface{}) 913 result["disable_password_authentication"] = *config.DisablePasswordAuthentication 914 915 if config.SSH != nil && len(*config.SSH.PublicKeys) > 0 { 916 ssh_keys := make([]map[string]interface{}, len(*config.SSH.PublicKeys)) 917 for _, i := range *config.SSH.PublicKeys { 918 key := make(map[string]interface{}) 919 key["path"] = *i.Path 920 921 if i.KeyData != nil { 922 key["key_data"] = *i.KeyData 923 } 924 925 ssh_keys = append(ssh_keys, key) 926 } 927 928 result["ssh_keys"] = ssh_keys 929 } 930 931 return []interface{}{result} 932 } 933 934 func flattenAzureRmVirtualMachineOsDisk(disk *compute.OSDisk) []interface{} { 935 result := make(map[string]interface{}) 936 result["name"] = *disk.Name 937 result["vhd_uri"] = *disk.Vhd.URI 938 result["create_option"] = disk.CreateOption 939 result["caching"] = disk.Caching 940 if disk.DiskSizeGB != nil { 941 result["disk_size_gb"] = *disk.DiskSizeGB 942 } 943 944 return []interface{}{result} 945 } 946 947 func expandAzureRmVirtualMachinePlan(d *schema.ResourceData) (*compute.Plan, error) { 948 planConfigs := d.Get("plan").(*schema.Set).List() 949 950 planConfig := planConfigs[0].(map[string]interface{}) 951 952 publisher := planConfig["publisher"].(string) 953 name := planConfig["name"].(string) 954 product := planConfig["product"].(string) 955 956 return &compute.Plan{ 957 Publisher: &publisher, 958 Name: &name, 959 Product: &product, 960 }, nil 961 } 962 963 func expandAzureRmVirtualMachineOsProfile(d *schema.ResourceData) (*compute.OSProfile, error) { 964 osProfiles := d.Get("os_profile").(*schema.Set).List() 965 966 osProfile := osProfiles[0].(map[string]interface{}) 967 968 adminUsername := osProfile["admin_username"].(string) 969 adminPassword := osProfile["admin_password"].(string) 970 computerName := osProfile["computer_name"].(string) 971 972 profile := &compute.OSProfile{ 973 AdminUsername: &adminUsername, 974 ComputerName: &computerName, 975 } 976 977 if adminPassword != "" { 978 profile.AdminPassword = &adminPassword 979 } 980 981 if _, ok := d.GetOk("os_profile_windows_config"); ok { 982 winConfig, err := expandAzureRmVirtualMachineOsProfileWindowsConfig(d) 983 if err != nil { 984 return nil, err 985 } 986 if winConfig != nil { 987 profile.WindowsConfiguration = winConfig 988 } 989 } 990 991 if _, ok := d.GetOk("os_profile_linux_config"); ok { 992 linuxConfig, err := expandAzureRmVirtualMachineOsProfileLinuxConfig(d) 993 if err != nil { 994 return nil, err 995 } 996 if linuxConfig != nil { 997 profile.LinuxConfiguration = linuxConfig 998 } 999 } 1000 1001 if _, ok := d.GetOk("os_profile_secrets"); ok { 1002 secrets := expandAzureRmVirtualMachineOsProfileSecrets(d) 1003 if secrets != nil { 1004 profile.Secrets = secrets 1005 } 1006 } 1007 1008 if v := osProfile["custom_data"].(string); v != "" { 1009 profile.CustomData = &v 1010 } 1011 1012 return profile, nil 1013 } 1014 1015 func expandAzureRmVirtualMachineOsProfileSecrets(d *schema.ResourceData) *[]compute.VaultSecretGroup { 1016 secretsConfig := d.Get("os_profile_secrets").(*schema.Set).List() 1017 secrets := make([]compute.VaultSecretGroup, 0, len(secretsConfig)) 1018 1019 for _, secretConfig := range secretsConfig { 1020 config := secretConfig.(map[string]interface{}) 1021 sourceVaultId := config["source_vault_id"].(string) 1022 1023 vaultSecretGroup := compute.VaultSecretGroup{ 1024 SourceVault: &compute.SubResource{ 1025 ID: &sourceVaultId, 1026 }, 1027 } 1028 1029 if v := config["vault_certificates"]; v != nil { 1030 certsConfig := v.([]interface{}) 1031 certs := make([]compute.VaultCertificate, 0, len(certsConfig)) 1032 for _, certConfig := range certsConfig { 1033 config := certConfig.(map[string]interface{}) 1034 1035 certUrl := config["certificate_url"].(string) 1036 cert := compute.VaultCertificate{ 1037 CertificateURL: &certUrl, 1038 } 1039 if v := config["certificate_store"].(string); v != "" { 1040 cert.CertificateStore = &v 1041 } 1042 1043 certs = append(certs, cert) 1044 } 1045 vaultSecretGroup.VaultCertificates = &certs 1046 } 1047 1048 secrets = append(secrets, vaultSecretGroup) 1049 } 1050 1051 return &secrets 1052 } 1053 1054 func expandAzureRmVirtualMachineOsProfileLinuxConfig(d *schema.ResourceData) (*compute.LinuxConfiguration, error) { 1055 osProfilesLinuxConfig := d.Get("os_profile_linux_config").(*schema.Set).List() 1056 1057 linuxConfig := osProfilesLinuxConfig[0].(map[string]interface{}) 1058 disablePasswordAuth := linuxConfig["disable_password_authentication"].(bool) 1059 1060 config := &compute.LinuxConfiguration{ 1061 DisablePasswordAuthentication: &disablePasswordAuth, 1062 } 1063 1064 linuxKeys := linuxConfig["ssh_keys"].([]interface{}) 1065 sshPublicKeys := []compute.SSHPublicKey{} 1066 for _, key := range linuxKeys { 1067 1068 sshKey, ok := key.(map[string]interface{}) 1069 if !ok { 1070 continue 1071 } 1072 path := sshKey["path"].(string) 1073 keyData := sshKey["key_data"].(string) 1074 1075 sshPublicKey := compute.SSHPublicKey{ 1076 Path: &path, 1077 KeyData: &keyData, 1078 } 1079 1080 sshPublicKeys = append(sshPublicKeys, sshPublicKey) 1081 } 1082 1083 config.SSH = &compute.SSHConfiguration{ 1084 PublicKeys: &sshPublicKeys, 1085 } 1086 1087 return config, nil 1088 } 1089 1090 func expandAzureRmVirtualMachineOsProfileWindowsConfig(d *schema.ResourceData) (*compute.WindowsConfiguration, error) { 1091 osProfilesWindowsConfig := d.Get("os_profile_windows_config").(*schema.Set).List() 1092 1093 osProfileConfig := osProfilesWindowsConfig[0].(map[string]interface{}) 1094 config := &compute.WindowsConfiguration{} 1095 1096 if v := osProfileConfig["provision_vm_agent"]; v != nil { 1097 provision := v.(bool) 1098 config.ProvisionVMAgent = &provision 1099 } 1100 1101 if v := osProfileConfig["enable_automatic_upgrades"]; v != nil { 1102 update := v.(bool) 1103 config.EnableAutomaticUpdates = &update 1104 } 1105 1106 if v := osProfileConfig["winrm"]; v != nil { 1107 winRm := v.([]interface{}) 1108 if len(winRm) > 0 { 1109 winRmListners := make([]compute.WinRMListener, 0, len(winRm)) 1110 for _, winRmConfig := range winRm { 1111 config := winRmConfig.(map[string]interface{}) 1112 1113 protocol := config["protocol"].(string) 1114 winRmListner := compute.WinRMListener{ 1115 Protocol: compute.ProtocolTypes(protocol), 1116 } 1117 if v := config["certificate_url"].(string); v != "" { 1118 winRmListner.CertificateURL = &v 1119 } 1120 1121 winRmListners = append(winRmListners, winRmListner) 1122 } 1123 config.WinRM = &compute.WinRMConfiguration{ 1124 Listeners: &winRmListners, 1125 } 1126 } 1127 } 1128 if v := osProfileConfig["additional_unattend_config"]; v != nil { 1129 additionalConfig := v.([]interface{}) 1130 if len(additionalConfig) > 0 { 1131 additionalConfigContent := make([]compute.AdditionalUnattendContent, 0, len(additionalConfig)) 1132 for _, addConfig := range additionalConfig { 1133 config := addConfig.(map[string]interface{}) 1134 pass := config["pass"].(string) 1135 component := config["component"].(string) 1136 settingName := config["setting_name"].(string) 1137 content := config["content"].(string) 1138 1139 addContent := compute.AdditionalUnattendContent{ 1140 PassName: compute.PassNames(pass), 1141 ComponentName: compute.ComponentNames(component), 1142 SettingName: compute.SettingNames(settingName), 1143 Content: &content, 1144 } 1145 1146 additionalConfigContent = append(additionalConfigContent, addContent) 1147 } 1148 config.AdditionalUnattendContent = &additionalConfigContent 1149 } 1150 } 1151 return config, nil 1152 } 1153 1154 func expandAzureRmVirtualMachineDataDisk(d *schema.ResourceData) ([]compute.DataDisk, error) { 1155 disks := d.Get("storage_data_disk").([]interface{}) 1156 data_disks := make([]compute.DataDisk, 0, len(disks)) 1157 for _, disk_config := range disks { 1158 config := disk_config.(map[string]interface{}) 1159 1160 name := config["name"].(string) 1161 vhd := config["vhd_uri"].(string) 1162 createOption := config["create_option"].(string) 1163 lun := int32(config["lun"].(int)) 1164 disk_size := int32(config["disk_size_gb"].(int)) 1165 1166 data_disk := compute.DataDisk{ 1167 Name: &name, 1168 Vhd: &compute.VirtualHardDisk{ 1169 URI: &vhd, 1170 }, 1171 Lun: &lun, 1172 DiskSizeGB: &disk_size, 1173 CreateOption: compute.DiskCreateOptionTypes(createOption), 1174 } 1175 1176 data_disks = append(data_disks, data_disk) 1177 } 1178 1179 return data_disks, nil 1180 } 1181 1182 func expandAzureRmVirtualMachineDiagnosticsProfile(d *schema.ResourceData) *compute.DiagnosticsProfile { 1183 bootDiagnostics := d.Get("boot_diagnostics").([]interface{}) 1184 1185 diagnosticsProfile := &compute.DiagnosticsProfile{} 1186 if len(bootDiagnostics) > 0 { 1187 bootDiagnostic := bootDiagnostics[0].(map[string]interface{}) 1188 1189 diagnostic := &compute.BootDiagnostics{ 1190 Enabled: riviera.Bool(bootDiagnostic["enabled"].(bool)), 1191 StorageURI: riviera.String(bootDiagnostic["storage_uri"].(string)), 1192 } 1193 1194 diagnosticsProfile.BootDiagnostics = diagnostic 1195 1196 return diagnosticsProfile 1197 } 1198 1199 return nil 1200 } 1201 1202 func expandAzureRmVirtualMachineImageReference(d *schema.ResourceData) (*compute.ImageReference, error) { 1203 storageImageRefs := d.Get("storage_image_reference").(*schema.Set).List() 1204 1205 storageImageRef := storageImageRefs[0].(map[string]interface{}) 1206 1207 publisher := storageImageRef["publisher"].(string) 1208 offer := storageImageRef["offer"].(string) 1209 sku := storageImageRef["sku"].(string) 1210 version := storageImageRef["version"].(string) 1211 1212 return &compute.ImageReference{ 1213 Publisher: &publisher, 1214 Offer: &offer, 1215 Sku: &sku, 1216 Version: &version, 1217 }, nil 1218 } 1219 1220 func expandAzureRmVirtualMachineNetworkProfile(d *schema.ResourceData) compute.NetworkProfile { 1221 nicIds := d.Get("network_interface_ids").(*schema.Set).List() 1222 network_interfaces := make([]compute.NetworkInterfaceReference, 0, len(nicIds)) 1223 1224 network_profile := compute.NetworkProfile{} 1225 1226 for _, nic := range nicIds { 1227 id := nic.(string) 1228 network_interface := compute.NetworkInterfaceReference{ 1229 ID: &id, 1230 } 1231 network_interfaces = append(network_interfaces, network_interface) 1232 } 1233 1234 network_profile.NetworkInterfaces = &network_interfaces 1235 1236 return network_profile 1237 } 1238 1239 func expandAzureRmVirtualMachineOsDisk(d *schema.ResourceData) (*compute.OSDisk, error) { 1240 disks := d.Get("storage_os_disk").(*schema.Set).List() 1241 1242 disk := disks[0].(map[string]interface{}) 1243 1244 name := disk["name"].(string) 1245 vhdURI := disk["vhd_uri"].(string) 1246 imageURI := disk["image_uri"].(string) 1247 createOption := disk["create_option"].(string) 1248 1249 osDisk := &compute.OSDisk{ 1250 Name: &name, 1251 Vhd: &compute.VirtualHardDisk{ 1252 URI: &vhdURI, 1253 }, 1254 CreateOption: compute.DiskCreateOptionTypes(createOption), 1255 } 1256 1257 if v := disk["image_uri"].(string); v != "" { 1258 osDisk.Image = &compute.VirtualHardDisk{ 1259 URI: &imageURI, 1260 } 1261 } 1262 1263 if v := disk["os_type"].(string); v != "" { 1264 if v == "linux" { 1265 osDisk.OsType = compute.Linux 1266 } else if v == "windows" { 1267 osDisk.OsType = compute.Windows 1268 } else { 1269 return nil, fmt.Errorf("[ERROR] os_type must be 'linux' or 'windows'") 1270 } 1271 } 1272 1273 if v := disk["caching"].(string); v != "" { 1274 osDisk.Caching = compute.CachingTypes(v) 1275 } 1276 1277 if v := disk["disk_size_gb"].(int); v != 0 { 1278 diskSize := int32(v) 1279 osDisk.DiskSizeGB = &diskSize 1280 } 1281 1282 return osDisk, nil 1283 } 1284 1285 func findStorageAccountResourceGroup(meta interface{}, storageAccountName string) (string, error) { 1286 client := meta.(*ArmClient).resourceFindClient 1287 filter := fmt.Sprintf("name eq '%s' and resourceType eq 'Microsoft.Storage/storageAccounts'", storageAccountName) 1288 expand := "" 1289 var pager *int32 1290 1291 rf, err := client.List(filter, expand, pager) 1292 if err != nil { 1293 return "", fmt.Errorf("Error making resource request for query %s: %s", filter, err) 1294 } 1295 1296 results := *rf.Value 1297 if len(results) != 1 { 1298 return "", fmt.Errorf("Wrong number of results making resource request for query %s: %s", filter, len(results)) 1299 } 1300 1301 id, err := parseAzureResourceID(*results[0].ID) 1302 if err != nil { 1303 return "", err 1304 } 1305 1306 return id.ResourceGroup, nil 1307 }