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