github.com/peterbale/terraform@v0.9.0-beta2.0.20170315142748-5723acd55547/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 StateFunc: userDataStateFunc, 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 result["custom_data"] = *osProfile.CustomData 891 } 892 893 return []interface{}{result} 894 } 895 896 func flattenAzureRmVirtualMachineOsProfileWindowsConfiguration(config *compute.WindowsConfiguration) []interface{} { 897 result := make(map[string]interface{}) 898 899 if config.ProvisionVMAgent != nil { 900 result["provision_vm_agent"] = *config.ProvisionVMAgent 901 } 902 903 if config.EnableAutomaticUpdates != nil { 904 result["enable_automatic_upgrades"] = *config.EnableAutomaticUpdates 905 } 906 907 if config.WinRM != nil { 908 listeners := make([]map[string]interface{}, 0, len(*config.WinRM.Listeners)) 909 for _, i := range *config.WinRM.Listeners { 910 listener := make(map[string]interface{}) 911 listener["protocol"] = i.Protocol 912 913 if i.CertificateURL != nil { 914 listener["certificate_url"] = *i.CertificateURL 915 } 916 917 listeners = append(listeners, listener) 918 } 919 920 result["winrm"] = listeners 921 } 922 923 if config.AdditionalUnattendContent != nil { 924 content := make([]map[string]interface{}, 0, len(*config.AdditionalUnattendContent)) 925 for _, i := range *config.AdditionalUnattendContent { 926 c := make(map[string]interface{}) 927 c["pass"] = i.PassName 928 c["component"] = i.ComponentName 929 c["setting_name"] = i.SettingName 930 931 if i.Content != nil { 932 c["content"] = *i.Content 933 } 934 935 content = append(content, c) 936 } 937 938 result["additional_unattend_config"] = content 939 } 940 941 return []interface{}{result} 942 } 943 944 func flattenAzureRmVirtualMachineOsProfileLinuxConfiguration(config *compute.LinuxConfiguration) []interface{} { 945 946 result := make(map[string]interface{}) 947 result["disable_password_authentication"] = *config.DisablePasswordAuthentication 948 949 if config.SSH != nil && len(*config.SSH.PublicKeys) > 0 { 950 ssh_keys := make([]map[string]interface{}, len(*config.SSH.PublicKeys)) 951 for _, i := range *config.SSH.PublicKeys { 952 key := make(map[string]interface{}) 953 key["path"] = *i.Path 954 955 if i.KeyData != nil { 956 key["key_data"] = *i.KeyData 957 } 958 959 ssh_keys = append(ssh_keys, key) 960 } 961 962 result["ssh_keys"] = ssh_keys 963 } 964 965 return []interface{}{result} 966 } 967 968 func flattenAzureRmVirtualMachineOsDisk(disk *compute.OSDisk) []interface{} { 969 result := make(map[string]interface{}) 970 result["name"] = *disk.Name 971 result["vhd_uri"] = *disk.Vhd.URI 972 result["create_option"] = disk.CreateOption 973 result["caching"] = disk.Caching 974 if disk.DiskSizeGB != nil { 975 result["disk_size_gb"] = *disk.DiskSizeGB 976 } 977 978 return []interface{}{result} 979 } 980 981 func expandAzureRmVirtualMachinePlan(d *schema.ResourceData) (*compute.Plan, error) { 982 planConfigs := d.Get("plan").(*schema.Set).List() 983 984 planConfig := planConfigs[0].(map[string]interface{}) 985 986 publisher := planConfig["publisher"].(string) 987 name := planConfig["name"].(string) 988 product := planConfig["product"].(string) 989 990 return &compute.Plan{ 991 Publisher: &publisher, 992 Name: &name, 993 Product: &product, 994 }, nil 995 } 996 997 func expandAzureRmVirtualMachineOsProfile(d *schema.ResourceData) (*compute.OSProfile, error) { 998 osProfiles := d.Get("os_profile").(*schema.Set).List() 999 1000 osProfile := osProfiles[0].(map[string]interface{}) 1001 1002 adminUsername := osProfile["admin_username"].(string) 1003 adminPassword := osProfile["admin_password"].(string) 1004 computerName := osProfile["computer_name"].(string) 1005 1006 profile := &compute.OSProfile{ 1007 AdminUsername: &adminUsername, 1008 ComputerName: &computerName, 1009 } 1010 1011 if adminPassword != "" { 1012 profile.AdminPassword = &adminPassword 1013 } 1014 1015 if _, ok := d.GetOk("os_profile_windows_config"); ok { 1016 winConfig, err := expandAzureRmVirtualMachineOsProfileWindowsConfig(d) 1017 if err != nil { 1018 return nil, err 1019 } 1020 if winConfig != nil { 1021 profile.WindowsConfiguration = winConfig 1022 } 1023 } 1024 1025 if _, ok := d.GetOk("os_profile_linux_config"); ok { 1026 linuxConfig, err := expandAzureRmVirtualMachineOsProfileLinuxConfig(d) 1027 if err != nil { 1028 return nil, err 1029 } 1030 if linuxConfig != nil { 1031 profile.LinuxConfiguration = linuxConfig 1032 } 1033 } 1034 1035 if _, ok := d.GetOk("os_profile_secrets"); ok { 1036 secrets := expandAzureRmVirtualMachineOsProfileSecrets(d) 1037 if secrets != nil { 1038 profile.Secrets = secrets 1039 } 1040 } 1041 1042 if v := osProfile["custom_data"].(string); v != "" { 1043 v = base64Encode(v) 1044 profile.CustomData = &v 1045 } 1046 1047 return profile, nil 1048 } 1049 1050 func expandAzureRmVirtualMachineOsProfileSecrets(d *schema.ResourceData) *[]compute.VaultSecretGroup { 1051 secretsConfig := d.Get("os_profile_secrets").(*schema.Set).List() 1052 secrets := make([]compute.VaultSecretGroup, 0, len(secretsConfig)) 1053 1054 for _, secretConfig := range secretsConfig { 1055 config := secretConfig.(map[string]interface{}) 1056 sourceVaultId := config["source_vault_id"].(string) 1057 1058 vaultSecretGroup := compute.VaultSecretGroup{ 1059 SourceVault: &compute.SubResource{ 1060 ID: &sourceVaultId, 1061 }, 1062 } 1063 1064 if v := config["vault_certificates"]; v != nil { 1065 certsConfig := v.([]interface{}) 1066 certs := make([]compute.VaultCertificate, 0, len(certsConfig)) 1067 for _, certConfig := range certsConfig { 1068 config := certConfig.(map[string]interface{}) 1069 1070 certUrl := config["certificate_url"].(string) 1071 cert := compute.VaultCertificate{ 1072 CertificateURL: &certUrl, 1073 } 1074 if v := config["certificate_store"].(string); v != "" { 1075 cert.CertificateStore = &v 1076 } 1077 1078 certs = append(certs, cert) 1079 } 1080 vaultSecretGroup.VaultCertificates = &certs 1081 } 1082 1083 secrets = append(secrets, vaultSecretGroup) 1084 } 1085 1086 return &secrets 1087 } 1088 1089 func expandAzureRmVirtualMachineOsProfileLinuxConfig(d *schema.ResourceData) (*compute.LinuxConfiguration, error) { 1090 osProfilesLinuxConfig := d.Get("os_profile_linux_config").(*schema.Set).List() 1091 1092 linuxConfig := osProfilesLinuxConfig[0].(map[string]interface{}) 1093 disablePasswordAuth := linuxConfig["disable_password_authentication"].(bool) 1094 1095 config := &compute.LinuxConfiguration{ 1096 DisablePasswordAuthentication: &disablePasswordAuth, 1097 } 1098 1099 linuxKeys := linuxConfig["ssh_keys"].([]interface{}) 1100 sshPublicKeys := []compute.SSHPublicKey{} 1101 for _, key := range linuxKeys { 1102 1103 sshKey, ok := key.(map[string]interface{}) 1104 if !ok { 1105 continue 1106 } 1107 path := sshKey["path"].(string) 1108 keyData := sshKey["key_data"].(string) 1109 1110 sshPublicKey := compute.SSHPublicKey{ 1111 Path: &path, 1112 KeyData: &keyData, 1113 } 1114 1115 sshPublicKeys = append(sshPublicKeys, sshPublicKey) 1116 } 1117 1118 if len(sshPublicKeys) > 0 { 1119 config.SSH = &compute.SSHConfiguration{ 1120 PublicKeys: &sshPublicKeys, 1121 } 1122 } 1123 1124 return config, nil 1125 } 1126 1127 func expandAzureRmVirtualMachineOsProfileWindowsConfig(d *schema.ResourceData) (*compute.WindowsConfiguration, error) { 1128 osProfilesWindowsConfig := d.Get("os_profile_windows_config").(*schema.Set).List() 1129 1130 osProfileConfig := osProfilesWindowsConfig[0].(map[string]interface{}) 1131 config := &compute.WindowsConfiguration{} 1132 1133 if v := osProfileConfig["provision_vm_agent"]; v != nil { 1134 provision := v.(bool) 1135 config.ProvisionVMAgent = &provision 1136 } 1137 1138 if v := osProfileConfig["enable_automatic_upgrades"]; v != nil { 1139 update := v.(bool) 1140 config.EnableAutomaticUpdates = &update 1141 } 1142 1143 if v := osProfileConfig["winrm"]; v != nil { 1144 winRm := v.([]interface{}) 1145 if len(winRm) > 0 { 1146 winRmListners := make([]compute.WinRMListener, 0, len(winRm)) 1147 for _, winRmConfig := range winRm { 1148 config := winRmConfig.(map[string]interface{}) 1149 1150 protocol := config["protocol"].(string) 1151 winRmListner := compute.WinRMListener{ 1152 Protocol: compute.ProtocolTypes(protocol), 1153 } 1154 if v := config["certificate_url"].(string); v != "" { 1155 winRmListner.CertificateURL = &v 1156 } 1157 1158 winRmListners = append(winRmListners, winRmListner) 1159 } 1160 config.WinRM = &compute.WinRMConfiguration{ 1161 Listeners: &winRmListners, 1162 } 1163 } 1164 } 1165 if v := osProfileConfig["additional_unattend_config"]; v != nil { 1166 additionalConfig := v.([]interface{}) 1167 if len(additionalConfig) > 0 { 1168 additionalConfigContent := make([]compute.AdditionalUnattendContent, 0, len(additionalConfig)) 1169 for _, addConfig := range additionalConfig { 1170 config := addConfig.(map[string]interface{}) 1171 pass := config["pass"].(string) 1172 component := config["component"].(string) 1173 settingName := config["setting_name"].(string) 1174 content := config["content"].(string) 1175 1176 addContent := compute.AdditionalUnattendContent{ 1177 PassName: compute.PassNames(pass), 1178 ComponentName: compute.ComponentNames(component), 1179 SettingName: compute.SettingNames(settingName), 1180 Content: &content, 1181 } 1182 1183 additionalConfigContent = append(additionalConfigContent, addContent) 1184 } 1185 config.AdditionalUnattendContent = &additionalConfigContent 1186 } 1187 } 1188 return config, nil 1189 } 1190 1191 func expandAzureRmVirtualMachineDataDisk(d *schema.ResourceData) ([]compute.DataDisk, error) { 1192 disks := d.Get("storage_data_disk").([]interface{}) 1193 data_disks := make([]compute.DataDisk, 0, len(disks)) 1194 for _, disk_config := range disks { 1195 config := disk_config.(map[string]interface{}) 1196 1197 name := config["name"].(string) 1198 vhd := config["vhd_uri"].(string) 1199 createOption := config["create_option"].(string) 1200 lun := int32(config["lun"].(int)) 1201 1202 data_disk := compute.DataDisk{ 1203 Name: &name, 1204 Vhd: &compute.VirtualHardDisk{ 1205 URI: &vhd, 1206 }, 1207 Lun: &lun, 1208 CreateOption: compute.DiskCreateOptionTypes(createOption), 1209 } 1210 1211 if v := config["caching"].(string); v != "" { 1212 data_disk.Caching = compute.CachingTypes(v) 1213 } 1214 1215 if v := config["disk_size_gb"]; v != nil { 1216 diskSize := int32(config["disk_size_gb"].(int)) 1217 data_disk.DiskSizeGB = &diskSize 1218 } 1219 1220 data_disks = append(data_disks, data_disk) 1221 } 1222 1223 return data_disks, nil 1224 } 1225 1226 func expandAzureRmVirtualMachineDiagnosticsProfile(d *schema.ResourceData) *compute.DiagnosticsProfile { 1227 bootDiagnostics := d.Get("boot_diagnostics").([]interface{}) 1228 1229 diagnosticsProfile := &compute.DiagnosticsProfile{} 1230 if len(bootDiagnostics) > 0 { 1231 bootDiagnostic := bootDiagnostics[0].(map[string]interface{}) 1232 1233 diagnostic := &compute.BootDiagnostics{ 1234 Enabled: riviera.Bool(bootDiagnostic["enabled"].(bool)), 1235 StorageURI: riviera.String(bootDiagnostic["storage_uri"].(string)), 1236 } 1237 1238 diagnosticsProfile.BootDiagnostics = diagnostic 1239 1240 return diagnosticsProfile 1241 } 1242 1243 return nil 1244 } 1245 1246 func expandAzureRmVirtualMachineImageReference(d *schema.ResourceData) (*compute.ImageReference, error) { 1247 storageImageRefs := d.Get("storage_image_reference").(*schema.Set).List() 1248 1249 storageImageRef := storageImageRefs[0].(map[string]interface{}) 1250 1251 publisher := storageImageRef["publisher"].(string) 1252 offer := storageImageRef["offer"].(string) 1253 sku := storageImageRef["sku"].(string) 1254 version := storageImageRef["version"].(string) 1255 1256 return &compute.ImageReference{ 1257 Publisher: &publisher, 1258 Offer: &offer, 1259 Sku: &sku, 1260 Version: &version, 1261 }, nil 1262 } 1263 1264 func expandAzureRmVirtualMachineNetworkProfile(d *schema.ResourceData) compute.NetworkProfile { 1265 nicIds := d.Get("network_interface_ids").(*schema.Set).List() 1266 network_interfaces := make([]compute.NetworkInterfaceReference, 0, len(nicIds)) 1267 1268 network_profile := compute.NetworkProfile{} 1269 1270 for _, nic := range nicIds { 1271 id := nic.(string) 1272 network_interface := compute.NetworkInterfaceReference{ 1273 ID: &id, 1274 } 1275 network_interfaces = append(network_interfaces, network_interface) 1276 } 1277 1278 network_profile.NetworkInterfaces = &network_interfaces 1279 1280 return network_profile 1281 } 1282 1283 func expandAzureRmVirtualMachineOsDisk(d *schema.ResourceData) (*compute.OSDisk, error) { 1284 disks := d.Get("storage_os_disk").(*schema.Set).List() 1285 1286 disk := disks[0].(map[string]interface{}) 1287 1288 name := disk["name"].(string) 1289 vhdURI := disk["vhd_uri"].(string) 1290 imageURI := disk["image_uri"].(string) 1291 createOption := disk["create_option"].(string) 1292 1293 osDisk := &compute.OSDisk{ 1294 Name: &name, 1295 Vhd: &compute.VirtualHardDisk{ 1296 URI: &vhdURI, 1297 }, 1298 CreateOption: compute.DiskCreateOptionTypes(createOption), 1299 } 1300 1301 if v := disk["image_uri"].(string); v != "" { 1302 osDisk.Image = &compute.VirtualHardDisk{ 1303 URI: &imageURI, 1304 } 1305 } 1306 1307 if v := disk["os_type"].(string); v != "" { 1308 if v == "linux" { 1309 osDisk.OsType = compute.Linux 1310 } else if v == "windows" { 1311 osDisk.OsType = compute.Windows 1312 } else { 1313 return nil, fmt.Errorf("[ERROR] os_type must be 'linux' or 'windows'") 1314 } 1315 } 1316 1317 if v := disk["caching"].(string); v != "" { 1318 osDisk.Caching = compute.CachingTypes(v) 1319 } 1320 1321 if v := disk["disk_size_gb"].(int); v != 0 { 1322 diskSize := int32(v) 1323 osDisk.DiskSizeGB = &diskSize 1324 } 1325 1326 return osDisk, nil 1327 } 1328 1329 func findStorageAccountResourceGroup(meta interface{}, storageAccountName string) (string, error) { 1330 client := meta.(*ArmClient).resourceFindClient 1331 filter := fmt.Sprintf("name eq '%s' and resourceType eq 'Microsoft.Storage/storageAccounts'", storageAccountName) 1332 expand := "" 1333 var pager *int32 1334 1335 rf, err := client.List(filter, expand, pager) 1336 if err != nil { 1337 return "", fmt.Errorf("Error making resource request for query %s: %s", filter, err) 1338 } 1339 1340 results := *rf.Value 1341 if len(results) != 1 { 1342 return "", fmt.Errorf("Wrong number of results making resource request for query %s: %d", filter, len(results)) 1343 } 1344 1345 id, err := parseAzureResourceID(*results[0].ID) 1346 if err != nil { 1347 return "", err 1348 } 1349 1350 return id.ResourceGroup, nil 1351 }