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