github.com/danrjohnson/terraform@v0.7.0-rc2.0.20160627135212-d0fc1fa086ff/builtin/providers/azurerm/resource_arm_virtual_machine.go (about)

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