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