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