github.com/IBM-Cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/builtin/providers/azurerm/resource_arm_virtual_machine_scale_set.go (about) 1 package azurerm 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "net/http" 8 9 "github.com/Azure/azure-sdk-for-go/arm/compute" 10 "github.com/hashicorp/terraform/helper/hashcode" 11 "github.com/hashicorp/terraform/helper/schema" 12 "github.com/hashicorp/terraform/helper/structure" 13 "github.com/hashicorp/terraform/helper/validation" 14 ) 15 16 func resourceArmVirtualMachineScaleSet() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceArmVirtualMachineScaleSetCreate, 19 Read: resourceArmVirtualMachineScaleSetRead, 20 Update: resourceArmVirtualMachineScaleSetCreate, 21 Delete: resourceArmVirtualMachineScaleSetDelete, 22 Importer: &schema.ResourceImporter{ 23 State: schema.ImportStatePassthrough, 24 }, 25 26 Schema: map[string]*schema.Schema{ 27 "name": { 28 Type: schema.TypeString, 29 Required: true, 30 ForceNew: true, 31 }, 32 33 "location": locationSchema(), 34 35 "resource_group_name": { 36 Type: schema.TypeString, 37 Required: true, 38 ForceNew: true, 39 }, 40 41 "sku": { 42 Type: schema.TypeSet, 43 Required: true, 44 MaxItems: 1, 45 Elem: &schema.Resource{ 46 Schema: map[string]*schema.Schema{ 47 "name": { 48 Type: schema.TypeString, 49 Required: true, 50 }, 51 52 "tier": { 53 Type: schema.TypeString, 54 Optional: true, 55 Computed: true, 56 }, 57 58 "capacity": { 59 Type: schema.TypeInt, 60 Required: true, 61 }, 62 }, 63 }, 64 Set: resourceArmVirtualMachineScaleSetSkuHash, 65 }, 66 67 "upgrade_policy_mode": { 68 Type: schema.TypeString, 69 Required: true, 70 }, 71 72 "overprovision": { 73 Type: schema.TypeBool, 74 Optional: true, 75 }, 76 77 "os_profile": { 78 Type: schema.TypeSet, 79 Required: true, 80 MaxItems: 1, 81 Elem: &schema.Resource{ 82 Schema: map[string]*schema.Schema{ 83 "computer_name_prefix": { 84 Type: schema.TypeString, 85 Required: true, 86 }, 87 88 "admin_username": { 89 Type: schema.TypeString, 90 Required: true, 91 }, 92 93 "admin_password": { 94 Type: schema.TypeString, 95 Required: true, 96 Sensitive: true, 97 }, 98 99 "custom_data": { 100 Type: schema.TypeString, 101 Optional: true, 102 ForceNew: true, 103 StateFunc: userDataStateFunc, 104 }, 105 }, 106 }, 107 Set: resourceArmVirtualMachineScaleSetsOsProfileHash, 108 }, 109 110 "os_profile_secrets": { 111 Type: schema.TypeSet, 112 Optional: true, 113 Elem: &schema.Resource{ 114 Schema: map[string]*schema.Schema{ 115 "source_vault_id": { 116 Type: schema.TypeString, 117 Required: true, 118 }, 119 120 "vault_certificates": { 121 Type: schema.TypeList, 122 Optional: true, 123 Elem: &schema.Resource{ 124 Schema: map[string]*schema.Schema{ 125 "certificate_url": { 126 Type: schema.TypeString, 127 Required: true, 128 }, 129 "certificate_store": { 130 Type: schema.TypeString, 131 Optional: true, 132 }, 133 }, 134 }, 135 }, 136 }, 137 }, 138 }, 139 140 "os_profile_windows_config": { 141 Type: schema.TypeSet, 142 Optional: true, 143 MaxItems: 1, 144 Elem: &schema.Resource{ 145 Schema: map[string]*schema.Schema{ 146 "provision_vm_agent": { 147 Type: schema.TypeBool, 148 Optional: true, 149 }, 150 "enable_automatic_upgrades": { 151 Type: schema.TypeBool, 152 Optional: true, 153 }, 154 "winrm": { 155 Type: schema.TypeSet, 156 Optional: true, 157 Elem: &schema.Resource{ 158 Schema: map[string]*schema.Schema{ 159 "protocol": { 160 Type: schema.TypeString, 161 Required: true, 162 }, 163 "certificate_url": { 164 Type: schema.TypeString, 165 Optional: true, 166 }, 167 }, 168 }, 169 }, 170 "additional_unattend_config": { 171 Type: schema.TypeSet, 172 Optional: true, 173 Elem: &schema.Resource{ 174 Schema: map[string]*schema.Schema{ 175 "pass": { 176 Type: schema.TypeString, 177 Required: true, 178 }, 179 "component": { 180 Type: schema.TypeString, 181 Required: true, 182 }, 183 "setting_name": { 184 Type: schema.TypeString, 185 Required: true, 186 }, 187 "content": { 188 Type: schema.TypeString, 189 Required: true, 190 }, 191 }, 192 }, 193 }, 194 }, 195 }, 196 Set: resourceArmVirtualMachineScaleSetOsProfileLWindowsConfigHash, 197 }, 198 199 "os_profile_linux_config": { 200 Type: schema.TypeSet, 201 Optional: true, 202 Computed: true, 203 MaxItems: 1, 204 Elem: &schema.Resource{ 205 Schema: map[string]*schema.Schema{ 206 "disable_password_authentication": { 207 Type: schema.TypeBool, 208 Optional: true, 209 Default: false, 210 ForceNew: true, 211 }, 212 "ssh_keys": { 213 Type: schema.TypeList, 214 Optional: true, 215 Elem: &schema.Resource{ 216 Schema: map[string]*schema.Schema{ 217 "path": { 218 Type: schema.TypeString, 219 Required: true, 220 }, 221 "key_data": { 222 Type: schema.TypeString, 223 Optional: true, 224 }, 225 }, 226 }, 227 }, 228 }, 229 }, 230 Set: resourceArmVirtualMachineScaleSetOsProfileLinuxConfigHash, 231 }, 232 233 "network_profile": { 234 Type: schema.TypeSet, 235 Required: true, 236 Elem: &schema.Resource{ 237 Schema: map[string]*schema.Schema{ 238 "name": { 239 Type: schema.TypeString, 240 Required: true, 241 }, 242 243 "primary": { 244 Type: schema.TypeBool, 245 Required: true, 246 }, 247 248 "ip_configuration": { 249 Type: schema.TypeList, 250 Required: true, 251 Elem: &schema.Resource{ 252 Schema: map[string]*schema.Schema{ 253 "name": { 254 Type: schema.TypeString, 255 Required: true, 256 }, 257 258 "subnet_id": { 259 Type: schema.TypeString, 260 Required: true, 261 }, 262 263 "load_balancer_backend_address_pool_ids": { 264 Type: schema.TypeSet, 265 Optional: true, 266 Elem: &schema.Schema{Type: schema.TypeString}, 267 Set: schema.HashString, 268 }, 269 270 "load_balancer_inbound_nat_rules_ids": { 271 Type: schema.TypeSet, 272 Optional: true, 273 Computed: true, 274 Elem: &schema.Schema{Type: schema.TypeString}, 275 Set: schema.HashString, 276 }, 277 }, 278 }, 279 }, 280 }, 281 }, 282 Set: resourceArmVirtualMachineScaleSetNetworkConfigurationHash, 283 }, 284 285 "storage_profile_os_disk": { 286 Type: schema.TypeSet, 287 Required: true, 288 MaxItems: 1, 289 Elem: &schema.Resource{ 290 Schema: map[string]*schema.Schema{ 291 "name": { 292 Type: schema.TypeString, 293 Required: true, 294 }, 295 296 "image": { 297 Type: schema.TypeString, 298 Optional: true, 299 }, 300 301 "vhd_containers": { 302 Type: schema.TypeSet, 303 Optional: true, 304 Elem: &schema.Schema{Type: schema.TypeString}, 305 Set: schema.HashString, 306 }, 307 308 "managed_disk_type": { 309 Type: schema.TypeString, 310 Optional: true, 311 Computed: true, 312 ConflictsWith: []string{"storage_profile_os_disk.vhd_containers"}, 313 ValidateFunc: validation.StringInSlice([]string{ 314 string(compute.PremiumLRS), 315 string(compute.StandardLRS), 316 }, true), 317 }, 318 319 "caching": { 320 Type: schema.TypeString, 321 Optional: true, 322 Computed: true, 323 }, 324 325 "os_type": { 326 Type: schema.TypeString, 327 Optional: true, 328 }, 329 330 "create_option": { 331 Type: schema.TypeString, 332 Required: true, 333 }, 334 }, 335 }, 336 Set: resourceArmVirtualMachineScaleSetStorageProfileOsDiskHash, 337 }, 338 339 "storage_profile_image_reference": { 340 Type: schema.TypeSet, 341 Optional: true, 342 Computed: true, 343 MaxItems: 1, 344 Elem: &schema.Resource{ 345 Schema: map[string]*schema.Schema{ 346 "publisher": { 347 Type: schema.TypeString, 348 Required: true, 349 }, 350 351 "offer": { 352 Type: schema.TypeString, 353 Required: true, 354 }, 355 356 "sku": { 357 Type: schema.TypeString, 358 Required: true, 359 }, 360 361 "version": { 362 Type: schema.TypeString, 363 Required: true, 364 }, 365 }, 366 }, 367 Set: resourceArmVirtualMachineScaleSetStorageProfileImageReferenceHash, 368 }, 369 370 "extension": { 371 Type: schema.TypeSet, 372 Optional: true, 373 Elem: &schema.Resource{ 374 Schema: map[string]*schema.Schema{ 375 "name": { 376 Type: schema.TypeString, 377 Required: true, 378 }, 379 380 "publisher": { 381 Type: schema.TypeString, 382 Required: true, 383 }, 384 385 "type": { 386 Type: schema.TypeString, 387 Required: true, 388 }, 389 390 "type_handler_version": { 391 Type: schema.TypeString, 392 Required: true, 393 }, 394 395 "auto_upgrade_minor_version": { 396 Type: schema.TypeBool, 397 Optional: true, 398 }, 399 400 "settings": { 401 Type: schema.TypeString, 402 Optional: true, 403 ValidateFunc: validation.ValidateJsonString, 404 DiffSuppressFunc: structure.SuppressJsonDiff, 405 }, 406 407 "protected_settings": { 408 Type: schema.TypeString, 409 Optional: true, 410 Sensitive: true, 411 ValidateFunc: validation.ValidateJsonString, 412 DiffSuppressFunc: structure.SuppressJsonDiff, 413 }, 414 }, 415 }, 416 Set: resourceArmVirtualMachineScaleSetExtensionHash, 417 }, 418 419 "tags": tagsSchema(), 420 }, 421 } 422 } 423 424 func resourceArmVirtualMachineScaleSetCreate(d *schema.ResourceData, meta interface{}) error { 425 client := meta.(*ArmClient) 426 vmScaleSetClient := client.vmScaleSetClient 427 428 log.Printf("[INFO] preparing arguments for Azure ARM Virtual Machine Scale Set creation.") 429 430 name := d.Get("name").(string) 431 location := d.Get("location").(string) 432 resGroup := d.Get("resource_group_name").(string) 433 tags := d.Get("tags").(map[string]interface{}) 434 435 sku, err := expandVirtualMachineScaleSetSku(d) 436 if err != nil { 437 return err 438 } 439 440 storageProfile := compute.VirtualMachineScaleSetStorageProfile{} 441 osDisk, err := expandAzureRMVirtualMachineScaleSetsStorageProfileOsDisk(d) 442 if err != nil { 443 return err 444 } 445 storageProfile.OsDisk = osDisk 446 if _, ok := d.GetOk("storage_profile_image_reference"); ok { 447 imageRef, err := expandAzureRmVirtualMachineScaleSetStorageProfileImageReference(d) 448 if err != nil { 449 return err 450 } 451 storageProfile.ImageReference = imageRef 452 } 453 454 osProfile, err := expandAzureRMVirtualMachineScaleSetsOsProfile(d) 455 if err != nil { 456 return err 457 } 458 459 extensions, err := expandAzureRMVirtualMachineScaleSetExtensions(d) 460 if err != nil { 461 return err 462 } 463 464 updatePolicy := d.Get("upgrade_policy_mode").(string) 465 overprovision := d.Get("overprovision").(bool) 466 scaleSetProps := compute.VirtualMachineScaleSetProperties{ 467 UpgradePolicy: &compute.UpgradePolicy{ 468 Mode: compute.UpgradeMode(updatePolicy), 469 }, 470 VirtualMachineProfile: &compute.VirtualMachineScaleSetVMProfile{ 471 NetworkProfile: expandAzureRmVirtualMachineScaleSetNetworkProfile(d), 472 StorageProfile: &storageProfile, 473 OsProfile: osProfile, 474 ExtensionProfile: extensions, 475 }, 476 Overprovision: &overprovision, 477 } 478 479 scaleSetParams := compute.VirtualMachineScaleSet{ 480 Name: &name, 481 Location: &location, 482 Tags: expandTags(tags), 483 Sku: sku, 484 VirtualMachineScaleSetProperties: &scaleSetProps, 485 } 486 _, vmErr := vmScaleSetClient.CreateOrUpdate(resGroup, name, scaleSetParams, make(chan struct{})) 487 if vmErr != nil { 488 return vmErr 489 } 490 491 read, err := vmScaleSetClient.Get(resGroup, name) 492 if err != nil { 493 return err 494 } 495 if read.ID == nil { 496 return fmt.Errorf("Cannot read Virtual Machine Scale Set %s (resource group %s) ID", name, resGroup) 497 } 498 499 d.SetId(*read.ID) 500 501 return resourceArmVirtualMachineScaleSetRead(d, meta) 502 } 503 504 func resourceArmVirtualMachineScaleSetRead(d *schema.ResourceData, meta interface{}) error { 505 vmScaleSetClient := meta.(*ArmClient).vmScaleSetClient 506 507 id, err := parseAzureResourceID(d.Id()) 508 if err != nil { 509 return err 510 } 511 resGroup := id.ResourceGroup 512 name := id.Path["virtualMachineScaleSets"] 513 514 resp, err := vmScaleSetClient.Get(resGroup, name) 515 if err != nil { 516 if resp.StatusCode == http.StatusNotFound { 517 log.Printf("[INFO] AzureRM Virtual Machine Scale Set (%s) Not Found. Removing from State", name) 518 d.SetId("") 519 return nil 520 } 521 return fmt.Errorf("Error making Read request on Azure Virtual Machine Scale Set %s: %s", name, err) 522 } 523 524 d.Set("name", resp.Name) 525 d.Set("resource_group_name", resGroup) 526 d.Set("location", azureRMNormalizeLocation(*resp.Location)) 527 528 if err := d.Set("sku", flattenAzureRmVirtualMachineScaleSetSku(resp.Sku)); err != nil { 529 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Sku error: %#v", err) 530 } 531 532 properties := resp.VirtualMachineScaleSetProperties 533 534 d.Set("upgrade_policy_mode", properties.UpgradePolicy.Mode) 535 d.Set("overprovision", properties.Overprovision) 536 537 osProfile, err := flattenAzureRMVirtualMachineScaleSetOsProfile(properties.VirtualMachineProfile.OsProfile) 538 if err != nil { 539 return fmt.Errorf("[DEBUG] Error flattening Virtual Machine Scale Set OS Profile. Error: %#v", err) 540 } 541 542 if err := d.Set("os_profile", osProfile); err != nil { 543 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile error: %#v", err) 544 } 545 546 if properties.VirtualMachineProfile.OsProfile.Secrets != nil { 547 if err := d.Set("os_profile_secrets", flattenAzureRmVirtualMachineScaleSetOsProfileSecrets(properties.VirtualMachineProfile.OsProfile.Secrets)); err != nil { 548 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile Secrets error: %#v", err) 549 } 550 } 551 552 if properties.VirtualMachineProfile.OsProfile.WindowsConfiguration != nil { 553 if err := d.Set("os_profile_windows_config", flattenAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(properties.VirtualMachineProfile.OsProfile.WindowsConfiguration)); err != nil { 554 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile Windows config error: %#v", err) 555 } 556 } 557 558 if properties.VirtualMachineProfile.OsProfile.LinuxConfiguration != nil { 559 if err := d.Set("os_profile_linux_config", flattenAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(properties.VirtualMachineProfile.OsProfile.LinuxConfiguration)); err != nil { 560 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile Windows config error: %#v", err) 561 } 562 } 563 564 if err := d.Set("network_profile", flattenAzureRmVirtualMachineScaleSetNetworkProfile(properties.VirtualMachineProfile.NetworkProfile)); err != nil { 565 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Network Profile error: %#v", err) 566 } 567 568 if properties.VirtualMachineProfile.StorageProfile.ImageReference != nil { 569 if err := d.Set("storage_profile_image_reference", flattenAzureRmVirtualMachineScaleSetStorageProfileImageReference(properties.VirtualMachineProfile.StorageProfile.ImageReference)); err != nil { 570 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Storage Profile Image Reference error: %#v", err) 571 } 572 } 573 574 if err := d.Set("storage_profile_os_disk", flattenAzureRmVirtualMachineScaleSetStorageProfileOSDisk(properties.VirtualMachineProfile.StorageProfile.OsDisk)); err != nil { 575 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Storage Profile OS Disk error: %#v", err) 576 } 577 578 if properties.VirtualMachineProfile.ExtensionProfile != nil { 579 extension, err := flattenAzureRmVirtualMachineScaleSetExtensionProfile(properties.VirtualMachineProfile.ExtensionProfile) 580 if err != nil { 581 return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Extension Profile error: %#v", err) 582 } 583 d.Set("extension", extension) 584 } 585 586 flattenAndSetTags(d, resp.Tags) 587 588 return nil 589 } 590 591 func resourceArmVirtualMachineScaleSetDelete(d *schema.ResourceData, meta interface{}) error { 592 vmScaleSetClient := meta.(*ArmClient).vmScaleSetClient 593 594 id, err := parseAzureResourceID(d.Id()) 595 if err != nil { 596 return err 597 } 598 resGroup := id.ResourceGroup 599 name := id.Path["virtualMachineScaleSets"] 600 601 _, err = vmScaleSetClient.Delete(resGroup, name, make(chan struct{})) 602 603 return err 604 } 605 606 func flattenAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(config *compute.LinuxConfiguration) []interface{} { 607 result := make(map[string]interface{}) 608 result["disable_password_authentication"] = *config.DisablePasswordAuthentication 609 610 if config.SSH != nil && len(*config.SSH.PublicKeys) > 0 { 611 ssh_keys := make([]map[string]interface{}, 0, len(*config.SSH.PublicKeys)) 612 for _, i := range *config.SSH.PublicKeys { 613 key := make(map[string]interface{}) 614 key["path"] = *i.Path 615 616 if i.KeyData != nil { 617 key["key_data"] = *i.KeyData 618 } 619 620 ssh_keys = append(ssh_keys, key) 621 } 622 623 result["ssh_keys"] = ssh_keys 624 } 625 626 return []interface{}{result} 627 } 628 629 func flattenAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(config *compute.WindowsConfiguration) []interface{} { 630 result := make(map[string]interface{}) 631 632 if config.ProvisionVMAgent != nil { 633 result["provision_vm_agent"] = *config.ProvisionVMAgent 634 } 635 636 if config.EnableAutomaticUpdates != nil { 637 result["enable_automatic_upgrades"] = *config.EnableAutomaticUpdates 638 } 639 640 if config.WinRM != nil { 641 listeners := make([]map[string]interface{}, 0, len(*config.WinRM.Listeners)) 642 for _, i := range *config.WinRM.Listeners { 643 listener := make(map[string]interface{}) 644 listener["protocol"] = i.Protocol 645 646 if i.CertificateURL != nil { 647 listener["certificate_url"] = *i.CertificateURL 648 } 649 650 listeners = append(listeners, listener) 651 } 652 653 result["winrm"] = listeners 654 } 655 656 if config.AdditionalUnattendContent != nil { 657 content := make([]map[string]interface{}, 0, len(*config.AdditionalUnattendContent)) 658 for _, i := range *config.AdditionalUnattendContent { 659 c := make(map[string]interface{}) 660 c["pass"] = i.PassName 661 c["component"] = i.ComponentName 662 c["setting_name"] = i.SettingName 663 c["content"] = *i.Content 664 665 content = append(content, c) 666 } 667 668 result["additional_unattend_config"] = content 669 } 670 671 return []interface{}{result} 672 } 673 674 func flattenAzureRmVirtualMachineScaleSetOsProfileSecrets(secrets *[]compute.VaultSecretGroup) []map[string]interface{} { 675 result := make([]map[string]interface{}, 0, len(*secrets)) 676 for _, secret := range *secrets { 677 s := map[string]interface{}{ 678 "source_vault_id": *secret.SourceVault.ID, 679 } 680 681 if secret.VaultCertificates != nil { 682 certs := make([]map[string]interface{}, 0, len(*secret.VaultCertificates)) 683 for _, cert := range *secret.VaultCertificates { 684 vaultCert := make(map[string]interface{}) 685 vaultCert["certificate_url"] = *cert.CertificateURL 686 687 if cert.CertificateStore != nil { 688 vaultCert["certificate_store"] = *cert.CertificateStore 689 } 690 691 certs = append(certs, vaultCert) 692 } 693 694 s["vault_certificates"] = certs 695 } 696 697 result = append(result, s) 698 } 699 return result 700 } 701 702 func flattenAzureRmVirtualMachineScaleSetNetworkProfile(profile *compute.VirtualMachineScaleSetNetworkProfile) []map[string]interface{} { 703 networkConfigurations := profile.NetworkInterfaceConfigurations 704 result := make([]map[string]interface{}, 0, len(*networkConfigurations)) 705 for _, netConfig := range *networkConfigurations { 706 s := map[string]interface{}{ 707 "name": *netConfig.Name, 708 "primary": *netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.Primary, 709 } 710 711 if netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.IPConfigurations != nil { 712 ipConfigs := make([]map[string]interface{}, 0, len(*netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.IPConfigurations)) 713 for _, ipConfig := range *netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.IPConfigurations { 714 config := make(map[string]interface{}) 715 config["name"] = *ipConfig.Name 716 717 properties := ipConfig.VirtualMachineScaleSetIPConfigurationProperties 718 719 if ipConfig.VirtualMachineScaleSetIPConfigurationProperties.Subnet != nil { 720 config["subnet_id"] = *properties.Subnet.ID 721 } 722 723 if properties.LoadBalancerBackendAddressPools != nil { 724 addressPools := make([]interface{}, 0, len(*properties.LoadBalancerBackendAddressPools)) 725 for _, pool := range *properties.LoadBalancerBackendAddressPools { 726 addressPools = append(addressPools, *pool.ID) 727 } 728 config["load_balancer_backend_address_pool_ids"] = schema.NewSet(schema.HashString, addressPools) 729 } 730 731 if properties.LoadBalancerInboundNatPools != nil { 732 inboundNatPools := make([]interface{}, 0, len(*properties.LoadBalancerInboundNatPools)) 733 for _, rule := range *properties.LoadBalancerInboundNatPools { 734 inboundNatPools = append(inboundNatPools, *rule.ID) 735 } 736 config["load_balancer_inbound_nat_rules_ids"] = schema.NewSet(schema.HashString, inboundNatPools) 737 } 738 739 ipConfigs = append(ipConfigs, config) 740 } 741 742 s["ip_configuration"] = ipConfigs 743 } 744 745 result = append(result, s) 746 } 747 748 return result 749 } 750 751 func flattenAzureRMVirtualMachineScaleSetOsProfile(profile *compute.VirtualMachineScaleSetOSProfile) ([]interface{}, error) { 752 result := make(map[string]interface{}) 753 754 result["computer_name_prefix"] = *profile.ComputerNamePrefix 755 result["admin_username"] = *profile.AdminUsername 756 757 if profile.CustomData != nil { 758 result["custom_data"] = *profile.CustomData 759 } 760 761 return []interface{}{result}, nil 762 } 763 764 func flattenAzureRmVirtualMachineScaleSetStorageProfileOSDisk(profile *compute.VirtualMachineScaleSetOSDisk) []interface{} { 765 result := make(map[string]interface{}) 766 767 if profile.Name != nil { 768 result["name"] = *profile.Name 769 } 770 771 if profile.Image != nil { 772 result["image"] = *profile.Image.URI 773 } 774 775 if profile.VhdContainers != nil { 776 containers := make([]interface{}, 0, len(*profile.VhdContainers)) 777 for _, container := range *profile.VhdContainers { 778 containers = append(containers, container) 779 } 780 result["vhd_containers"] = schema.NewSet(schema.HashString, containers) 781 } 782 783 if profile.ManagedDisk != nil { 784 result["managed_disk_type"] = string(profile.ManagedDisk.StorageAccountType) 785 } 786 787 result["caching"] = profile.Caching 788 result["create_option"] = profile.CreateOption 789 result["os_type"] = profile.OsType 790 791 return []interface{}{result} 792 } 793 794 func flattenAzureRmVirtualMachineScaleSetStorageProfileImageReference(profile *compute.ImageReference) []interface{} { 795 result := make(map[string]interface{}) 796 result["publisher"] = *profile.Publisher 797 result["offer"] = *profile.Offer 798 result["sku"] = *profile.Sku 799 result["version"] = *profile.Version 800 801 return []interface{}{result} 802 } 803 804 func flattenAzureRmVirtualMachineScaleSetSku(sku *compute.Sku) []interface{} { 805 result := make(map[string]interface{}) 806 result["name"] = *sku.Name 807 result["capacity"] = *sku.Capacity 808 809 if *sku.Tier != "" { 810 result["tier"] = *sku.Tier 811 } 812 813 return []interface{}{result} 814 } 815 816 func flattenAzureRmVirtualMachineScaleSetExtensionProfile(profile *compute.VirtualMachineScaleSetExtensionProfile) ([]map[string]interface{}, error) { 817 if profile.Extensions == nil { 818 return nil, nil 819 } 820 821 result := make([]map[string]interface{}, 0, len(*profile.Extensions)) 822 for _, extension := range *profile.Extensions { 823 e := make(map[string]interface{}) 824 e["name"] = *extension.Name 825 properties := extension.VirtualMachineScaleSetExtensionProperties 826 if properties != nil { 827 e["publisher"] = *properties.Publisher 828 e["type"] = *properties.Type 829 e["type_handler_version"] = *properties.TypeHandlerVersion 830 if properties.AutoUpgradeMinorVersion != nil { 831 e["auto_upgrade_minor_version"] = *properties.AutoUpgradeMinorVersion 832 } 833 834 if properties.Settings != nil { 835 settings, err := structure.FlattenJsonToString(*properties.Settings) 836 if err != nil { 837 return nil, err 838 } 839 e["settings"] = settings 840 } 841 } 842 843 result = append(result, e) 844 } 845 846 return result, nil 847 } 848 849 func resourceArmVirtualMachineScaleSetStorageProfileImageReferenceHash(v interface{}) int { 850 var buf bytes.Buffer 851 m := v.(map[string]interface{}) 852 buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string))) 853 buf.WriteString(fmt.Sprintf("%s-", m["offer"].(string))) 854 buf.WriteString(fmt.Sprintf("%s-", m["sku"].(string))) 855 buf.WriteString(fmt.Sprintf("%s-", m["version"].(string))) 856 857 return hashcode.String(buf.String()) 858 } 859 860 func resourceArmVirtualMachineScaleSetSkuHash(v interface{}) int { 861 var buf bytes.Buffer 862 m := v.(map[string]interface{}) 863 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 864 if m["tier"] != nil { 865 buf.WriteString(fmt.Sprintf("%s-", m["tier"].(string))) 866 } 867 buf.WriteString(fmt.Sprintf("%d-", m["capacity"].(int))) 868 869 return hashcode.String(buf.String()) 870 } 871 872 func resourceArmVirtualMachineScaleSetStorageProfileOsDiskHash(v interface{}) int { 873 var buf bytes.Buffer 874 m := v.(map[string]interface{}) 875 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 876 877 if m["vhd_containers"] != nil { 878 buf.WriteString(fmt.Sprintf("%s-", m["vhd_containers"].(*schema.Set).List())) 879 } 880 881 return hashcode.String(buf.String()) 882 } 883 884 func resourceArmVirtualMachineScaleSetNetworkConfigurationHash(v interface{}) int { 885 var buf bytes.Buffer 886 m := v.(map[string]interface{}) 887 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 888 buf.WriteString(fmt.Sprintf("%t-", m["primary"].(bool))) 889 return hashcode.String(buf.String()) 890 } 891 892 func resourceArmVirtualMachineScaleSetsOsProfileHash(v interface{}) int { 893 var buf bytes.Buffer 894 m := v.(map[string]interface{}) 895 buf.WriteString(fmt.Sprintf("%s-", m["computer_name_prefix"].(string))) 896 buf.WriteString(fmt.Sprintf("%s-", m["admin_username"].(string))) 897 if m["custom_data"] != nil { 898 customData := m["custom_data"].(string) 899 if !isBase64Encoded(customData) { 900 customData = base64Encode(customData) 901 } 902 buf.WriteString(fmt.Sprintf("%s-", customData)) 903 } 904 return hashcode.String(buf.String()) 905 } 906 907 func resourceArmVirtualMachineScaleSetOsProfileLinuxConfigHash(v interface{}) int { 908 var buf bytes.Buffer 909 m := v.(map[string]interface{}) 910 buf.WriteString(fmt.Sprintf("%t-", m["disable_password_authentication"].(bool))) 911 912 return hashcode.String(buf.String()) 913 } 914 915 func resourceArmVirtualMachineScaleSetOsProfileLWindowsConfigHash(v interface{}) int { 916 var buf bytes.Buffer 917 m := v.(map[string]interface{}) 918 if m["provision_vm_agent"] != nil { 919 buf.WriteString(fmt.Sprintf("%t-", m["provision_vm_agent"].(bool))) 920 } 921 if m["enable_automatic_upgrades"] != nil { 922 buf.WriteString(fmt.Sprintf("%t-", m["enable_automatic_upgrades"].(bool))) 923 } 924 return hashcode.String(buf.String()) 925 } 926 927 func resourceArmVirtualMachineScaleSetExtensionHash(v interface{}) int { 928 var buf bytes.Buffer 929 m := v.(map[string]interface{}) 930 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 931 buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string))) 932 buf.WriteString(fmt.Sprintf("%s-", m["type"].(string))) 933 buf.WriteString(fmt.Sprintf("%s-", m["type_handler_version"].(string))) 934 if m["auto_upgrade_minor_version"] != nil { 935 buf.WriteString(fmt.Sprintf("%t-", m["auto_upgrade_minor_version"].(bool))) 936 } 937 938 return hashcode.String(buf.String()) 939 } 940 941 func expandVirtualMachineScaleSetSku(d *schema.ResourceData) (*compute.Sku, error) { 942 skuConfig := d.Get("sku").(*schema.Set).List() 943 944 config := skuConfig[0].(map[string]interface{}) 945 946 name := config["name"].(string) 947 tier := config["tier"].(string) 948 capacity := int64(config["capacity"].(int)) 949 950 sku := &compute.Sku{ 951 Name: &name, 952 Capacity: &capacity, 953 } 954 955 if tier != "" { 956 sku.Tier = &tier 957 } 958 959 return sku, nil 960 } 961 962 func expandAzureRmVirtualMachineScaleSetNetworkProfile(d *schema.ResourceData) *compute.VirtualMachineScaleSetNetworkProfile { 963 scaleSetNetworkProfileConfigs := d.Get("network_profile").(*schema.Set).List() 964 networkProfileConfig := make([]compute.VirtualMachineScaleSetNetworkConfiguration, 0, len(scaleSetNetworkProfileConfigs)) 965 966 for _, npProfileConfig := range scaleSetNetworkProfileConfigs { 967 config := npProfileConfig.(map[string]interface{}) 968 969 name := config["name"].(string) 970 primary := config["primary"].(bool) 971 972 ipConfigurationConfigs := config["ip_configuration"].([]interface{}) 973 ipConfigurations := make([]compute.VirtualMachineScaleSetIPConfiguration, 0, len(ipConfigurationConfigs)) 974 for _, ipConfigConfig := range ipConfigurationConfigs { 975 ipconfig := ipConfigConfig.(map[string]interface{}) 976 name := ipconfig["name"].(string) 977 subnetId := ipconfig["subnet_id"].(string) 978 979 ipConfiguration := compute.VirtualMachineScaleSetIPConfiguration{ 980 Name: &name, 981 VirtualMachineScaleSetIPConfigurationProperties: &compute.VirtualMachineScaleSetIPConfigurationProperties{ 982 Subnet: &compute.APIEntityReference{ 983 ID: &subnetId, 984 }, 985 }, 986 } 987 988 if v := ipconfig["load_balancer_backend_address_pool_ids"]; v != nil { 989 pools := v.(*schema.Set).List() 990 resources := make([]compute.SubResource, 0, len(pools)) 991 for _, p := range pools { 992 id := p.(string) 993 resources = append(resources, compute.SubResource{ 994 ID: &id, 995 }) 996 } 997 ipConfiguration.LoadBalancerBackendAddressPools = &resources 998 } 999 1000 if v := ipconfig["load_balancer_inbound_nat_rules_ids"]; v != nil { 1001 rules := v.(*schema.Set).List() 1002 rulesResources := make([]compute.SubResource, 0, len(rules)) 1003 for _, m := range rules { 1004 id := m.(string) 1005 rulesResources = append(rulesResources, compute.SubResource{ 1006 ID: &id, 1007 }) 1008 } 1009 ipConfiguration.LoadBalancerInboundNatPools = &rulesResources 1010 } 1011 1012 ipConfigurations = append(ipConfigurations, ipConfiguration) 1013 } 1014 1015 nProfile := compute.VirtualMachineScaleSetNetworkConfiguration{ 1016 Name: &name, 1017 VirtualMachineScaleSetNetworkConfigurationProperties: &compute.VirtualMachineScaleSetNetworkConfigurationProperties{ 1018 Primary: &primary, 1019 IPConfigurations: &ipConfigurations, 1020 }, 1021 } 1022 1023 networkProfileConfig = append(networkProfileConfig, nProfile) 1024 } 1025 1026 return &compute.VirtualMachineScaleSetNetworkProfile{ 1027 NetworkInterfaceConfigurations: &networkProfileConfig, 1028 } 1029 } 1030 1031 func expandAzureRMVirtualMachineScaleSetsOsProfile(d *schema.ResourceData) (*compute.VirtualMachineScaleSetOSProfile, error) { 1032 osProfileConfigs := d.Get("os_profile").(*schema.Set).List() 1033 1034 osProfileConfig := osProfileConfigs[0].(map[string]interface{}) 1035 namePrefix := osProfileConfig["computer_name_prefix"].(string) 1036 username := osProfileConfig["admin_username"].(string) 1037 password := osProfileConfig["admin_password"].(string) 1038 customData := osProfileConfig["custom_data"].(string) 1039 1040 osProfile := &compute.VirtualMachineScaleSetOSProfile{ 1041 ComputerNamePrefix: &namePrefix, 1042 AdminUsername: &username, 1043 } 1044 1045 if password != "" { 1046 osProfile.AdminPassword = &password 1047 } 1048 1049 if customData != "" { 1050 customData = base64Encode(customData) 1051 osProfile.CustomData = &customData 1052 } 1053 1054 if _, ok := d.GetOk("os_profile_secrets"); ok { 1055 secrets := expandAzureRmVirtualMachineScaleSetOsProfileSecrets(d) 1056 if secrets != nil { 1057 osProfile.Secrets = secrets 1058 } 1059 } 1060 1061 if _, ok := d.GetOk("os_profile_linux_config"); ok { 1062 linuxConfig, err := expandAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(d) 1063 if err != nil { 1064 return nil, err 1065 } 1066 osProfile.LinuxConfiguration = linuxConfig 1067 } 1068 1069 if _, ok := d.GetOk("os_profile_windows_config"); ok { 1070 winConfig, err := expandAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(d) 1071 if err != nil { 1072 return nil, err 1073 } 1074 if winConfig != nil { 1075 osProfile.WindowsConfiguration = winConfig 1076 } 1077 } 1078 1079 return osProfile, nil 1080 } 1081 1082 func expandAzureRMVirtualMachineScaleSetsStorageProfileOsDisk(d *schema.ResourceData) (*compute.VirtualMachineScaleSetOSDisk, error) { 1083 osDiskConfigs := d.Get("storage_profile_os_disk").(*schema.Set).List() 1084 1085 osDiskConfig := osDiskConfigs[0].(map[string]interface{}) 1086 name := osDiskConfig["name"].(string) 1087 image := osDiskConfig["image"].(string) 1088 vhd_containers := osDiskConfig["vhd_containers"].(*schema.Set).List() 1089 caching := osDiskConfig["caching"].(string) 1090 osType := osDiskConfig["os_type"].(string) 1091 createOption := osDiskConfig["create_option"].(string) 1092 managedDiskType := osDiskConfig["managed_disk_type"].(string) 1093 1094 osDisk := &compute.VirtualMachineScaleSetOSDisk{ 1095 Name: &name, 1096 Caching: compute.CachingTypes(caching), 1097 OsType: compute.OperatingSystemTypes(osType), 1098 CreateOption: compute.DiskCreateOptionTypes(createOption), 1099 } 1100 1101 if image != "" { 1102 osDisk.Image = &compute.VirtualHardDisk{ 1103 URI: &image, 1104 } 1105 } 1106 1107 if len(vhd_containers) > 0 { 1108 var vhdContainers []string 1109 for _, v := range vhd_containers { 1110 str := v.(string) 1111 vhdContainers = append(vhdContainers, str) 1112 } 1113 osDisk.VhdContainers = &vhdContainers 1114 } 1115 1116 managedDisk := &compute.VirtualMachineScaleSetManagedDiskParameters{} 1117 1118 if managedDiskType != "" { 1119 if name == "" { 1120 osDisk.Name = nil 1121 managedDisk.StorageAccountType = compute.StorageAccountTypes(managedDiskType) 1122 osDisk.ManagedDisk = managedDisk 1123 } else { 1124 return nil, fmt.Errorf("[ERROR] Conflict between `name` and `managed_disk_type` (please set name to blank)") 1125 } 1126 } 1127 1128 //BEGIN: code to be removed after GH-13016 is merged 1129 if image != "" && managedDiskType != "" { 1130 return nil, fmt.Errorf("[ERROR] Conflict between `image` and `managed_disk_type` (only one or the other can be used)") 1131 } 1132 1133 if len(vhd_containers) > 0 && managedDiskType != "" { 1134 return nil, fmt.Errorf("[ERROR] Conflict between `vhd_containers` and `managed_disk_type` (only one or the other can be used)") 1135 } 1136 //END: code to be removed after GH-13016 is merged 1137 1138 return osDisk, nil 1139 } 1140 1141 func expandAzureRmVirtualMachineScaleSetStorageProfileImageReference(d *schema.ResourceData) (*compute.ImageReference, error) { 1142 storageImageRefs := d.Get("storage_profile_image_reference").(*schema.Set).List() 1143 1144 storageImageRef := storageImageRefs[0].(map[string]interface{}) 1145 1146 publisher := storageImageRef["publisher"].(string) 1147 offer := storageImageRef["offer"].(string) 1148 sku := storageImageRef["sku"].(string) 1149 version := storageImageRef["version"].(string) 1150 1151 return &compute.ImageReference{ 1152 Publisher: &publisher, 1153 Offer: &offer, 1154 Sku: &sku, 1155 Version: &version, 1156 }, nil 1157 } 1158 1159 func expandAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(d *schema.ResourceData) (*compute.LinuxConfiguration, error) { 1160 osProfilesLinuxConfig := d.Get("os_profile_linux_config").(*schema.Set).List() 1161 1162 linuxConfig := osProfilesLinuxConfig[0].(map[string]interface{}) 1163 disablePasswordAuth := linuxConfig["disable_password_authentication"].(bool) 1164 1165 linuxKeys := linuxConfig["ssh_keys"].([]interface{}) 1166 sshPublicKeys := make([]compute.SSHPublicKey, 0, len(linuxKeys)) 1167 for _, key := range linuxKeys { 1168 if key == nil { 1169 continue 1170 } 1171 sshKey := key.(map[string]interface{}) 1172 path := sshKey["path"].(string) 1173 keyData := sshKey["key_data"].(string) 1174 1175 sshPublicKey := compute.SSHPublicKey{ 1176 Path: &path, 1177 KeyData: &keyData, 1178 } 1179 1180 sshPublicKeys = append(sshPublicKeys, sshPublicKey) 1181 } 1182 1183 config := &compute.LinuxConfiguration{ 1184 DisablePasswordAuthentication: &disablePasswordAuth, 1185 SSH: &compute.SSHConfiguration{ 1186 PublicKeys: &sshPublicKeys, 1187 }, 1188 } 1189 1190 return config, nil 1191 } 1192 1193 func expandAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(d *schema.ResourceData) (*compute.WindowsConfiguration, error) { 1194 osProfilesWindowsConfig := d.Get("os_profile_windows_config").(*schema.Set).List() 1195 1196 osProfileConfig := osProfilesWindowsConfig[0].(map[string]interface{}) 1197 config := &compute.WindowsConfiguration{} 1198 1199 if v := osProfileConfig["provision_vm_agent"]; v != nil { 1200 provision := v.(bool) 1201 config.ProvisionVMAgent = &provision 1202 } 1203 1204 if v := osProfileConfig["enable_automatic_upgrades"]; v != nil { 1205 update := v.(bool) 1206 config.EnableAutomaticUpdates = &update 1207 } 1208 1209 if v := osProfileConfig["winrm"]; v != nil { 1210 winRm := v.(*schema.Set).List() 1211 if len(winRm) > 0 { 1212 winRmListeners := make([]compute.WinRMListener, 0, len(winRm)) 1213 for _, winRmConfig := range winRm { 1214 config := winRmConfig.(map[string]interface{}) 1215 1216 protocol := config["protocol"].(string) 1217 winRmListener := compute.WinRMListener{ 1218 Protocol: compute.ProtocolTypes(protocol), 1219 } 1220 if v := config["certificate_url"].(string); v != "" { 1221 winRmListener.CertificateURL = &v 1222 } 1223 1224 winRmListeners = append(winRmListeners, winRmListener) 1225 } 1226 config.WinRM = &compute.WinRMConfiguration{ 1227 Listeners: &winRmListeners, 1228 } 1229 } 1230 } 1231 if v := osProfileConfig["additional_unattend_config"]; v != nil { 1232 additionalConfig := v.(*schema.Set).List() 1233 if len(additionalConfig) > 0 { 1234 additionalConfigContent := make([]compute.AdditionalUnattendContent, 0, len(additionalConfig)) 1235 for _, addConfig := range additionalConfig { 1236 config := addConfig.(map[string]interface{}) 1237 pass := config["pass"].(string) 1238 component := config["component"].(string) 1239 settingName := config["setting_name"].(string) 1240 content := config["content"].(string) 1241 1242 addContent := compute.AdditionalUnattendContent{ 1243 PassName: compute.PassNames(pass), 1244 ComponentName: compute.ComponentNames(component), 1245 SettingName: compute.SettingNames(settingName), 1246 Content: &content, 1247 } 1248 1249 additionalConfigContent = append(additionalConfigContent, addContent) 1250 } 1251 config.AdditionalUnattendContent = &additionalConfigContent 1252 } 1253 } 1254 return config, nil 1255 } 1256 1257 func expandAzureRmVirtualMachineScaleSetOsProfileSecrets(d *schema.ResourceData) *[]compute.VaultSecretGroup { 1258 secretsConfig := d.Get("os_profile_secrets").(*schema.Set).List() 1259 secrets := make([]compute.VaultSecretGroup, 0, len(secretsConfig)) 1260 1261 for _, secretConfig := range secretsConfig { 1262 config := secretConfig.(map[string]interface{}) 1263 sourceVaultId := config["source_vault_id"].(string) 1264 1265 vaultSecretGroup := compute.VaultSecretGroup{ 1266 SourceVault: &compute.SubResource{ 1267 ID: &sourceVaultId, 1268 }, 1269 } 1270 1271 if v := config["vault_certificates"]; v != nil { 1272 certsConfig := v.([]interface{}) 1273 certs := make([]compute.VaultCertificate, 0, len(certsConfig)) 1274 for _, certConfig := range certsConfig { 1275 config := certConfig.(map[string]interface{}) 1276 1277 certUrl := config["certificate_url"].(string) 1278 cert := compute.VaultCertificate{ 1279 CertificateURL: &certUrl, 1280 } 1281 if v := config["certificate_store"].(string); v != "" { 1282 cert.CertificateStore = &v 1283 } 1284 1285 certs = append(certs, cert) 1286 } 1287 vaultSecretGroup.VaultCertificates = &certs 1288 } 1289 1290 secrets = append(secrets, vaultSecretGroup) 1291 } 1292 1293 return &secrets 1294 } 1295 1296 func expandAzureRMVirtualMachineScaleSetExtensions(d *schema.ResourceData) (*compute.VirtualMachineScaleSetExtensionProfile, error) { 1297 extensions := d.Get("extension").(*schema.Set).List() 1298 resources := make([]compute.VirtualMachineScaleSetExtension, 0, len(extensions)) 1299 for _, e := range extensions { 1300 config := e.(map[string]interface{}) 1301 name := config["name"].(string) 1302 publisher := config["publisher"].(string) 1303 t := config["type"].(string) 1304 version := config["type_handler_version"].(string) 1305 1306 extension := compute.VirtualMachineScaleSetExtension{ 1307 Name: &name, 1308 VirtualMachineScaleSetExtensionProperties: &compute.VirtualMachineScaleSetExtensionProperties{ 1309 Publisher: &publisher, 1310 Type: &t, 1311 TypeHandlerVersion: &version, 1312 }, 1313 } 1314 1315 if u := config["auto_upgrade_minor_version"]; u != nil { 1316 upgrade := u.(bool) 1317 extension.VirtualMachineScaleSetExtensionProperties.AutoUpgradeMinorVersion = &upgrade 1318 } 1319 1320 if s := config["settings"].(string); s != "" { 1321 settings, err := structure.ExpandJsonFromString(s) 1322 if err != nil { 1323 return nil, fmt.Errorf("unable to parse settings: %s", err) 1324 } 1325 extension.VirtualMachineScaleSetExtensionProperties.Settings = &settings 1326 } 1327 1328 if s := config["protected_settings"].(string); s != "" { 1329 protectedSettings, err := structure.ExpandJsonFromString(s) 1330 if err != nil { 1331 return nil, fmt.Errorf("unable to parse protected_settings: %s", err) 1332 } 1333 extension.VirtualMachineScaleSetExtensionProperties.ProtectedSettings = &protectedSettings 1334 } 1335 1336 resources = append(resources, extension) 1337 } 1338 1339 return &compute.VirtualMachineScaleSetExtensionProfile{ 1340 Extensions: &resources, 1341 }, nil 1342 }