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