terraform/builtin/providers/azure/resource_virtual_machine.go

243 lines
6.3 KiB
Go

package azure
import (
"bytes"
"fmt"
"log"
"github.com/MSOpenTech/azure-sdk-for-go/clients/hostedServiceClient"
"github.com/MSOpenTech/azure-sdk-for-go/clients/vmClient"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceVirtualMachine() *schema.Resource {
return &schema.Resource{
Create: resourceVirtualMachineCreate,
Read: resourceVirtualMachineRead,
Delete: resourceVirtualMachineDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"location": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"image": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"size": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"username": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"password": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
ForceNew: true,
},
"ssh_public_key_file": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
ForceNew: true,
},
"ssh_port": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 22,
ForceNew: true,
},
"endpoint": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Computed: true,
ForceNew: true, // This can be updatable once we support updates on the resource
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"protocol": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"port": &schema.Schema{
Type: schema.TypeInt,
Required: true,
},
"local_port": &schema.Schema{
Type: schema.TypeInt,
Required: true,
},
},
},
Set: resourceVirtualMachineEndpointHash,
},
"url": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"ip_address": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"vip_address": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Creating Azure Virtual Machine Configuration...")
vmConfig, err := vmClient.CreateAzureVMConfiguration(
d.Get("name").(string),
d.Get("size").(string),
d.Get("image").(string),
d.Get("location").(string))
if err != nil {
return fmt.Errorf("Error creating Azure virtual machine configuration: %s", err)
}
// Only Linux VMs are supported. If we want to support other VM types, we need to
// grab the image details and based on the OS add the corresponding configuration.
log.Printf("[DEBUG] Adding Azure Linux Provisioning Configuration...")
vmConfig, err = vmClient.AddAzureLinuxProvisioningConfig(
vmConfig,
d.Get("username").(string),
d.Get("password").(string),
d.Get("ssh_public_key_file").(string),
d.Get("ssh_port").(int))
if err != nil {
return fmt.Errorf("Error adding Azure linux provisioning configuration: %s", err)
}
if v := d.Get("endpoint").(*schema.Set); v.Len() > 0 {
log.Printf("[DEBUG] Adding Endpoints to the Azure Virtual Machine...")
endpoints := make([]vmClient.InputEndpoint, v.Len())
for i, v := range v.List() {
m := v.(map[string]interface{})
endpoint := vmClient.InputEndpoint{}
endpoint.Name = m["name"].(string)
endpoint.Protocol = m["protocol"].(string)
endpoint.Port = m["port"].(int)
endpoint.LocalPort = m["local_port"].(int)
endpoints[i] = endpoint
}
configSets := vmConfig.ConfigurationSets.ConfigurationSet
if len(configSets) == 0 {
return fmt.Errorf("Azure virtual machine does not have configuration sets")
}
for i := 0; i < len(configSets); i++ {
if configSets[i].ConfigurationSetType != "NetworkConfiguration" {
continue
}
configSets[i].InputEndpoints.InputEndpoint =
append(configSets[i].InputEndpoints.InputEndpoint, endpoints...)
}
}
log.Printf("[DEBUG] Creating Azure Virtual Machine...")
err = vmClient.CreateAzureVM(
vmConfig,
d.Get("name").(string),
d.Get("location").(string))
if err != nil {
return fmt.Errorf("Error creating Azure virtual machine: %s", err)
}
d.SetId(d.Get("name").(string))
return resourceVirtualMachineRead(d, meta)
}
func resourceVirtualMachineRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Getting Azure Virtual Machine Deployment: %s", d.Id())
VMDeployment, err := vmClient.GetVMDeployment(d.Id(), d.Id())
if err != nil {
return fmt.Errorf("Error getting Azure virtual machine deployment: %s", err)
}
d.Set("url", VMDeployment.Url)
roleInstances := VMDeployment.RoleInstanceList.RoleInstance
if len(roleInstances) == 0 {
return fmt.Errorf("Virtual Machine does not have IP addresses")
}
ipAddress := roleInstances[0].IpAddress
d.Set("ip_address", ipAddress)
vips := VMDeployment.VirtualIPs.VirtualIP
if len(vips) == 0 {
return fmt.Errorf("Virtual Machine does not have VIP addresses")
}
vip := vips[0].Address
d.Set("vip_address", vip)
d.SetConnInfo(map[string]string{
"type": "ssh",
"host": vip,
"user": d.Get("username").(string),
})
return nil
}
func resourceVirtualMachineDelete(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Deleting Azure Virtual Machine Deployment: %s", d.Id())
if err := vmClient.DeleteVMDeployment(d.Id(), d.Id()); err != nil {
return fmt.Errorf("Error deleting Azure virtual machine deployment: %s", err)
}
log.Printf("[DEBUG] Deleting Azure Hosted Service: %s", d.Id())
if err := hostedServiceClient.DeleteHostedService(d.Id()); err != nil {
return fmt.Errorf("Error deleting Azure hosted service: %s", err)
}
d.SetId("")
return nil
}
func resourceVirtualMachineEndpointHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
buf.WriteString(fmt.Sprintf("%d-", m["port"].(int)))
buf.WriteString(fmt.Sprintf("%d-", m["local_port"].(int)))
return hashcode.String(buf.String())
}