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