github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/azurerm/resource_arm_virtual_machine.go (about)

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