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