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