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