terraform/builtin/providers/vcd/resource_vcd_vapp.go

372 lines
9.5 KiB
Go

package vcd
import (
"fmt"
"log"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
types "github.com/ukcloud/govcloudair/types/v56"
)
func resourceVcdVApp() *schema.Resource {
return &schema.Resource{
Create: resourceVcdVAppCreate,
Update: resourceVcdVAppUpdate,
Read: resourceVcdVAppRead,
Delete: resourceVcdVAppDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"template_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"catalog_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"network_href": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"network_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"memory": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
},
"cpus": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
},
"ip": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"initscript": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"metadata": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
},
"href": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"power_on": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: true,
},
},
}
}
func resourceVcdVAppCreate(d *schema.ResourceData, meta interface{}) error {
vcdClient := meta.(*VCDClient)
catalog, err := vcdClient.Org.FindCatalog(d.Get("catalog_name").(string))
if err != nil {
return fmt.Errorf("Error finding catalog: %#v", err)
}
catalogitem, err := catalog.FindCatalogItem(d.Get("template_name").(string))
if err != nil {
return fmt.Errorf("Error finding catelog item: %#v", err)
}
vapptemplate, err := catalogitem.GetVAppTemplate()
if err != nil {
return fmt.Errorf("Error finding VAppTemplate: %#v", err)
}
log.Printf("[DEBUG] VAppTemplate: %#v", vapptemplate)
var networkHref string
net, err := vcdClient.OrgVdc.FindVDCNetwork(d.Get("network_name").(string))
if err != nil {
return fmt.Errorf("Error finding OrgVCD Network: %#v", err)
}
if attr, ok := d.GetOk("network_href"); ok {
networkHref = attr.(string)
} else {
networkHref = net.OrgVDCNetwork.HREF
}
// vapptemplate := govcd.NewVAppTemplate(&vcdClient.Client)
//
createvapp := &types.InstantiateVAppTemplateParams{
Ovf: "http://schemas.dmtf.org/ovf/envelope/1",
Xmlns: "http://www.vmware.com/vcloud/v1.5",
Name: d.Get("name").(string),
InstantiationParams: &types.InstantiationParams{
NetworkConfigSection: &types.NetworkConfigSection{
Info: "Configuration parameters for logical networks",
NetworkConfig: &types.VAppNetworkConfiguration{
NetworkName: d.Get("network_name").(string),
Configuration: &types.NetworkConfiguration{
ParentNetwork: &types.Reference{
HREF: networkHref,
},
FenceMode: "bridged",
},
},
},
},
Source: &types.Reference{
HREF: vapptemplate.VAppTemplate.HREF,
},
}
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
e := vcdClient.OrgVdc.InstantiateVAppTemplate(createvapp)
if e != nil {
return resource.RetryableError(fmt.Errorf("Error: %#v", e))
}
e = vcdClient.OrgVdc.Refresh()
if e != nil {
return resource.RetryableError(fmt.Errorf("Error: %#v", e))
}
return nil
})
if err != nil {
return err
}
vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Get("name").(string))
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
task, err := vapp.ChangeVMName(d.Get("name").(string))
if err != nil {
return resource.RetryableError(fmt.Errorf("Error with vm name change: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
if err != nil {
return fmt.Errorf("Error changing vmname: %#v", err)
}
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
task, err := vapp.ChangeNetworkConfig(d.Get("network_name").(string), d.Get("ip").(string))
if err != nil {
return resource.RetryableError(fmt.Errorf("Error with Networking change: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
if err != nil {
return fmt.Errorf("Error changing network: %#v", err)
}
if initscript, ok := d.GetOk("initscript"); ok {
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
task, err := vapp.RunCustomizationScript(d.Get("name").(string), initscript.(string))
if err != nil {
return resource.RetryableError(fmt.Errorf("Error with setting init script: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
if err != nil {
return fmt.Errorf("Error completing tasks: %#v", err)
}
}
d.SetId(d.Get("name").(string))
return resourceVcdVAppUpdate(d, meta)
}
func resourceVcdVAppUpdate(d *schema.ResourceData, meta interface{}) error {
vcdClient := meta.(*VCDClient)
vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Id())
if err != nil {
return fmt.Errorf("Error finding VApp: %#v", err)
}
status, err := vapp.GetStatus()
if err != nil {
return fmt.Errorf("Error getting VApp status: %#v", err)
}
if d.HasChange("metadata") {
oraw, nraw := d.GetChange("metadata")
metadata := oraw.(map[string]interface{})
for k := range metadata {
task, err := vapp.DeleteMetadata(k)
if err != nil {
return fmt.Errorf("Error deleting metadata: %#v", err)
}
err = task.WaitTaskCompletion()
if err != nil {
return fmt.Errorf("Error completing tasks: %#v", err)
}
}
metadata = nraw.(map[string]interface{})
for k, v := range metadata {
task, err := vapp.AddMetadata(k, v.(string))
if err != nil {
return fmt.Errorf("Error adding metadata: %#v", err)
}
err = task.WaitTaskCompletion()
if err != nil {
return fmt.Errorf("Error completing tasks: %#v", err)
}
}
}
if d.HasChange("memory") || d.HasChange("cpus") || d.HasChange("power_on") {
if status != "POWERED_OFF" {
task, err := vapp.PowerOff()
if err != nil {
return fmt.Errorf("Error Powering Off: %#v", err)
}
err = task.WaitTaskCompletion()
if err != nil {
return fmt.Errorf("Error completing tasks: %#v", err)
}
}
if d.HasChange("memory") {
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
task, err := vapp.ChangeMemorySize(d.Get("memory").(int))
if err != nil {
return resource.RetryableError(fmt.Errorf("Error changing memory size: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
if err != nil {
return err
}
}
if d.HasChange("cpus") {
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
task, err := vapp.ChangeCPUcount(d.Get("cpus").(int))
if err != nil {
return resource.RetryableError(fmt.Errorf("Error changing cpu count: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
if err != nil {
return fmt.Errorf("Error completing task: %#v", err)
}
}
if d.Get("power_on").(bool) {
task, err := vapp.PowerOn()
if err != nil {
return fmt.Errorf("Error Powering Up: %#v", err)
}
err = task.WaitTaskCompletion()
if err != nil {
return fmt.Errorf("Error completing tasks: %#v", err)
}
}
}
return resourceVcdVAppRead(d, meta)
}
func resourceVcdVAppRead(d *schema.ResourceData, meta interface{}) error {
vcdClient := meta.(*VCDClient)
err := vcdClient.OrgVdc.Refresh()
if err != nil {
return fmt.Errorf("Error refreshing vdc: %#v", err)
}
_, err = vcdClient.OrgVdc.FindVAppByName(d.Id())
if err != nil {
log.Printf("[DEBUG] Unable to find vapp. Removing from tfstate")
d.SetId("")
return nil
}
ip, err := getVAppIPAddress(d, meta)
if err != nil {
return err
}
d.Set("ip", ip)
return nil
}
func getVAppIPAddress(d *schema.ResourceData, meta interface{}) (string, error) {
vcdClient := meta.(*VCDClient)
var ip string
err := retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
err := vcdClient.OrgVdc.Refresh()
if err != nil {
return resource.RetryableError(fmt.Errorf("Error refreshing vdc: %#v", err))
}
vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Id())
if err != nil {
return resource.RetryableError(fmt.Errorf("Unable to find vapp."))
}
ip = vapp.VApp.Children.VM[0].NetworkConnectionSection.NetworkConnection.IPAddress
if ip == "" {
return resource.RetryableError(fmt.Errorf("Timeout: VM did not aquire IP address"))
}
return nil
})
return ip, err
}
func resourceVcdVAppDelete(d *schema.ResourceData, meta interface{}) error {
vcdClient := meta.(*VCDClient)
vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Id())
if err != nil {
return fmt.Errorf("error finding vapp: %s", err)
}
if err != nil {
return fmt.Errorf("Error getting VApp status: %#v", err)
}
_ = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
task, err := vapp.Undeploy()
if err != nil {
return resource.RetryableError(fmt.Errorf("Error undeploying: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
task, err := vapp.Delete()
if err != nil {
return resource.RetryableError(fmt.Errorf("Error deleting: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
return err
}