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