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