terraform/builtin/providers/azurerm/resource_arm_virtual_machin...

1354 lines
40 KiB
Go

package azurerm
import (
"bytes"
"fmt"
"log"
"net/http"
"github.com/Azure/azure-sdk-for-go/arm/compute"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/structure"
"github.com/hashicorp/terraform/helper/validation"
)
func resourceArmVirtualMachineScaleSet() *schema.Resource {
return &schema.Resource{
Create: resourceArmVirtualMachineScaleSetCreate,
Read: resourceArmVirtualMachineScaleSetRead,
Update: resourceArmVirtualMachineScaleSetCreate,
Delete: resourceArmVirtualMachineScaleSetDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"location": locationSchema(),
"resource_group_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"sku": {
Type: schema.TypeSet,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"tier": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"capacity": {
Type: schema.TypeInt,
Required: true,
},
},
},
Set: resourceArmVirtualMachineScaleSetSkuHash,
},
"upgrade_policy_mode": {
Type: schema.TypeString,
Required: true,
},
"overprovision": {
Type: schema.TypeBool,
Optional: true,
},
"single_placement_group": {
Type: schema.TypeBool,
Optional: true,
Default: true,
ForceNew: true,
},
"os_profile": {
Type: schema.TypeSet,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"computer_name_prefix": {
Type: schema.TypeString,
Required: true,
},
"admin_username": {
Type: schema.TypeString,
Required: true,
},
"admin_password": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
},
"custom_data": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
StateFunc: userDataStateFunc,
},
},
},
Set: resourceArmVirtualMachineScaleSetsOsProfileHash,
},
"os_profile_secrets": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"source_vault_id": {
Type: schema.TypeString,
Required: true,
},
"vault_certificates": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"certificate_url": {
Type: schema.TypeString,
Required: true,
},
"certificate_store": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
},
},
"os_profile_windows_config": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"provision_vm_agent": {
Type: schema.TypeBool,
Optional: true,
},
"enable_automatic_upgrades": {
Type: schema.TypeBool,
Optional: true,
},
"winrm": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"protocol": {
Type: schema.TypeString,
Required: true,
},
"certificate_url": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
"additional_unattend_config": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"pass": {
Type: schema.TypeString,
Required: true,
},
"component": {
Type: schema.TypeString,
Required: true,
},
"setting_name": {
Type: schema.TypeString,
Required: true,
},
"content": {
Type: schema.TypeString,
Required: true,
},
},
},
},
},
},
Set: resourceArmVirtualMachineScaleSetOsProfileLWindowsConfigHash,
},
"os_profile_linux_config": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"disable_password_authentication": {
Type: schema.TypeBool,
Optional: true,
Default: false,
ForceNew: true,
},
"ssh_keys": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"path": {
Type: schema.TypeString,
Required: true,
},
"key_data": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
},
Set: resourceArmVirtualMachineScaleSetOsProfileLinuxConfigHash,
},
"network_profile": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"primary": {
Type: schema.TypeBool,
Required: true,
},
"ip_configuration": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"subnet_id": {
Type: schema.TypeString,
Required: true,
},
"load_balancer_backend_address_pool_ids": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"load_balancer_inbound_nat_rules_ids": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
},
},
},
},
},
Set: resourceArmVirtualMachineScaleSetNetworkConfigurationHash,
},
"storage_profile_os_disk": {
Type: schema.TypeSet,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"image": {
Type: schema.TypeString,
Optional: true,
},
"vhd_containers": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"managed_disk_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ConflictsWith: []string{"storage_profile_os_disk.vhd_containers"},
ValidateFunc: validation.StringInSlice([]string{
string(compute.PremiumLRS),
string(compute.StandardLRS),
}, true),
},
"caching": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"os_type": {
Type: schema.TypeString,
Optional: true,
},
"create_option": {
Type: schema.TypeString,
Required: true,
},
},
},
Set: resourceArmVirtualMachineScaleSetStorageProfileOsDiskHash,
},
"storage_profile_image_reference": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"publisher": {
Type: schema.TypeString,
Required: true,
},
"offer": {
Type: schema.TypeString,
Required: true,
},
"sku": {
Type: schema.TypeString,
Required: true,
},
"version": {
Type: schema.TypeString,
Required: true,
},
},
},
Set: resourceArmVirtualMachineScaleSetStorageProfileImageReferenceHash,
},
"extension": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"publisher": {
Type: schema.TypeString,
Required: true,
},
"type": {
Type: schema.TypeString,
Required: true,
},
"type_handler_version": {
Type: schema.TypeString,
Required: true,
},
"auto_upgrade_minor_version": {
Type: schema.TypeBool,
Optional: true,
},
"settings": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.ValidateJsonString,
DiffSuppressFunc: structure.SuppressJsonDiff,
},
"protected_settings": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ValidateFunc: validation.ValidateJsonString,
DiffSuppressFunc: structure.SuppressJsonDiff,
},
},
},
Set: resourceArmVirtualMachineScaleSetExtensionHash,
},
"tags": tagsSchema(),
},
}
}
func resourceArmVirtualMachineScaleSetCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient)
vmScaleSetClient := client.vmScaleSetClient
log.Printf("[INFO] preparing arguments for Azure ARM Virtual Machine Scale Set creation.")
name := d.Get("name").(string)
location := d.Get("location").(string)
resGroup := d.Get("resource_group_name").(string)
tags := d.Get("tags").(map[string]interface{})
sku, err := expandVirtualMachineScaleSetSku(d)
if err != nil {
return err
}
storageProfile := compute.VirtualMachineScaleSetStorageProfile{}
osDisk, err := expandAzureRMVirtualMachineScaleSetsStorageProfileOsDisk(d)
if err != nil {
return err
}
storageProfile.OsDisk = osDisk
if _, ok := d.GetOk("storage_profile_image_reference"); ok {
imageRef, err := expandAzureRmVirtualMachineScaleSetStorageProfileImageReference(d)
if err != nil {
return err
}
storageProfile.ImageReference = imageRef
}
osProfile, err := expandAzureRMVirtualMachineScaleSetsOsProfile(d)
if err != nil {
return err
}
extensions, err := expandAzureRMVirtualMachineScaleSetExtensions(d)
if err != nil {
return err
}
updatePolicy := d.Get("upgrade_policy_mode").(string)
overprovision := d.Get("overprovision").(bool)
singlePlacementGroup := d.Get("single_placement_group").(bool)
scaleSetProps := compute.VirtualMachineScaleSetProperties{
UpgradePolicy: &compute.UpgradePolicy{
Mode: compute.UpgradeMode(updatePolicy),
},
VirtualMachineProfile: &compute.VirtualMachineScaleSetVMProfile{
NetworkProfile: expandAzureRmVirtualMachineScaleSetNetworkProfile(d),
StorageProfile: &storageProfile,
OsProfile: osProfile,
ExtensionProfile: extensions,
},
Overprovision: &overprovision,
SinglePlacementGroup: &singlePlacementGroup,
}
scaleSetParams := compute.VirtualMachineScaleSet{
Name: &name,
Location: &location,
Tags: expandTags(tags),
Sku: sku,
VirtualMachineScaleSetProperties: &scaleSetProps,
}
_, vmErr := vmScaleSetClient.CreateOrUpdate(resGroup, name, scaleSetParams, make(chan struct{}))
if vmErr != nil {
return vmErr
}
read, err := vmScaleSetClient.Get(resGroup, name)
if err != nil {
return err
}
if read.ID == nil {
return fmt.Errorf("Cannot read Virtual Machine Scale Set %s (resource group %s) ID", name, resGroup)
}
d.SetId(*read.ID)
return resourceArmVirtualMachineScaleSetRead(d, meta)
}
func resourceArmVirtualMachineScaleSetRead(d *schema.ResourceData, meta interface{}) error {
vmScaleSetClient := meta.(*ArmClient).vmScaleSetClient
id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["virtualMachineScaleSets"]
resp, err := vmScaleSetClient.Get(resGroup, name)
if err != nil {
if resp.StatusCode == http.StatusNotFound {
log.Printf("[INFO] AzureRM Virtual Machine Scale Set (%s) Not Found. Removing from State", name)
d.SetId("")
return nil
}
return fmt.Errorf("Error making Read request on Azure Virtual Machine Scale Set %s: %s", name, err)
}
d.Set("name", resp.Name)
d.Set("resource_group_name", resGroup)
d.Set("location", azureRMNormalizeLocation(*resp.Location))
if err := d.Set("sku", flattenAzureRmVirtualMachineScaleSetSku(resp.Sku)); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Sku error: %#v", err)
}
properties := resp.VirtualMachineScaleSetProperties
d.Set("upgrade_policy_mode", properties.UpgradePolicy.Mode)
d.Set("overprovision", properties.Overprovision)
d.Set("single_placement_group", properties.SinglePlacementGroup)
osProfile, err := flattenAzureRMVirtualMachineScaleSetOsProfile(properties.VirtualMachineProfile.OsProfile)
if err != nil {
return fmt.Errorf("[DEBUG] Error flattening Virtual Machine Scale Set OS Profile. Error: %#v", err)
}
if err := d.Set("os_profile", osProfile); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile error: %#v", err)
}
if properties.VirtualMachineProfile.OsProfile.Secrets != nil {
if err := d.Set("os_profile_secrets", flattenAzureRmVirtualMachineScaleSetOsProfileSecrets(properties.VirtualMachineProfile.OsProfile.Secrets)); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile Secrets error: %#v", err)
}
}
if properties.VirtualMachineProfile.OsProfile.WindowsConfiguration != nil {
if err := d.Set("os_profile_windows_config", flattenAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(properties.VirtualMachineProfile.OsProfile.WindowsConfiguration)); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile Windows config error: %#v", err)
}
}
if properties.VirtualMachineProfile.OsProfile.LinuxConfiguration != nil {
if err := d.Set("os_profile_linux_config", flattenAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(properties.VirtualMachineProfile.OsProfile.LinuxConfiguration)); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set OS Profile Windows config error: %#v", err)
}
}
if err := d.Set("network_profile", flattenAzureRmVirtualMachineScaleSetNetworkProfile(properties.VirtualMachineProfile.NetworkProfile)); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Network Profile error: %#v", err)
}
if properties.VirtualMachineProfile.StorageProfile.ImageReference != nil {
if err := d.Set("storage_profile_image_reference", flattenAzureRmVirtualMachineScaleSetStorageProfileImageReference(properties.VirtualMachineProfile.StorageProfile.ImageReference)); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Storage Profile Image Reference error: %#v", err)
}
}
if err := d.Set("storage_profile_os_disk", flattenAzureRmVirtualMachineScaleSetStorageProfileOSDisk(properties.VirtualMachineProfile.StorageProfile.OsDisk)); err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Storage Profile OS Disk error: %#v", err)
}
if properties.VirtualMachineProfile.ExtensionProfile != nil {
extension, err := flattenAzureRmVirtualMachineScaleSetExtensionProfile(properties.VirtualMachineProfile.ExtensionProfile)
if err != nil {
return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Extension Profile error: %#v", err)
}
d.Set("extension", extension)
}
flattenAndSetTags(d, resp.Tags)
return nil
}
func resourceArmVirtualMachineScaleSetDelete(d *schema.ResourceData, meta interface{}) error {
vmScaleSetClient := meta.(*ArmClient).vmScaleSetClient
id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["virtualMachineScaleSets"]
_, err = vmScaleSetClient.Delete(resGroup, name, make(chan struct{}))
return err
}
func flattenAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(config *compute.LinuxConfiguration) []interface{} {
result := make(map[string]interface{})
result["disable_password_authentication"] = *config.DisablePasswordAuthentication
if config.SSH != nil && len(*config.SSH.PublicKeys) > 0 {
ssh_keys := make([]map[string]interface{}, 0, len(*config.SSH.PublicKeys))
for _, i := range *config.SSH.PublicKeys {
key := make(map[string]interface{})
key["path"] = *i.Path
if i.KeyData != nil {
key["key_data"] = *i.KeyData
}
ssh_keys = append(ssh_keys, key)
}
result["ssh_keys"] = ssh_keys
}
return []interface{}{result}
}
func flattenAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(config *compute.WindowsConfiguration) []interface{} {
result := make(map[string]interface{})
if config.ProvisionVMAgent != nil {
result["provision_vm_agent"] = *config.ProvisionVMAgent
}
if config.EnableAutomaticUpdates != nil {
result["enable_automatic_upgrades"] = *config.EnableAutomaticUpdates
}
if config.WinRM != nil {
listeners := make([]map[string]interface{}, 0, len(*config.WinRM.Listeners))
for _, i := range *config.WinRM.Listeners {
listener := make(map[string]interface{})
listener["protocol"] = i.Protocol
if i.CertificateURL != nil {
listener["certificate_url"] = *i.CertificateURL
}
listeners = append(listeners, listener)
}
result["winrm"] = listeners
}
if config.AdditionalUnattendContent != nil {
content := make([]map[string]interface{}, 0, len(*config.AdditionalUnattendContent))
for _, i := range *config.AdditionalUnattendContent {
c := make(map[string]interface{})
c["pass"] = i.PassName
c["component"] = i.ComponentName
c["setting_name"] = i.SettingName
c["content"] = *i.Content
content = append(content, c)
}
result["additional_unattend_config"] = content
}
return []interface{}{result}
}
func flattenAzureRmVirtualMachineScaleSetOsProfileSecrets(secrets *[]compute.VaultSecretGroup) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(*secrets))
for _, secret := range *secrets {
s := map[string]interface{}{
"source_vault_id": *secret.SourceVault.ID,
}
if secret.VaultCertificates != nil {
certs := make([]map[string]interface{}, 0, len(*secret.VaultCertificates))
for _, cert := range *secret.VaultCertificates {
vaultCert := make(map[string]interface{})
vaultCert["certificate_url"] = *cert.CertificateURL
if cert.CertificateStore != nil {
vaultCert["certificate_store"] = *cert.CertificateStore
}
certs = append(certs, vaultCert)
}
s["vault_certificates"] = certs
}
result = append(result, s)
}
return result
}
func flattenAzureRmVirtualMachineScaleSetNetworkProfile(profile *compute.VirtualMachineScaleSetNetworkProfile) []map[string]interface{} {
networkConfigurations := profile.NetworkInterfaceConfigurations
result := make([]map[string]interface{}, 0, len(*networkConfigurations))
for _, netConfig := range *networkConfigurations {
s := map[string]interface{}{
"name": *netConfig.Name,
"primary": *netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.Primary,
}
if netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.IPConfigurations != nil {
ipConfigs := make([]map[string]interface{}, 0, len(*netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.IPConfigurations))
for _, ipConfig := range *netConfig.VirtualMachineScaleSetNetworkConfigurationProperties.IPConfigurations {
config := make(map[string]interface{})
config["name"] = *ipConfig.Name
properties := ipConfig.VirtualMachineScaleSetIPConfigurationProperties
if ipConfig.VirtualMachineScaleSetIPConfigurationProperties.Subnet != nil {
config["subnet_id"] = *properties.Subnet.ID
}
if properties.LoadBalancerBackendAddressPools != nil {
addressPools := make([]interface{}, 0, len(*properties.LoadBalancerBackendAddressPools))
for _, pool := range *properties.LoadBalancerBackendAddressPools {
addressPools = append(addressPools, *pool.ID)
}
config["load_balancer_backend_address_pool_ids"] = schema.NewSet(schema.HashString, addressPools)
}
if properties.LoadBalancerInboundNatPools != nil {
inboundNatPools := make([]interface{}, 0, len(*properties.LoadBalancerInboundNatPools))
for _, rule := range *properties.LoadBalancerInboundNatPools {
inboundNatPools = append(inboundNatPools, *rule.ID)
}
config["load_balancer_inbound_nat_rules_ids"] = schema.NewSet(schema.HashString, inboundNatPools)
}
ipConfigs = append(ipConfigs, config)
}
s["ip_configuration"] = ipConfigs
}
result = append(result, s)
}
return result
}
func flattenAzureRMVirtualMachineScaleSetOsProfile(profile *compute.VirtualMachineScaleSetOSProfile) ([]interface{}, error) {
result := make(map[string]interface{})
result["computer_name_prefix"] = *profile.ComputerNamePrefix
result["admin_username"] = *profile.AdminUsername
if profile.CustomData != nil {
result["custom_data"] = *profile.CustomData
}
return []interface{}{result}, nil
}
func flattenAzureRmVirtualMachineScaleSetStorageProfileOSDisk(profile *compute.VirtualMachineScaleSetOSDisk) []interface{} {
result := make(map[string]interface{})
if profile.Name != nil {
result["name"] = *profile.Name
}
if profile.Image != nil {
result["image"] = *profile.Image.URI
}
if profile.VhdContainers != nil {
containers := make([]interface{}, 0, len(*profile.VhdContainers))
for _, container := range *profile.VhdContainers {
containers = append(containers, container)
}
result["vhd_containers"] = schema.NewSet(schema.HashString, containers)
}
if profile.ManagedDisk != nil {
result["managed_disk_type"] = string(profile.ManagedDisk.StorageAccountType)
}
result["caching"] = profile.Caching
result["create_option"] = profile.CreateOption
result["os_type"] = profile.OsType
return []interface{}{result}
}
func flattenAzureRmVirtualMachineScaleSetStorageProfileImageReference(profile *compute.ImageReference) []interface{} {
result := make(map[string]interface{})
result["publisher"] = *profile.Publisher
result["offer"] = *profile.Offer
result["sku"] = *profile.Sku
result["version"] = *profile.Version
return []interface{}{result}
}
func flattenAzureRmVirtualMachineScaleSetSku(sku *compute.Sku) []interface{} {
result := make(map[string]interface{})
result["name"] = *sku.Name
result["capacity"] = *sku.Capacity
if *sku.Tier != "" {
result["tier"] = *sku.Tier
}
return []interface{}{result}
}
func flattenAzureRmVirtualMachineScaleSetExtensionProfile(profile *compute.VirtualMachineScaleSetExtensionProfile) ([]map[string]interface{}, error) {
if profile.Extensions == nil {
return nil, nil
}
result := make([]map[string]interface{}, 0, len(*profile.Extensions))
for _, extension := range *profile.Extensions {
e := make(map[string]interface{})
e["name"] = *extension.Name
properties := extension.VirtualMachineScaleSetExtensionProperties
if properties != nil {
e["publisher"] = *properties.Publisher
e["type"] = *properties.Type
e["type_handler_version"] = *properties.TypeHandlerVersion
if properties.AutoUpgradeMinorVersion != nil {
e["auto_upgrade_minor_version"] = *properties.AutoUpgradeMinorVersion
}
if properties.Settings != nil {
settings, err := structure.FlattenJsonToString(*properties.Settings)
if err != nil {
return nil, err
}
e["settings"] = settings
}
}
result = append(result, e)
}
return result, nil
}
func resourceArmVirtualMachineScaleSetStorageProfileImageReferenceHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["offer"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["sku"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["version"].(string)))
return hashcode.String(buf.String())
}
func resourceArmVirtualMachineScaleSetSkuHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
if m["tier"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["tier"].(string)))
}
buf.WriteString(fmt.Sprintf("%d-", m["capacity"].(int)))
return hashcode.String(buf.String())
}
func resourceArmVirtualMachineScaleSetStorageProfileOsDiskHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
if m["vhd_containers"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["vhd_containers"].(*schema.Set).List()))
}
return hashcode.String(buf.String())
}
func resourceArmVirtualMachineScaleSetNetworkConfigurationHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
buf.WriteString(fmt.Sprintf("%t-", m["primary"].(bool)))
return hashcode.String(buf.String())
}
func resourceArmVirtualMachineScaleSetsOsProfileHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["computer_name_prefix"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["admin_username"].(string)))
if m["custom_data"] != nil {
customData := m["custom_data"].(string)
if !isBase64Encoded(customData) {
customData = base64Encode(customData)
}
buf.WriteString(fmt.Sprintf("%s-", customData))
}
return hashcode.String(buf.String())
}
func resourceArmVirtualMachineScaleSetOsProfileLinuxConfigHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%t-", m["disable_password_authentication"].(bool)))
return hashcode.String(buf.String())
}
func resourceArmVirtualMachineScaleSetOsProfileLWindowsConfigHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
if m["provision_vm_agent"] != nil {
buf.WriteString(fmt.Sprintf("%t-", m["provision_vm_agent"].(bool)))
}
if m["enable_automatic_upgrades"] != nil {
buf.WriteString(fmt.Sprintf("%t-", m["enable_automatic_upgrades"].(bool)))
}
return hashcode.String(buf.String())
}
func resourceArmVirtualMachineScaleSetExtensionHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["type"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["type_handler_version"].(string)))
if m["auto_upgrade_minor_version"] != nil {
buf.WriteString(fmt.Sprintf("%t-", m["auto_upgrade_minor_version"].(bool)))
}
return hashcode.String(buf.String())
}
func expandVirtualMachineScaleSetSku(d *schema.ResourceData) (*compute.Sku, error) {
skuConfig := d.Get("sku").(*schema.Set).List()
config := skuConfig[0].(map[string]interface{})
name := config["name"].(string)
tier := config["tier"].(string)
capacity := int64(config["capacity"].(int))
sku := &compute.Sku{
Name: &name,
Capacity: &capacity,
}
if tier != "" {
sku.Tier = &tier
}
return sku, nil
}
func expandAzureRmVirtualMachineScaleSetNetworkProfile(d *schema.ResourceData) *compute.VirtualMachineScaleSetNetworkProfile {
scaleSetNetworkProfileConfigs := d.Get("network_profile").(*schema.Set).List()
networkProfileConfig := make([]compute.VirtualMachineScaleSetNetworkConfiguration, 0, len(scaleSetNetworkProfileConfigs))
for _, npProfileConfig := range scaleSetNetworkProfileConfigs {
config := npProfileConfig.(map[string]interface{})
name := config["name"].(string)
primary := config["primary"].(bool)
ipConfigurationConfigs := config["ip_configuration"].([]interface{})
ipConfigurations := make([]compute.VirtualMachineScaleSetIPConfiguration, 0, len(ipConfigurationConfigs))
for _, ipConfigConfig := range ipConfigurationConfigs {
ipconfig := ipConfigConfig.(map[string]interface{})
name := ipconfig["name"].(string)
subnetId := ipconfig["subnet_id"].(string)
ipConfiguration := compute.VirtualMachineScaleSetIPConfiguration{
Name: &name,
VirtualMachineScaleSetIPConfigurationProperties: &compute.VirtualMachineScaleSetIPConfigurationProperties{
Subnet: &compute.APIEntityReference{
ID: &subnetId,
},
},
}
if v := ipconfig["load_balancer_backend_address_pool_ids"]; v != nil {
pools := v.(*schema.Set).List()
resources := make([]compute.SubResource, 0, len(pools))
for _, p := range pools {
id := p.(string)
resources = append(resources, compute.SubResource{
ID: &id,
})
}
ipConfiguration.LoadBalancerBackendAddressPools = &resources
}
if v := ipconfig["load_balancer_inbound_nat_rules_ids"]; v != nil {
rules := v.(*schema.Set).List()
rulesResources := make([]compute.SubResource, 0, len(rules))
for _, m := range rules {
id := m.(string)
rulesResources = append(rulesResources, compute.SubResource{
ID: &id,
})
}
ipConfiguration.LoadBalancerInboundNatPools = &rulesResources
}
ipConfigurations = append(ipConfigurations, ipConfiguration)
}
nProfile := compute.VirtualMachineScaleSetNetworkConfiguration{
Name: &name,
VirtualMachineScaleSetNetworkConfigurationProperties: &compute.VirtualMachineScaleSetNetworkConfigurationProperties{
Primary: &primary,
IPConfigurations: &ipConfigurations,
},
}
networkProfileConfig = append(networkProfileConfig, nProfile)
}
return &compute.VirtualMachineScaleSetNetworkProfile{
NetworkInterfaceConfigurations: &networkProfileConfig,
}
}
func expandAzureRMVirtualMachineScaleSetsOsProfile(d *schema.ResourceData) (*compute.VirtualMachineScaleSetOSProfile, error) {
osProfileConfigs := d.Get("os_profile").(*schema.Set).List()
osProfileConfig := osProfileConfigs[0].(map[string]interface{})
namePrefix := osProfileConfig["computer_name_prefix"].(string)
username := osProfileConfig["admin_username"].(string)
password := osProfileConfig["admin_password"].(string)
customData := osProfileConfig["custom_data"].(string)
osProfile := &compute.VirtualMachineScaleSetOSProfile{
ComputerNamePrefix: &namePrefix,
AdminUsername: &username,
}
if password != "" {
osProfile.AdminPassword = &password
}
if customData != "" {
customData = base64Encode(customData)
osProfile.CustomData = &customData
}
if _, ok := d.GetOk("os_profile_secrets"); ok {
secrets := expandAzureRmVirtualMachineScaleSetOsProfileSecrets(d)
if secrets != nil {
osProfile.Secrets = secrets
}
}
if _, ok := d.GetOk("os_profile_linux_config"); ok {
linuxConfig, err := expandAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(d)
if err != nil {
return nil, err
}
osProfile.LinuxConfiguration = linuxConfig
}
if _, ok := d.GetOk("os_profile_windows_config"); ok {
winConfig, err := expandAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(d)
if err != nil {
return nil, err
}
if winConfig != nil {
osProfile.WindowsConfiguration = winConfig
}
}
return osProfile, nil
}
func expandAzureRMVirtualMachineScaleSetsStorageProfileOsDisk(d *schema.ResourceData) (*compute.VirtualMachineScaleSetOSDisk, error) {
osDiskConfigs := d.Get("storage_profile_os_disk").(*schema.Set).List()
osDiskConfig := osDiskConfigs[0].(map[string]interface{})
name := osDiskConfig["name"].(string)
image := osDiskConfig["image"].(string)
vhd_containers := osDiskConfig["vhd_containers"].(*schema.Set).List()
caching := osDiskConfig["caching"].(string)
osType := osDiskConfig["os_type"].(string)
createOption := osDiskConfig["create_option"].(string)
managedDiskType := osDiskConfig["managed_disk_type"].(string)
osDisk := &compute.VirtualMachineScaleSetOSDisk{
Name: &name,
Caching: compute.CachingTypes(caching),
OsType: compute.OperatingSystemTypes(osType),
CreateOption: compute.DiskCreateOptionTypes(createOption),
}
if image != "" {
osDisk.Image = &compute.VirtualHardDisk{
URI: &image,
}
}
if len(vhd_containers) > 0 {
var vhdContainers []string
for _, v := range vhd_containers {
str := v.(string)
vhdContainers = append(vhdContainers, str)
}
osDisk.VhdContainers = &vhdContainers
}
managedDisk := &compute.VirtualMachineScaleSetManagedDiskParameters{}
if managedDiskType != "" {
if name == "" {
osDisk.Name = nil
managedDisk.StorageAccountType = compute.StorageAccountTypes(managedDiskType)
osDisk.ManagedDisk = managedDisk
} else {
return nil, fmt.Errorf("[ERROR] Conflict between `name` and `managed_disk_type` on `storage_profile_os_disk` (please set name to blank)")
}
}
//BEGIN: code to be removed after GH-13016 is merged
if image != "" && managedDiskType != "" {
return nil, fmt.Errorf("[ERROR] Conflict between `image` and `managed_disk_type` on `storage_profile_os_disk` (only one or the other can be used)")
}
if len(vhd_containers) > 0 && managedDiskType != "" {
return nil, fmt.Errorf("[ERROR] Conflict between `vhd_containers` and `managed_disk_type` on `storage_profile_os_disk` (only one or the other can be used)")
}
//END: code to be removed after GH-13016 is merged
return osDisk, nil
}
func expandAzureRmVirtualMachineScaleSetStorageProfileImageReference(d *schema.ResourceData) (*compute.ImageReference, error) {
storageImageRefs := d.Get("storage_profile_image_reference").(*schema.Set).List()
storageImageRef := storageImageRefs[0].(map[string]interface{})
publisher := storageImageRef["publisher"].(string)
offer := storageImageRef["offer"].(string)
sku := storageImageRef["sku"].(string)
version := storageImageRef["version"].(string)
return &compute.ImageReference{
Publisher: &publisher,
Offer: &offer,
Sku: &sku,
Version: &version,
}, nil
}
func expandAzureRmVirtualMachineScaleSetOsProfileLinuxConfig(d *schema.ResourceData) (*compute.LinuxConfiguration, error) {
osProfilesLinuxConfig := d.Get("os_profile_linux_config").(*schema.Set).List()
linuxConfig := osProfilesLinuxConfig[0].(map[string]interface{})
disablePasswordAuth := linuxConfig["disable_password_authentication"].(bool)
linuxKeys := linuxConfig["ssh_keys"].([]interface{})
sshPublicKeys := make([]compute.SSHPublicKey, 0, len(linuxKeys))
for _, key := range linuxKeys {
if key == nil {
continue
}
sshKey := key.(map[string]interface{})
path := sshKey["path"].(string)
keyData := sshKey["key_data"].(string)
sshPublicKey := compute.SSHPublicKey{
Path: &path,
KeyData: &keyData,
}
sshPublicKeys = append(sshPublicKeys, sshPublicKey)
}
config := &compute.LinuxConfiguration{
DisablePasswordAuthentication: &disablePasswordAuth,
SSH: &compute.SSHConfiguration{
PublicKeys: &sshPublicKeys,
},
}
return config, nil
}
func expandAzureRmVirtualMachineScaleSetOsProfileWindowsConfig(d *schema.ResourceData) (*compute.WindowsConfiguration, error) {
osProfilesWindowsConfig := d.Get("os_profile_windows_config").(*schema.Set).List()
osProfileConfig := osProfilesWindowsConfig[0].(map[string]interface{})
config := &compute.WindowsConfiguration{}
if v := osProfileConfig["provision_vm_agent"]; v != nil {
provision := v.(bool)
config.ProvisionVMAgent = &provision
}
if v := osProfileConfig["enable_automatic_upgrades"]; v != nil {
update := v.(bool)
config.EnableAutomaticUpdates = &update
}
if v := osProfileConfig["winrm"]; v != nil {
winRm := v.(*schema.Set).List()
if len(winRm) > 0 {
winRmListeners := make([]compute.WinRMListener, 0, len(winRm))
for _, winRmConfig := range winRm {
config := winRmConfig.(map[string]interface{})
protocol := config["protocol"].(string)
winRmListener := compute.WinRMListener{
Protocol: compute.ProtocolTypes(protocol),
}
if v := config["certificate_url"].(string); v != "" {
winRmListener.CertificateURL = &v
}
winRmListeners = append(winRmListeners, winRmListener)
}
config.WinRM = &compute.WinRMConfiguration{
Listeners: &winRmListeners,
}
}
}
if v := osProfileConfig["additional_unattend_config"]; v != nil {
additionalConfig := v.(*schema.Set).List()
if len(additionalConfig) > 0 {
additionalConfigContent := make([]compute.AdditionalUnattendContent, 0, len(additionalConfig))
for _, addConfig := range additionalConfig {
config := addConfig.(map[string]interface{})
pass := config["pass"].(string)
component := config["component"].(string)
settingName := config["setting_name"].(string)
content := config["content"].(string)
addContent := compute.AdditionalUnattendContent{
PassName: compute.PassNames(pass),
ComponentName: compute.ComponentNames(component),
SettingName: compute.SettingNames(settingName),
Content: &content,
}
additionalConfigContent = append(additionalConfigContent, addContent)
}
config.AdditionalUnattendContent = &additionalConfigContent
}
}
return config, nil
}
func expandAzureRmVirtualMachineScaleSetOsProfileSecrets(d *schema.ResourceData) *[]compute.VaultSecretGroup {
secretsConfig := d.Get("os_profile_secrets").(*schema.Set).List()
secrets := make([]compute.VaultSecretGroup, 0, len(secretsConfig))
for _, secretConfig := range secretsConfig {
config := secretConfig.(map[string]interface{})
sourceVaultId := config["source_vault_id"].(string)
vaultSecretGroup := compute.VaultSecretGroup{
SourceVault: &compute.SubResource{
ID: &sourceVaultId,
},
}
if v := config["vault_certificates"]; v != nil {
certsConfig := v.([]interface{})
certs := make([]compute.VaultCertificate, 0, len(certsConfig))
for _, certConfig := range certsConfig {
config := certConfig.(map[string]interface{})
certUrl := config["certificate_url"].(string)
cert := compute.VaultCertificate{
CertificateURL: &certUrl,
}
if v := config["certificate_store"].(string); v != "" {
cert.CertificateStore = &v
}
certs = append(certs, cert)
}
vaultSecretGroup.VaultCertificates = &certs
}
secrets = append(secrets, vaultSecretGroup)
}
return &secrets
}
func expandAzureRMVirtualMachineScaleSetExtensions(d *schema.ResourceData) (*compute.VirtualMachineScaleSetExtensionProfile, error) {
extensions := d.Get("extension").(*schema.Set).List()
resources := make([]compute.VirtualMachineScaleSetExtension, 0, len(extensions))
for _, e := range extensions {
config := e.(map[string]interface{})
name := config["name"].(string)
publisher := config["publisher"].(string)
t := config["type"].(string)
version := config["type_handler_version"].(string)
extension := compute.VirtualMachineScaleSetExtension{
Name: &name,
VirtualMachineScaleSetExtensionProperties: &compute.VirtualMachineScaleSetExtensionProperties{
Publisher: &publisher,
Type: &t,
TypeHandlerVersion: &version,
},
}
if u := config["auto_upgrade_minor_version"]; u != nil {
upgrade := u.(bool)
extension.VirtualMachineScaleSetExtensionProperties.AutoUpgradeMinorVersion = &upgrade
}
if s := config["settings"].(string); s != "" {
settings, err := structure.ExpandJsonFromString(s)
if err != nil {
return nil, fmt.Errorf("unable to parse settings: %s", err)
}
extension.VirtualMachineScaleSetExtensionProperties.Settings = &settings
}
if s := config["protected_settings"].(string); s != "" {
protectedSettings, err := structure.ExpandJsonFromString(s)
if err != nil {
return nil, fmt.Errorf("unable to parse protected_settings: %s", err)
}
extension.VirtualMachineScaleSetExtensionProperties.ProtectedSettings = &protectedSettings
}
resources = append(resources, extension)
}
return &compute.VirtualMachineScaleSetExtensionProfile{
Extensions: &resources,
}, nil
}