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