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