github.com/cbroglie/terraform@v0.7.0-rc3.0.20170410193827-735dfc416d46/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  	"github.com/hashicorp/terraform/helper/validation"
    15  	riviera "github.com/jen20/riviera/azure"
    16  )
    17  
    18  func resourceArmVirtualMachine() *schema.Resource {
    19  	return &schema.Resource{
    20  		Create: resourceArmVirtualMachineCreate,
    21  		Read:   resourceArmVirtualMachineRead,
    22  		Update: resourceArmVirtualMachineCreate,
    23  		Delete: resourceArmVirtualMachineDelete,
    24  		Importer: &schema.ResourceImporter{
    25  			State: schema.ImportStatePassthrough,
    26  		},
    27  
    28  		Schema: map[string]*schema.Schema{
    29  			"name": {
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  				ForceNew: true,
    33  			},
    34  
    35  			"location": locationSchema(),
    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  				MaxItems: 1,
    47  				Elem: &schema.Resource{
    48  					Schema: map[string]*schema.Schema{
    49  						"name": {
    50  							Type:     schema.TypeString,
    51  							Required: true,
    52  						},
    53  
    54  						"publisher": {
    55  							Type:     schema.TypeString,
    56  							Required: true,
    57  						},
    58  
    59  						"product": {
    60  							Type:     schema.TypeString,
    61  							Required: true,
    62  						},
    63  					},
    64  				},
    65  				Set: resourceArmVirtualMachinePlanHash,
    66  			},
    67  
    68  			"availability_set_id": {
    69  				Type:     schema.TypeString,
    70  				Optional: true,
    71  				Computed: true,
    72  				ForceNew: true,
    73  				StateFunc: func(id interface{}) string {
    74  					return strings.ToLower(id.(string))
    75  				},
    76  			},
    77  
    78  			"license_type": {
    79  				Type:         schema.TypeString,
    80  				Optional:     true,
    81  				Computed:     true,
    82  				ValidateFunc: validateLicenseType,
    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  				ForceNew: true,
    95  				MaxItems: 1,
    96  				Elem: &schema.Resource{
    97  					Schema: map[string]*schema.Schema{
    98  						"publisher": {
    99  							Type:     schema.TypeString,
   100  							Required: true,
   101  							ForceNew: true,
   102  						},
   103  
   104  						"offer": {
   105  							Type:     schema.TypeString,
   106  							Required: true,
   107  							ForceNew: true,
   108  						},
   109  
   110  						"sku": {
   111  							Type:     schema.TypeString,
   112  							Required: true,
   113  							ForceNew: true,
   114  						},
   115  
   116  						"version": {
   117  							Type:     schema.TypeString,
   118  							Optional: true,
   119  							Computed: true,
   120  							ForceNew: true,
   121  						},
   122  					},
   123  				},
   124  				Set: resourceArmVirtualMachineStorageImageReferenceHash,
   125  			},
   126  
   127  			"storage_os_disk": {
   128  				Type:     schema.TypeSet,
   129  				Required: true,
   130  				MaxItems: 1,
   131  				Elem: &schema.Resource{
   132  					Schema: map[string]*schema.Schema{
   133  						"os_type": {
   134  							Type:     schema.TypeString,
   135  							Optional: true,
   136  						},
   137  
   138  						"name": {
   139  							Type:     schema.TypeString,
   140  							Required: true,
   141  						},
   142  
   143  						"vhd_uri": {
   144  							Type:     schema.TypeString,
   145  							Optional: true,
   146  							ForceNew: true,
   147  						},
   148  
   149  						"managed_disk_id": {
   150  							Type:          schema.TypeString,
   151  							Optional:      true,
   152  							ForceNew:      true,
   153  							Computed:      true,
   154  							ConflictsWith: []string{"storage_os_disk.vhd_uri"},
   155  						},
   156  
   157  						"managed_disk_type": {
   158  							Type:          schema.TypeString,
   159  							Optional:      true,
   160  							Computed:      true,
   161  							ConflictsWith: []string{"storage_os_disk.vhd_uri"},
   162  							ValidateFunc: validation.StringInSlice([]string{
   163  								string(compute.PremiumLRS),
   164  								string(compute.StandardLRS),
   165  							}, true),
   166  						},
   167  
   168  						"image_uri": {
   169  							Type:     schema.TypeString,
   170  							Optional: true,
   171  						},
   172  
   173  						"caching": {
   174  							Type:     schema.TypeString,
   175  							Optional: true,
   176  							Computed: true,
   177  						},
   178  
   179  						"create_option": {
   180  							Type:     schema.TypeString,
   181  							Required: true,
   182  						},
   183  
   184  						"disk_size_gb": {
   185  							Type:         schema.TypeInt,
   186  							Optional:     true,
   187  							ValidateFunc: validateDiskSizeGB,
   188  						},
   189  					},
   190  				},
   191  				Set: resourceArmVirtualMachineStorageOsDiskHash,
   192  			},
   193  
   194  			"delete_os_disk_on_termination": {
   195  				Type:     schema.TypeBool,
   196  				Optional: true,
   197  				Default:  false,
   198  			},
   199  
   200  			"storage_data_disk": {
   201  				Type:     schema.TypeList,
   202  				Optional: true,
   203  				Elem: &schema.Resource{
   204  					Schema: map[string]*schema.Schema{
   205  						"name": {
   206  							Type:     schema.TypeString,
   207  							Required: true,
   208  						},
   209  
   210  						"vhd_uri": {
   211  							Type:     schema.TypeString,
   212  							Optional: true,
   213  						},
   214  
   215  						"managed_disk_id": {
   216  							Type:          schema.TypeString,
   217  							Optional:      true,
   218  							ForceNew:      true,
   219  							Computed:      true,
   220  							ConflictsWith: []string{"storage_data_disk.vhd_uri"},
   221  						},
   222  
   223  						"managed_disk_type": {
   224  							Type:          schema.TypeString,
   225  							Optional:      true,
   226  							Computed:      true,
   227  							ConflictsWith: []string{"storage_data_disk.vhd_uri"},
   228  							ValidateFunc: validation.StringInSlice([]string{
   229  								string(compute.PremiumLRS),
   230  								string(compute.StandardLRS),
   231  							}, true),
   232  						},
   233  
   234  						"create_option": {
   235  							Type:     schema.TypeString,
   236  							Required: true,
   237  						},
   238  
   239  						"caching": {
   240  							Type:     schema.TypeString,
   241  							Optional: true,
   242  							Computed: true,
   243  						},
   244  
   245  						"disk_size_gb": {
   246  							Type:         schema.TypeInt,
   247  							Optional:     true,
   248  							Computed:     true,
   249  							ValidateFunc: validateDiskSizeGB,
   250  						},
   251  
   252  						"lun": {
   253  							Type:     schema.TypeInt,
   254  							Required: true,
   255  						},
   256  					},
   257  				},
   258  			},
   259  
   260  			"delete_data_disks_on_termination": {
   261  				Type:     schema.TypeBool,
   262  				Optional: true,
   263  				Default:  false,
   264  			},
   265  
   266  			"diagnostics_profile": {
   267  				Type:          schema.TypeSet,
   268  				Optional:      true,
   269  				MaxItems:      1,
   270  				ConflictsWith: []string{"boot_diagnostics"},
   271  				Deprecated:    "Use field boot_diagnostics instead",
   272  				Elem: &schema.Resource{
   273  					Schema: map[string]*schema.Schema{
   274  						"boot_diagnostics": {
   275  							Type:     schema.TypeSet,
   276  							Required: true,
   277  							MaxItems: 1,
   278  							Elem: &schema.Resource{
   279  								Schema: map[string]*schema.Schema{
   280  									"enabled": {
   281  										Type:     schema.TypeBool,
   282  										Required: true,
   283  									},
   284  
   285  									"storage_uri": {
   286  										Type:     schema.TypeString,
   287  										Required: true,
   288  									},
   289  								},
   290  							},
   291  						},
   292  					},
   293  				},
   294  			},
   295  
   296  			"boot_diagnostics": {
   297  				Type:     schema.TypeList,
   298  				Optional: true,
   299  				MaxItems: 1,
   300  				Elem: &schema.Resource{
   301  					Schema: map[string]*schema.Schema{
   302  						"enabled": {
   303  							Type:     schema.TypeBool,
   304  							Required: true,
   305  						},
   306  
   307  						"storage_uri": {
   308  							Type:     schema.TypeString,
   309  							Required: true,
   310  						},
   311  					},
   312  				},
   313  			},
   314  
   315  			"os_profile": {
   316  				Type:     schema.TypeSet,
   317  				Required: true,
   318  				MaxItems: 1,
   319  				Elem: &schema.Resource{
   320  					Schema: map[string]*schema.Schema{
   321  						"computer_name": {
   322  							Type:     schema.TypeString,
   323  							ForceNew: true,
   324  							Required: true,
   325  						},
   326  
   327  						"admin_username": {
   328  							Type:     schema.TypeString,
   329  							Required: true,
   330  						},
   331  
   332  						"admin_password": {
   333  							Type:     schema.TypeString,
   334  							Required: true,
   335  						},
   336  
   337  						"custom_data": {
   338  							Type:      schema.TypeString,
   339  							Optional:  true,
   340  							Computed:  true,
   341  							StateFunc: userDataStateFunc,
   342  						},
   343  					},
   344  				},
   345  				Set: resourceArmVirtualMachineStorageOsProfileHash,
   346  			},
   347  
   348  			"os_profile_windows_config": {
   349  				Type:     schema.TypeSet,
   350  				Optional: true,
   351  				MaxItems: 1,
   352  				Elem: &schema.Resource{
   353  					Schema: map[string]*schema.Schema{
   354  						"provision_vm_agent": {
   355  							Type:     schema.TypeBool,
   356  							Optional: true,
   357  						},
   358  						"enable_automatic_upgrades": {
   359  							Type:     schema.TypeBool,
   360  							Optional: true,
   361  						},
   362  						"winrm": {
   363  							Type:     schema.TypeList,
   364  							Optional: true,
   365  							Elem: &schema.Resource{
   366  								Schema: map[string]*schema.Schema{
   367  									"protocol": {
   368  										Type:     schema.TypeString,
   369  										Required: true,
   370  									},
   371  									"certificate_url": {
   372  										Type:     schema.TypeString,
   373  										Optional: true,
   374  									},
   375  								},
   376  							},
   377  						},
   378  						"additional_unattend_config": {
   379  							Type:     schema.TypeList,
   380  							Optional: true,
   381  							Elem: &schema.Resource{
   382  								Schema: map[string]*schema.Schema{
   383  									"pass": {
   384  										Type:     schema.TypeString,
   385  										Required: true,
   386  									},
   387  									"component": {
   388  										Type:     schema.TypeString,
   389  										Required: true,
   390  									},
   391  									"setting_name": {
   392  										Type:     schema.TypeString,
   393  										Required: true,
   394  									},
   395  									"content": {
   396  										Type:     schema.TypeString,
   397  										Required: true,
   398  									},
   399  								},
   400  							},
   401  						},
   402  					},
   403  				},
   404  				Set: resourceArmVirtualMachineStorageOsProfileWindowsConfigHash,
   405  			},
   406  
   407  			"os_profile_linux_config": {
   408  				Type:     schema.TypeSet,
   409  				Optional: true,
   410  				MaxItems: 1,
   411  				Elem: &schema.Resource{
   412  					Schema: map[string]*schema.Schema{
   413  						"disable_password_authentication": {
   414  							Type:     schema.TypeBool,
   415  							Required: true,
   416  						},
   417  						"ssh_keys": {
   418  							Type:     schema.TypeList,
   419  							Optional: true,
   420  							Elem: &schema.Resource{
   421  								Schema: map[string]*schema.Schema{
   422  									"path": {
   423  										Type:     schema.TypeString,
   424  										Required: true,
   425  									},
   426  									"key_data": {
   427  										Type:     schema.TypeString,
   428  										Optional: true,
   429  									},
   430  								},
   431  							},
   432  						},
   433  					},
   434  				},
   435  				Set: resourceArmVirtualMachineStorageOsProfileLinuxConfigHash,
   436  			},
   437  
   438  			"os_profile_secrets": {
   439  				Type:     schema.TypeSet,
   440  				Optional: true,
   441  				Elem: &schema.Resource{
   442  					Schema: map[string]*schema.Schema{
   443  						"source_vault_id": {
   444  							Type:     schema.TypeString,
   445  							Required: true,
   446  						},
   447  
   448  						"vault_certificates": {
   449  							Type:     schema.TypeList,
   450  							Optional: true,
   451  							Elem: &schema.Resource{
   452  								Schema: map[string]*schema.Schema{
   453  									"certificate_url": {
   454  										Type:     schema.TypeString,
   455  										Required: true,
   456  									},
   457  									"certificate_store": {
   458  										Type:     schema.TypeString,
   459  										Optional: true,
   460  									},
   461  								},
   462  							},
   463  						},
   464  					},
   465  				},
   466  			},
   467  
   468  			"network_interface_ids": {
   469  				Type:     schema.TypeSet,
   470  				Required: true,
   471  				Elem: &schema.Schema{
   472  					Type: schema.TypeString,
   473  				},
   474  				Set: schema.HashString,
   475  			},
   476  
   477  			"primary_network_interface_id": {
   478  				Type:     schema.TypeString,
   479  				Optional: true,
   480  			},
   481  
   482  			"tags": tagsSchema(),
   483  		},
   484  	}
   485  }
   486  
   487  func validateLicenseType(v interface{}, k string) (ws []string, errors []error) {
   488  	value := v.(string)
   489  	if value != "" && value != "Windows_Server" {
   490  		errors = append(errors, fmt.Errorf(
   491  			"[ERROR] license_type must be 'Windows_Server' or empty"))
   492  	}
   493  	return
   494  }
   495  
   496  func resourceArmVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
   497  	client := meta.(*ArmClient)
   498  	vmClient := client.vmClient
   499  
   500  	log.Printf("[INFO] preparing arguments for Azure ARM Virtual Machine creation.")
   501  
   502  	name := d.Get("name").(string)
   503  	location := d.Get("location").(string)
   504  	resGroup := d.Get("resource_group_name").(string)
   505  	tags := d.Get("tags").(map[string]interface{})
   506  	expandedTags := expandTags(tags)
   507  
   508  	osDisk, err := expandAzureRmVirtualMachineOsDisk(d)
   509  	if err != nil {
   510  		return err
   511  	}
   512  	storageProfile := compute.StorageProfile{
   513  		OsDisk: osDisk,
   514  	}
   515  
   516  	if _, ok := d.GetOk("storage_image_reference"); ok {
   517  		imageRef, err := expandAzureRmVirtualMachineImageReference(d)
   518  		if err != nil {
   519  			return err
   520  		}
   521  		storageProfile.ImageReference = imageRef
   522  	}
   523  
   524  	if _, ok := d.GetOk("storage_data_disk"); ok {
   525  		dataDisks, err := expandAzureRmVirtualMachineDataDisk(d)
   526  		if err != nil {
   527  			return err
   528  		}
   529  		storageProfile.DataDisks = &dataDisks
   530  	}
   531  
   532  	networkProfile := expandAzureRmVirtualMachineNetworkProfile(d)
   533  	vmSize := d.Get("vm_size").(string)
   534  	properties := compute.VirtualMachineProperties{
   535  		NetworkProfile: &networkProfile,
   536  		HardwareProfile: &compute.HardwareProfile{
   537  			VMSize: compute.VirtualMachineSizeTypes(vmSize),
   538  		},
   539  		StorageProfile: &storageProfile,
   540  	}
   541  
   542  	if v, ok := d.GetOk("license_type"); ok {
   543  		license := v.(string)
   544  		properties.LicenseType = &license
   545  	}
   546  
   547  	if _, ok := d.GetOk("boot_diagnostics"); ok {
   548  		diagnosticsProfile := expandAzureRmVirtualMachineDiagnosticsProfile(d)
   549  		if diagnosticsProfile != nil {
   550  			properties.DiagnosticsProfile = diagnosticsProfile
   551  		}
   552  	}
   553  
   554  	osProfile, err := expandAzureRmVirtualMachineOsProfile(d)
   555  	if err != nil {
   556  		return err
   557  	}
   558  	properties.OsProfile = osProfile
   559  
   560  	if v, ok := d.GetOk("availability_set_id"); ok {
   561  		availabilitySet := v.(string)
   562  		availSet := compute.SubResource{
   563  			ID: &availabilitySet,
   564  		}
   565  
   566  		properties.AvailabilitySet = &availSet
   567  	}
   568  
   569  	vm := compute.VirtualMachine{
   570  		Name:                     &name,
   571  		Location:                 &location,
   572  		VirtualMachineProperties: &properties,
   573  		Tags: expandedTags,
   574  	}
   575  
   576  	if _, ok := d.GetOk("plan"); ok {
   577  		plan, err := expandAzureRmVirtualMachinePlan(d)
   578  		if err != nil {
   579  			return err
   580  		}
   581  
   582  		vm.Plan = plan
   583  	}
   584  
   585  	_, vmErr := vmClient.CreateOrUpdate(resGroup, name, vm, make(chan struct{}))
   586  	if vmErr != nil {
   587  		return vmErr
   588  	}
   589  
   590  	read, err := vmClient.Get(resGroup, name, "")
   591  	if err != nil {
   592  		return err
   593  	}
   594  	if read.ID == nil {
   595  		return fmt.Errorf("Cannot read Virtual Machine %s (resource group %s) ID", name, resGroup)
   596  	}
   597  
   598  	d.SetId(*read.ID)
   599  
   600  	return resourceArmVirtualMachineRead(d, meta)
   601  }
   602  
   603  func resourceArmVirtualMachineRead(d *schema.ResourceData, meta interface{}) error {
   604  	vmClient := meta.(*ArmClient).vmClient
   605  
   606  	id, err := parseAzureResourceID(d.Id())
   607  	if err != nil {
   608  		return err
   609  	}
   610  	resGroup := id.ResourceGroup
   611  	name := id.Path["virtualMachines"]
   612  
   613  	resp, err := vmClient.Get(resGroup, name, "")
   614  
   615  	if err != nil {
   616  		if resp.StatusCode == http.StatusNotFound {
   617  			d.SetId("")
   618  			return nil
   619  		}
   620  		return fmt.Errorf("Error making Read request on Azure Virtual Machine %s: %s", name, err)
   621  	}
   622  
   623  	d.Set("name", resp.Name)
   624  	d.Set("resource_group_name", resGroup)
   625  	d.Set("location", resp.Location)
   626  
   627  	if resp.Plan != nil {
   628  		if err := d.Set("plan", schema.NewSet(resourceArmVirtualMachinePlanHash, flattenAzureRmVirtualMachinePlan(resp.Plan))); err != nil {
   629  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Plan error: %#v", err)
   630  		}
   631  	}
   632  
   633  	if resp.VirtualMachineProperties.AvailabilitySet != nil {
   634  		d.Set("availability_set_id", strings.ToLower(*resp.VirtualMachineProperties.AvailabilitySet.ID))
   635  	}
   636  
   637  	d.Set("vm_size", resp.VirtualMachineProperties.HardwareProfile.VMSize)
   638  
   639  	if resp.VirtualMachineProperties.StorageProfile.ImageReference != nil {
   640  		if err := d.Set("storage_image_reference", schema.NewSet(resourceArmVirtualMachineStorageImageReferenceHash, flattenAzureRmVirtualMachineImageReference(resp.VirtualMachineProperties.StorageProfile.ImageReference))); err != nil {
   641  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage Image Reference error: %#v", err)
   642  		}
   643  	}
   644  
   645  	if err := d.Set("storage_os_disk", schema.NewSet(resourceArmVirtualMachineStorageOsDiskHash, flattenAzureRmVirtualMachineOsDisk(resp.VirtualMachineProperties.StorageProfile.OsDisk))); err != nil {
   646  		return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Disk error: %#v", err)
   647  	}
   648  
   649  	if resp.VirtualMachineProperties.StorageProfile.DataDisks != nil {
   650  		if err := d.Set("storage_data_disk", flattenAzureRmVirtualMachineDataDisk(resp.VirtualMachineProperties.StorageProfile.DataDisks)); err != nil {
   651  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage Data Disks error: %#v", err)
   652  		}
   653  	}
   654  
   655  	if err := d.Set("os_profile", schema.NewSet(resourceArmVirtualMachineStorageOsProfileHash, flattenAzureRmVirtualMachineOsProfile(resp.VirtualMachineProperties.OsProfile))); err != nil {
   656  		return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile: %#v", err)
   657  	}
   658  
   659  	if resp.VirtualMachineProperties.OsProfile.WindowsConfiguration != nil {
   660  		if err := d.Set("os_profile_windows_config", flattenAzureRmVirtualMachineOsProfileWindowsConfiguration(resp.VirtualMachineProperties.OsProfile.WindowsConfiguration)); err != nil {
   661  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile Windows Configuration: %#v", err)
   662  		}
   663  	}
   664  
   665  	if resp.VirtualMachineProperties.OsProfile.LinuxConfiguration != nil {
   666  		if err := d.Set("os_profile_linux_config", flattenAzureRmVirtualMachineOsProfileLinuxConfiguration(resp.VirtualMachineProperties.OsProfile.LinuxConfiguration)); err != nil {
   667  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile Linux Configuration: %#v", err)
   668  		}
   669  	}
   670  
   671  	if resp.VirtualMachineProperties.OsProfile.Secrets != nil {
   672  		if err := d.Set("os_profile_secrets", flattenAzureRmVirtualMachineOsProfileSecrets(resp.VirtualMachineProperties.OsProfile.Secrets)); err != nil {
   673  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage OS Profile Secrets: %#v", err)
   674  		}
   675  	}
   676  
   677  	if resp.VirtualMachineProperties.DiagnosticsProfile != nil && resp.VirtualMachineProperties.DiagnosticsProfile.BootDiagnostics != nil {
   678  		if err := d.Set("boot_diagnostics", flattenAzureRmVirtualMachineDiagnosticsProfile(resp.VirtualMachineProperties.DiagnosticsProfile.BootDiagnostics)); err != nil {
   679  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Diagnostics Profile: %#v", err)
   680  		}
   681  	}
   682  
   683  	if resp.VirtualMachineProperties.NetworkProfile != nil {
   684  		if err := d.Set("network_interface_ids", flattenAzureRmVirtualMachineNetworkInterfaces(resp.VirtualMachineProperties.NetworkProfile)); err != nil {
   685  			return fmt.Errorf("[DEBUG] Error setting Virtual Machine Storage Network Interfaces: %#v", err)
   686  		}
   687  
   688  		if resp.VirtualMachineProperties.NetworkProfile.NetworkInterfaces != nil {
   689  			for _, nic := range *resp.VirtualMachineProperties.NetworkProfile.NetworkInterfaces {
   690  				if nic.NetworkInterfaceReferenceProperties != nil && *nic.NetworkInterfaceReferenceProperties.Primary {
   691  					d.Set("primary_network_interface_id", nic.ID)
   692  					break
   693  				}
   694  			}
   695  		}
   696  	}
   697  
   698  	flattenAndSetTags(d, resp.Tags)
   699  
   700  	return nil
   701  }
   702  
   703  func resourceArmVirtualMachineDelete(d *schema.ResourceData, meta interface{}) error {
   704  	vmClient := meta.(*ArmClient).vmClient
   705  
   706  	id, err := parseAzureResourceID(d.Id())
   707  	if err != nil {
   708  		return err
   709  	}
   710  	resGroup := id.ResourceGroup
   711  	name := id.Path["virtualMachines"]
   712  
   713  	if _, err = vmClient.Delete(resGroup, name, make(chan struct{})); err != nil {
   714  		return err
   715  	}
   716  
   717  	// delete OS Disk if opted in
   718  	if deleteOsDisk := d.Get("delete_os_disk_on_termination").(bool); deleteOsDisk {
   719  		log.Printf("[INFO] delete_os_disk_on_termination is enabled, deleting disk from %s", name)
   720  
   721  		osDisk, err := expandAzureRmVirtualMachineOsDisk(d)
   722  		if err != nil {
   723  			return fmt.Errorf("Error expanding OS Disk: %s", err)
   724  		}
   725  
   726  		if osDisk.Vhd != nil {
   727  			if err = resourceArmVirtualMachineDeleteVhd(*osDisk.Vhd.URI, meta); err != nil {
   728  				return fmt.Errorf("Error deleting OS Disk VHD: %s", err)
   729  			}
   730  		} else if osDisk.ManagedDisk != nil {
   731  			if err = resourceArmVirtualMachineDeleteManagedDisk(*osDisk.ManagedDisk.ID, meta); err != nil {
   732  				return fmt.Errorf("Error deleting OS Managed Disk: %s", err)
   733  			}
   734  		} else {
   735  			return fmt.Errorf("Unable to locate OS managed disk properties from %s", name)
   736  		}
   737  	}
   738  
   739  	// delete Data disks if opted in
   740  	if deleteDataDisks := d.Get("delete_data_disks_on_termination").(bool); deleteDataDisks {
   741  		log.Printf("[INFO] delete_data_disks_on_termination is enabled, deleting each data disk from %s", name)
   742  
   743  		disks, err := expandAzureRmVirtualMachineDataDisk(d)
   744  		if err != nil {
   745  			return fmt.Errorf("Error expanding Data Disks: %s", err)
   746  		}
   747  
   748  		for _, disk := range disks {
   749  			if disk.Vhd != nil {
   750  				if err = resourceArmVirtualMachineDeleteVhd(*disk.Vhd.URI, meta); err != nil {
   751  					return fmt.Errorf("Error deleting Data Disk VHD: %s", err)
   752  				}
   753  			} else if disk.ManagedDisk != nil {
   754  				if err = resourceArmVirtualMachineDeleteManagedDisk(*disk.ManagedDisk.ID, meta); err != nil {
   755  					return fmt.Errorf("Error deleting Data Managed Disk: %s", err)
   756  				}
   757  			} else {
   758  				return fmt.Errorf("Unable to locate data managed disk properties from %s", name)
   759  			}
   760  		}
   761  	}
   762  
   763  	return nil
   764  }
   765  
   766  func resourceArmVirtualMachineDeleteVhd(uri string, meta interface{}) error {
   767  	vhdURL, err := url.Parse(uri)
   768  	if err != nil {
   769  		return fmt.Errorf("Cannot parse Disk VHD URI: %s", err)
   770  	}
   771  
   772  	// VHD URI is in the form: https://storageAccountName.blob.core.windows.net/containerName/blobName
   773  	storageAccountName := strings.Split(vhdURL.Host, ".")[0]
   774  	path := strings.Split(strings.TrimPrefix(vhdURL.Path, "/"), "/")
   775  	containerName := path[0]
   776  	blobName := path[1]
   777  
   778  	storageAccountResourceGroupName, err := findStorageAccountResourceGroup(meta, storageAccountName)
   779  	if err != nil {
   780  		return fmt.Errorf("Error finding resource group for storage account %s: %s", storageAccountName, err)
   781  	}
   782  
   783  	blobClient, saExists, err := meta.(*ArmClient).getBlobStorageClientForStorageAccount(storageAccountResourceGroupName, storageAccountName)
   784  	if err != nil {
   785  		return fmt.Errorf("Error creating blob store client for VHD deletion: %s", err)
   786  	}
   787  
   788  	if !saExists {
   789  		log.Printf("[INFO] Storage Account %q in resource group %q doesn't exist so the VHD blob won't exist", storageAccountName, storageAccountResourceGroupName)
   790  		return nil
   791  	}
   792  
   793  	log.Printf("[INFO] Deleting VHD blob %s", blobName)
   794  	_, err = blobClient.DeleteBlobIfExists(containerName, blobName, nil)
   795  	if err != nil {
   796  		return fmt.Errorf("Error deleting VHD blob: %s", err)
   797  	}
   798  
   799  	return nil
   800  }
   801  
   802  func resourceArmVirtualMachineDeleteManagedDisk(managedDiskID string, meta interface{}) error {
   803  	diskClient := meta.(*ArmClient).diskClient
   804  
   805  	id, err := parseAzureResourceID(managedDiskID)
   806  	if err != nil {
   807  		return err
   808  	}
   809  	resGroup := id.ResourceGroup
   810  	name := id.Path["disks"]
   811  
   812  	_, err = diskClient.Delete(resGroup, name, make(chan struct{}))
   813  	if err != nil {
   814  		return fmt.Errorf("Error deleting Managed Disk (%s %s) %s", name, resGroup, err)
   815  	}
   816  
   817  	return nil
   818  }
   819  
   820  func resourceArmVirtualMachinePlanHash(v interface{}) int {
   821  	var buf bytes.Buffer
   822  	m := v.(map[string]interface{})
   823  	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
   824  	buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string)))
   825  	buf.WriteString(fmt.Sprintf("%s-", m["product"].(string)))
   826  
   827  	return hashcode.String(buf.String())
   828  }
   829  
   830  func resourceArmVirtualMachineStorageImageReferenceHash(v interface{}) int {
   831  	var buf bytes.Buffer
   832  	m := v.(map[string]interface{})
   833  	buf.WriteString(fmt.Sprintf("%s-", m["publisher"].(string)))
   834  	buf.WriteString(fmt.Sprintf("%s-", m["offer"].(string)))
   835  	buf.WriteString(fmt.Sprintf("%s-", m["sku"].(string)))
   836  
   837  	return hashcode.String(buf.String())
   838  }
   839  
   840  func resourceArmVirtualMachineStorageOsProfileHash(v interface{}) int {
   841  	var buf bytes.Buffer
   842  	m := v.(map[string]interface{})
   843  	buf.WriteString(fmt.Sprintf("%s-", m["admin_username"].(string)))
   844  	buf.WriteString(fmt.Sprintf("%s-", m["computer_name"].(string)))
   845  	return hashcode.String(buf.String())
   846  }
   847  
   848  func resourceArmVirtualMachineStorageOsDiskHash(v interface{}) int {
   849  	var buf bytes.Buffer
   850  	m := v.(map[string]interface{})
   851  	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
   852  	if m["vhd_uri"] != nil {
   853  		buf.WriteString(fmt.Sprintf("%s-", m["vhd_uri"].(string)))
   854  	}
   855  	return hashcode.String(buf.String())
   856  }
   857  
   858  func resourceArmVirtualMachineStorageOsProfileLinuxConfigHash(v interface{}) int {
   859  	var buf bytes.Buffer
   860  	m := v.(map[string]interface{})
   861  	buf.WriteString(fmt.Sprintf("%t-", m["disable_password_authentication"].(bool)))
   862  
   863  	return hashcode.String(buf.String())
   864  }
   865  
   866  func resourceArmVirtualMachineStorageOsProfileWindowsConfigHash(v interface{}) int {
   867  	var buf bytes.Buffer
   868  	m := v.(map[string]interface{})
   869  	if m["provision_vm_agent"] != nil {
   870  		buf.WriteString(fmt.Sprintf("%t-", m["provision_vm_agent"].(bool)))
   871  	}
   872  	if m["enable_automatic_upgrades"] != nil {
   873  		buf.WriteString(fmt.Sprintf("%t-", m["enable_automatic_upgrades"].(bool)))
   874  	}
   875  	return hashcode.String(buf.String())
   876  }
   877  
   878  func flattenAzureRmVirtualMachinePlan(plan *compute.Plan) []interface{} {
   879  	result := make(map[string]interface{})
   880  	result["name"] = *plan.Name
   881  	result["publisher"] = *plan.Publisher
   882  	result["product"] = *plan.Product
   883  
   884  	return []interface{}{result}
   885  }
   886  
   887  func flattenAzureRmVirtualMachineImageReference(image *compute.ImageReference) []interface{} {
   888  	result := make(map[string]interface{})
   889  	result["offer"] = *image.Offer
   890  	result["publisher"] = *image.Publisher
   891  	result["sku"] = *image.Sku
   892  
   893  	if image.Version != nil {
   894  		result["version"] = *image.Version
   895  	}
   896  
   897  	return []interface{}{result}
   898  }
   899  
   900  func flattenAzureRmVirtualMachineDiagnosticsProfile(profile *compute.BootDiagnostics) []interface{} {
   901  	result := make(map[string]interface{})
   902  
   903  	result["enabled"] = *profile.Enabled
   904  	if profile.StorageURI != nil {
   905  		result["storage_uri"] = *profile.StorageURI
   906  	}
   907  
   908  	return []interface{}{result}
   909  }
   910  
   911  func flattenAzureRmVirtualMachineNetworkInterfaces(profile *compute.NetworkProfile) []string {
   912  	result := make([]string, 0, len(*profile.NetworkInterfaces))
   913  	for _, nic := range *profile.NetworkInterfaces {
   914  		result = append(result, *nic.ID)
   915  	}
   916  	return result
   917  }
   918  
   919  func flattenAzureRmVirtualMachineOsProfileSecrets(secrets *[]compute.VaultSecretGroup) []map[string]interface{} {
   920  	result := make([]map[string]interface{}, 0, len(*secrets))
   921  	for _, secret := range *secrets {
   922  		s := map[string]interface{}{
   923  			"source_vault_id": *secret.SourceVault.ID,
   924  		}
   925  
   926  		if secret.VaultCertificates != nil {
   927  			certs := make([]map[string]interface{}, 0, len(*secret.VaultCertificates))
   928  			for _, cert := range *secret.VaultCertificates {
   929  				vaultCert := make(map[string]interface{})
   930  				vaultCert["certificate_url"] = *cert.CertificateURL
   931  
   932  				if cert.CertificateStore != nil {
   933  					vaultCert["certificate_store"] = *cert.CertificateStore
   934  				}
   935  
   936  				certs = append(certs, vaultCert)
   937  			}
   938  
   939  			s["vault_certificates"] = certs
   940  		}
   941  
   942  		result = append(result, s)
   943  	}
   944  	return result
   945  }
   946  
   947  func flattenAzureRmVirtualMachineDataDisk(disks *[]compute.DataDisk) interface{} {
   948  	result := make([]interface{}, len(*disks))
   949  	for i, disk := range *disks {
   950  		l := make(map[string]interface{})
   951  		l["name"] = *disk.Name
   952  		if disk.Vhd != nil {
   953  			l["vhd_uri"] = *disk.Vhd.URI
   954  		}
   955  		if disk.ManagedDisk != nil {
   956  			l["managed_disk_type"] = string(disk.ManagedDisk.StorageAccountType)
   957  			l["managed_disk_id"] = *disk.ManagedDisk.ID
   958  		}
   959  		l["create_option"] = disk.CreateOption
   960  		l["caching"] = string(disk.Caching)
   961  		if disk.DiskSizeGB != nil {
   962  			l["disk_size_gb"] = *disk.DiskSizeGB
   963  		}
   964  		l["lun"] = *disk.Lun
   965  
   966  		result[i] = l
   967  	}
   968  	return result
   969  }
   970  
   971  func flattenAzureRmVirtualMachineOsProfile(osProfile *compute.OSProfile) []interface{} {
   972  	result := make(map[string]interface{})
   973  	result["computer_name"] = *osProfile.ComputerName
   974  	result["admin_username"] = *osProfile.AdminUsername
   975  	if osProfile.CustomData != nil {
   976  		result["custom_data"] = *osProfile.CustomData
   977  	}
   978  
   979  	return []interface{}{result}
   980  }
   981  
   982  func flattenAzureRmVirtualMachineOsProfileWindowsConfiguration(config *compute.WindowsConfiguration) []interface{} {
   983  	result := make(map[string]interface{})
   984  
   985  	if config.ProvisionVMAgent != nil {
   986  		result["provision_vm_agent"] = *config.ProvisionVMAgent
   987  	}
   988  
   989  	if config.EnableAutomaticUpdates != nil {
   990  		result["enable_automatic_upgrades"] = *config.EnableAutomaticUpdates
   991  	}
   992  
   993  	if config.WinRM != nil {
   994  		listeners := make([]map[string]interface{}, 0, len(*config.WinRM.Listeners))
   995  		for _, i := range *config.WinRM.Listeners {
   996  			listener := make(map[string]interface{})
   997  			listener["protocol"] = i.Protocol
   998  
   999  			if i.CertificateURL != nil {
  1000  				listener["certificate_url"] = *i.CertificateURL
  1001  			}
  1002  
  1003  			listeners = append(listeners, listener)
  1004  		}
  1005  
  1006  		result["winrm"] = listeners
  1007  	}
  1008  
  1009  	if config.AdditionalUnattendContent != nil {
  1010  		content := make([]map[string]interface{}, 0, len(*config.AdditionalUnattendContent))
  1011  		for _, i := range *config.AdditionalUnattendContent {
  1012  			c := make(map[string]interface{})
  1013  			c["pass"] = i.PassName
  1014  			c["component"] = i.ComponentName
  1015  			c["setting_name"] = i.SettingName
  1016  
  1017  			if i.Content != nil {
  1018  				c["content"] = *i.Content
  1019  			}
  1020  
  1021  			content = append(content, c)
  1022  		}
  1023  
  1024  		result["additional_unattend_config"] = content
  1025  	}
  1026  
  1027  	return []interface{}{result}
  1028  }
  1029  
  1030  func flattenAzureRmVirtualMachineOsProfileLinuxConfiguration(config *compute.LinuxConfiguration) []interface{} {
  1031  
  1032  	result := make(map[string]interface{})
  1033  	result["disable_password_authentication"] = *config.DisablePasswordAuthentication
  1034  
  1035  	if config.SSH != nil && len(*config.SSH.PublicKeys) > 0 {
  1036  		ssh_keys := make([]map[string]interface{}, len(*config.SSH.PublicKeys))
  1037  		for _, i := range *config.SSH.PublicKeys {
  1038  			key := make(map[string]interface{})
  1039  			key["path"] = *i.Path
  1040  
  1041  			if i.KeyData != nil {
  1042  				key["key_data"] = *i.KeyData
  1043  			}
  1044  
  1045  			ssh_keys = append(ssh_keys, key)
  1046  		}
  1047  
  1048  		result["ssh_keys"] = ssh_keys
  1049  	}
  1050  
  1051  	return []interface{}{result}
  1052  }
  1053  
  1054  func flattenAzureRmVirtualMachineOsDisk(disk *compute.OSDisk) []interface{} {
  1055  	result := make(map[string]interface{})
  1056  	result["name"] = *disk.Name
  1057  	if disk.Vhd != nil {
  1058  		result["vhd_uri"] = *disk.Vhd.URI
  1059  	}
  1060  	if disk.ManagedDisk != nil {
  1061  		result["managed_disk_type"] = string(disk.ManagedDisk.StorageAccountType)
  1062  		result["managed_disk_id"] = *disk.ManagedDisk.ID
  1063  	}
  1064  	result["create_option"] = disk.CreateOption
  1065  	result["caching"] = disk.Caching
  1066  	if disk.DiskSizeGB != nil {
  1067  		result["disk_size_gb"] = *disk.DiskSizeGB
  1068  	}
  1069  
  1070  	return []interface{}{result}
  1071  }
  1072  
  1073  func expandAzureRmVirtualMachinePlan(d *schema.ResourceData) (*compute.Plan, error) {
  1074  	planConfigs := d.Get("plan").(*schema.Set).List()
  1075  
  1076  	planConfig := planConfigs[0].(map[string]interface{})
  1077  
  1078  	publisher := planConfig["publisher"].(string)
  1079  	name := planConfig["name"].(string)
  1080  	product := planConfig["product"].(string)
  1081  
  1082  	return &compute.Plan{
  1083  		Publisher: &publisher,
  1084  		Name:      &name,
  1085  		Product:   &product,
  1086  	}, nil
  1087  }
  1088  
  1089  func expandAzureRmVirtualMachineOsProfile(d *schema.ResourceData) (*compute.OSProfile, error) {
  1090  	osProfiles := d.Get("os_profile").(*schema.Set).List()
  1091  
  1092  	osProfile := osProfiles[0].(map[string]interface{})
  1093  
  1094  	adminUsername := osProfile["admin_username"].(string)
  1095  	adminPassword := osProfile["admin_password"].(string)
  1096  	computerName := osProfile["computer_name"].(string)
  1097  
  1098  	profile := &compute.OSProfile{
  1099  		AdminUsername: &adminUsername,
  1100  		ComputerName:  &computerName,
  1101  	}
  1102  
  1103  	if adminPassword != "" {
  1104  		profile.AdminPassword = &adminPassword
  1105  	}
  1106  
  1107  	if _, ok := d.GetOk("os_profile_windows_config"); ok {
  1108  		winConfig, err := expandAzureRmVirtualMachineOsProfileWindowsConfig(d)
  1109  		if err != nil {
  1110  			return nil, err
  1111  		}
  1112  		if winConfig != nil {
  1113  			profile.WindowsConfiguration = winConfig
  1114  		}
  1115  	}
  1116  
  1117  	if _, ok := d.GetOk("os_profile_linux_config"); ok {
  1118  		linuxConfig, err := expandAzureRmVirtualMachineOsProfileLinuxConfig(d)
  1119  		if err != nil {
  1120  			return nil, err
  1121  		}
  1122  		if linuxConfig != nil {
  1123  			profile.LinuxConfiguration = linuxConfig
  1124  		}
  1125  	}
  1126  
  1127  	if _, ok := d.GetOk("os_profile_secrets"); ok {
  1128  		secrets := expandAzureRmVirtualMachineOsProfileSecrets(d)
  1129  		if secrets != nil {
  1130  			profile.Secrets = secrets
  1131  		}
  1132  	}
  1133  
  1134  	if v := osProfile["custom_data"].(string); v != "" {
  1135  		v = base64Encode(v)
  1136  		profile.CustomData = &v
  1137  	}
  1138  
  1139  	return profile, nil
  1140  }
  1141  
  1142  func expandAzureRmVirtualMachineOsProfileSecrets(d *schema.ResourceData) *[]compute.VaultSecretGroup {
  1143  	secretsConfig := d.Get("os_profile_secrets").(*schema.Set).List()
  1144  	secrets := make([]compute.VaultSecretGroup, 0, len(secretsConfig))
  1145  
  1146  	for _, secretConfig := range secretsConfig {
  1147  		config := secretConfig.(map[string]interface{})
  1148  		sourceVaultId := config["source_vault_id"].(string)
  1149  
  1150  		vaultSecretGroup := compute.VaultSecretGroup{
  1151  			SourceVault: &compute.SubResource{
  1152  				ID: &sourceVaultId,
  1153  			},
  1154  		}
  1155  
  1156  		if v := config["vault_certificates"]; v != nil {
  1157  			certsConfig := v.([]interface{})
  1158  			certs := make([]compute.VaultCertificate, 0, len(certsConfig))
  1159  			for _, certConfig := range certsConfig {
  1160  				config := certConfig.(map[string]interface{})
  1161  
  1162  				certUrl := config["certificate_url"].(string)
  1163  				cert := compute.VaultCertificate{
  1164  					CertificateURL: &certUrl,
  1165  				}
  1166  				if v := config["certificate_store"].(string); v != "" {
  1167  					cert.CertificateStore = &v
  1168  				}
  1169  
  1170  				certs = append(certs, cert)
  1171  			}
  1172  			vaultSecretGroup.VaultCertificates = &certs
  1173  		}
  1174  
  1175  		secrets = append(secrets, vaultSecretGroup)
  1176  	}
  1177  
  1178  	return &secrets
  1179  }
  1180  
  1181  func expandAzureRmVirtualMachineOsProfileLinuxConfig(d *schema.ResourceData) (*compute.LinuxConfiguration, error) {
  1182  	osProfilesLinuxConfig := d.Get("os_profile_linux_config").(*schema.Set).List()
  1183  
  1184  	linuxConfig := osProfilesLinuxConfig[0].(map[string]interface{})
  1185  	disablePasswordAuth := linuxConfig["disable_password_authentication"].(bool)
  1186  
  1187  	config := &compute.LinuxConfiguration{
  1188  		DisablePasswordAuthentication: &disablePasswordAuth,
  1189  	}
  1190  
  1191  	linuxKeys := linuxConfig["ssh_keys"].([]interface{})
  1192  	sshPublicKeys := []compute.SSHPublicKey{}
  1193  	for _, key := range linuxKeys {
  1194  
  1195  		sshKey, ok := key.(map[string]interface{})
  1196  		if !ok {
  1197  			continue
  1198  		}
  1199  		path := sshKey["path"].(string)
  1200  		keyData := sshKey["key_data"].(string)
  1201  
  1202  		sshPublicKey := compute.SSHPublicKey{
  1203  			Path:    &path,
  1204  			KeyData: &keyData,
  1205  		}
  1206  
  1207  		sshPublicKeys = append(sshPublicKeys, sshPublicKey)
  1208  	}
  1209  
  1210  	if len(sshPublicKeys) > 0 {
  1211  		config.SSH = &compute.SSHConfiguration{
  1212  			PublicKeys: &sshPublicKeys,
  1213  		}
  1214  	}
  1215  
  1216  	return config, nil
  1217  }
  1218  
  1219  func expandAzureRmVirtualMachineOsProfileWindowsConfig(d *schema.ResourceData) (*compute.WindowsConfiguration, error) {
  1220  	osProfilesWindowsConfig := d.Get("os_profile_windows_config").(*schema.Set).List()
  1221  
  1222  	osProfileConfig := osProfilesWindowsConfig[0].(map[string]interface{})
  1223  	config := &compute.WindowsConfiguration{}
  1224  
  1225  	if v := osProfileConfig["provision_vm_agent"]; v != nil {
  1226  		provision := v.(bool)
  1227  		config.ProvisionVMAgent = &provision
  1228  	}
  1229  
  1230  	if v := osProfileConfig["enable_automatic_upgrades"]; v != nil {
  1231  		update := v.(bool)
  1232  		config.EnableAutomaticUpdates = &update
  1233  	}
  1234  
  1235  	if v := osProfileConfig["winrm"]; v != nil {
  1236  		winRm := v.([]interface{})
  1237  		if len(winRm) > 0 {
  1238  			winRmListeners := make([]compute.WinRMListener, 0, len(winRm))
  1239  			for _, winRmConfig := range winRm {
  1240  				config := winRmConfig.(map[string]interface{})
  1241  
  1242  				protocol := config["protocol"].(string)
  1243  				winRmListener := compute.WinRMListener{
  1244  					Protocol: compute.ProtocolTypes(protocol),
  1245  				}
  1246  				if v := config["certificate_url"].(string); v != "" {
  1247  					winRmListener.CertificateURL = &v
  1248  				}
  1249  
  1250  				winRmListeners = append(winRmListeners, winRmListener)
  1251  			}
  1252  			config.WinRM = &compute.WinRMConfiguration{
  1253  				Listeners: &winRmListeners,
  1254  			}
  1255  		}
  1256  	}
  1257  	if v := osProfileConfig["additional_unattend_config"]; v != nil {
  1258  		additionalConfig := v.([]interface{})
  1259  		if len(additionalConfig) > 0 {
  1260  			additionalConfigContent := make([]compute.AdditionalUnattendContent, 0, len(additionalConfig))
  1261  			for _, addConfig := range additionalConfig {
  1262  				config := addConfig.(map[string]interface{})
  1263  				pass := config["pass"].(string)
  1264  				component := config["component"].(string)
  1265  				settingName := config["setting_name"].(string)
  1266  				content := config["content"].(string)
  1267  
  1268  				addContent := compute.AdditionalUnattendContent{
  1269  					PassName:      compute.PassNames(pass),
  1270  					ComponentName: compute.ComponentNames(component),
  1271  					SettingName:   compute.SettingNames(settingName),
  1272  					Content:       &content,
  1273  				}
  1274  
  1275  				additionalConfigContent = append(additionalConfigContent, addContent)
  1276  			}
  1277  			config.AdditionalUnattendContent = &additionalConfigContent
  1278  		}
  1279  	}
  1280  	return config, nil
  1281  }
  1282  
  1283  func expandAzureRmVirtualMachineDataDisk(d *schema.ResourceData) ([]compute.DataDisk, error) {
  1284  	disks := d.Get("storage_data_disk").([]interface{})
  1285  	data_disks := make([]compute.DataDisk, 0, len(disks))
  1286  	for _, disk_config := range disks {
  1287  		config := disk_config.(map[string]interface{})
  1288  
  1289  		name := config["name"].(string)
  1290  		createOption := config["create_option"].(string)
  1291  		vhdURI := config["vhd_uri"].(string)
  1292  		managedDiskType := config["managed_disk_type"].(string)
  1293  		managedDiskID := config["managed_disk_id"].(string)
  1294  		lun := int32(config["lun"].(int))
  1295  
  1296  		data_disk := compute.DataDisk{
  1297  			Name:         &name,
  1298  			Lun:          &lun,
  1299  			CreateOption: compute.DiskCreateOptionTypes(createOption),
  1300  		}
  1301  
  1302  		if vhdURI != "" {
  1303  			data_disk.Vhd = &compute.VirtualHardDisk{
  1304  				URI: &vhdURI,
  1305  			}
  1306  		}
  1307  
  1308  		managedDisk := &compute.ManagedDiskParameters{}
  1309  
  1310  		if managedDiskType != "" {
  1311  			managedDisk.StorageAccountType = compute.StorageAccountTypes(managedDiskType)
  1312  			data_disk.ManagedDisk = managedDisk
  1313  		}
  1314  
  1315  		if managedDiskID != "" {
  1316  			managedDisk.ID = &managedDiskID
  1317  			data_disk.ManagedDisk = managedDisk
  1318  		}
  1319  
  1320  		//BEGIN: code to be removed after GH-13016 is merged
  1321  		if vhdURI != "" && managedDiskID != "" {
  1322  			return nil, fmt.Errorf("[ERROR] Conflict between `vhd_uri` and `managed_disk_id` (only one or the other can be used)")
  1323  		}
  1324  		if vhdURI != "" && managedDiskType != "" {
  1325  			return nil, fmt.Errorf("[ERROR] Conflict between `vhd_uri` and `managed_disk_type` (only one or the other can be used)")
  1326  		}
  1327  		//END: code to be removed after GH-13016 is merged
  1328  		if managedDiskID == "" && strings.EqualFold(string(data_disk.CreateOption), string(compute.Attach)) {
  1329  			return nil, fmt.Errorf("[ERROR] Must specify which disk to attach")
  1330  		}
  1331  
  1332  		if v := config["caching"].(string); v != "" {
  1333  			data_disk.Caching = compute.CachingTypes(v)
  1334  		}
  1335  
  1336  		if v := config["disk_size_gb"]; v != nil {
  1337  			diskSize := int32(config["disk_size_gb"].(int))
  1338  			data_disk.DiskSizeGB = &diskSize
  1339  		}
  1340  
  1341  		data_disks = append(data_disks, data_disk)
  1342  	}
  1343  
  1344  	return data_disks, nil
  1345  }
  1346  
  1347  func expandAzureRmVirtualMachineDiagnosticsProfile(d *schema.ResourceData) *compute.DiagnosticsProfile {
  1348  	bootDiagnostics := d.Get("boot_diagnostics").([]interface{})
  1349  
  1350  	diagnosticsProfile := &compute.DiagnosticsProfile{}
  1351  	if len(bootDiagnostics) > 0 {
  1352  		bootDiagnostic := bootDiagnostics[0].(map[string]interface{})
  1353  
  1354  		diagnostic := &compute.BootDiagnostics{
  1355  			Enabled:    riviera.Bool(bootDiagnostic["enabled"].(bool)),
  1356  			StorageURI: riviera.String(bootDiagnostic["storage_uri"].(string)),
  1357  		}
  1358  
  1359  		diagnosticsProfile.BootDiagnostics = diagnostic
  1360  
  1361  		return diagnosticsProfile
  1362  	}
  1363  
  1364  	return nil
  1365  }
  1366  
  1367  func expandAzureRmVirtualMachineImageReference(d *schema.ResourceData) (*compute.ImageReference, error) {
  1368  	storageImageRefs := d.Get("storage_image_reference").(*schema.Set).List()
  1369  
  1370  	storageImageRef := storageImageRefs[0].(map[string]interface{})
  1371  
  1372  	publisher := storageImageRef["publisher"].(string)
  1373  	offer := storageImageRef["offer"].(string)
  1374  	sku := storageImageRef["sku"].(string)
  1375  	version := storageImageRef["version"].(string)
  1376  
  1377  	return &compute.ImageReference{
  1378  		Publisher: &publisher,
  1379  		Offer:     &offer,
  1380  		Sku:       &sku,
  1381  		Version:   &version,
  1382  	}, nil
  1383  }
  1384  
  1385  func expandAzureRmVirtualMachineNetworkProfile(d *schema.ResourceData) compute.NetworkProfile {
  1386  	nicIds := d.Get("network_interface_ids").(*schema.Set).List()
  1387  	primaryNicId := d.Get("primary_network_interface_id").(string)
  1388  	network_interfaces := make([]compute.NetworkInterfaceReference, 0, len(nicIds))
  1389  
  1390  	network_profile := compute.NetworkProfile{}
  1391  
  1392  	for _, nic := range nicIds {
  1393  		id := nic.(string)
  1394  		primary := id == primaryNicId
  1395  
  1396  		network_interface := compute.NetworkInterfaceReference{
  1397  			ID: &id,
  1398  			NetworkInterfaceReferenceProperties: &compute.NetworkInterfaceReferenceProperties{
  1399  				Primary: &primary,
  1400  			},
  1401  		}
  1402  		network_interfaces = append(network_interfaces, network_interface)
  1403  	}
  1404  
  1405  	network_profile.NetworkInterfaces = &network_interfaces
  1406  
  1407  	return network_profile
  1408  }
  1409  
  1410  func expandAzureRmVirtualMachineOsDisk(d *schema.ResourceData) (*compute.OSDisk, error) {
  1411  	disks := d.Get("storage_os_disk").(*schema.Set).List()
  1412  
  1413  	config := disks[0].(map[string]interface{})
  1414  
  1415  	name := config["name"].(string)
  1416  	imageURI := config["image_uri"].(string)
  1417  	createOption := config["create_option"].(string)
  1418  	vhdURI := config["vhd_uri"].(string)
  1419  	managedDiskType := config["managed_disk_type"].(string)
  1420  	managedDiskID := config["managed_disk_id"].(string)
  1421  
  1422  	osDisk := &compute.OSDisk{
  1423  		Name:         &name,
  1424  		CreateOption: compute.DiskCreateOptionTypes(createOption),
  1425  	}
  1426  
  1427  	if vhdURI != "" {
  1428  		osDisk.Vhd = &compute.VirtualHardDisk{
  1429  			URI: &vhdURI,
  1430  		}
  1431  	}
  1432  
  1433  	managedDisk := &compute.ManagedDiskParameters{}
  1434  
  1435  	if managedDiskType != "" {
  1436  		managedDisk.StorageAccountType = compute.StorageAccountTypes(managedDiskType)
  1437  		osDisk.ManagedDisk = managedDisk
  1438  	}
  1439  
  1440  	if managedDiskID != "" {
  1441  		managedDisk.ID = &managedDiskID
  1442  		osDisk.ManagedDisk = managedDisk
  1443  	}
  1444  
  1445  	//BEGIN: code to be removed after GH-13016 is merged
  1446  	if vhdURI != "" && managedDiskID != "" {
  1447  		return nil, fmt.Errorf("[ERROR] Conflict between `vhd_uri` and `managed_disk_id` (only one or the other can be used)")
  1448  	}
  1449  	if vhdURI != "" && managedDiskType != "" {
  1450  		return nil, fmt.Errorf("[ERROR] Conflict between `vhd_uri` and `managed_disk_type` (only one or the other can be used)")
  1451  	}
  1452  	//END: code to be removed after GH-13016 is merged
  1453  	if managedDiskID == "" && strings.EqualFold(string(osDisk.CreateOption), string(compute.Attach)) {
  1454  		return nil, fmt.Errorf("[ERROR] Must specify which disk to attach")
  1455  	}
  1456  
  1457  	if v := config["image_uri"].(string); v != "" {
  1458  		osDisk.Image = &compute.VirtualHardDisk{
  1459  			URI: &imageURI,
  1460  		}
  1461  	}
  1462  
  1463  	if v := config["os_type"].(string); v != "" {
  1464  		if v == "linux" {
  1465  			osDisk.OsType = compute.Linux
  1466  		} else if v == "windows" {
  1467  			osDisk.OsType = compute.Windows
  1468  		} else {
  1469  			return nil, fmt.Errorf("[ERROR] os_type must be 'linux' or 'windows'")
  1470  		}
  1471  	}
  1472  
  1473  	if v := config["caching"].(string); v != "" {
  1474  		osDisk.Caching = compute.CachingTypes(v)
  1475  	}
  1476  
  1477  	if v := config["disk_size_gb"].(int); v != 0 {
  1478  		diskSize := int32(v)
  1479  		osDisk.DiskSizeGB = &diskSize
  1480  	}
  1481  
  1482  	return osDisk, nil
  1483  }
  1484  
  1485  func findStorageAccountResourceGroup(meta interface{}, storageAccountName string) (string, error) {
  1486  	client := meta.(*ArmClient).resourceFindClient
  1487  	filter := fmt.Sprintf("name eq '%s' and resourceType eq 'Microsoft.Storage/storageAccounts'", storageAccountName)
  1488  	expand := ""
  1489  	var pager *int32
  1490  
  1491  	rf, err := client.List(filter, expand, pager)
  1492  	if err != nil {
  1493  		return "", fmt.Errorf("Error making resource request for query %s: %s", filter, err)
  1494  	}
  1495  
  1496  	results := *rf.Value
  1497  	if len(results) != 1 {
  1498  		return "", fmt.Errorf("Wrong number of results making resource request for query %s: %d", filter, len(results))
  1499  	}
  1500  
  1501  	id, err := parseAzureResourceID(*results[0].ID)
  1502  	if err != nil {
  1503  		return "", err
  1504  	}
  1505  
  1506  	return id.ResourceGroup, nil
  1507  }