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