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