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