307 lines
8.2 KiB
Go
307 lines
8.2 KiB
Go
|
package opc
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"github.com/hashicorp/terraform/helper/schema"
|
||
|
"github.com/oracle/terraform-provider-compute/sdk/compute"
|
||
|
"log"
|
||
|
)
|
||
|
|
||
|
func resourceInstance() *schema.Resource {
|
||
|
return &schema.Resource{
|
||
|
Create: resourceInstanceCreate,
|
||
|
Read: resourceInstanceRead,
|
||
|
Delete: resourceInstanceDelete,
|
||
|
|
||
|
Schema: map[string]*schema.Schema{
|
||
|
"name": {
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"shape": {
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"imageList": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"label": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"ip": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: false,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"opcId": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: false,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"sshKeys": {
|
||
|
Type: schema.TypeList,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||
|
},
|
||
|
|
||
|
"attributes": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"vcable": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"storage": {
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: map[string]*schema.Schema{
|
||
|
"index": {
|
||
|
Type: schema.TypeInt,
|
||
|
Required: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
"volume": {
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
"name": {
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
|
||
|
"bootOrder": {
|
||
|
Type: schema.TypeList,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
Elem: &schema.Schema{Type: schema.TypeInt},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func getAttrs(d *schema.ResourceData) (*map[string]interface{}, error) {
|
||
|
var attrs map[string]interface{}
|
||
|
|
||
|
attrString := d.Get("attributes").(string)
|
||
|
if attrString == "" {
|
||
|
return &attrs, nil
|
||
|
}
|
||
|
if err := json.Unmarshal([]byte(attrString), &attrs); err != nil {
|
||
|
return &attrs, fmt.Errorf("Cannot parse '%s' as json", attrString)
|
||
|
}
|
||
|
return &attrs, nil
|
||
|
}
|
||
|
|
||
|
func resourceInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
||
|
log.Printf("[DEBUG] Resource data: %#v", d.State())
|
||
|
|
||
|
client := meta.(*OPCClient).Instances()
|
||
|
name := d.Get("name").(string)
|
||
|
shape := d.Get("shape").(string)
|
||
|
imageList := d.Get("imageList").(string)
|
||
|
label := d.Get("label").(string)
|
||
|
storage := getStorageAttachments(d)
|
||
|
sshKeys := getSSHKeys(d)
|
||
|
bootOrder := getBootOrder(d)
|
||
|
|
||
|
attrs, err := getAttrs(d)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] Creating instance with name %s, shape %s, imageList %s, storage %s, bootOrder %s, label %s, sshKeys %s, attrs %#v",
|
||
|
name, shape, imageList, storage, bootOrder, label, sshKeys, attrs)
|
||
|
|
||
|
id, err := client.LaunchInstance(name, label, shape, imageList, storage, bootOrder, sshKeys, *attrs)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("Error creating instance %s: %s", name, err)
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] Waiting for instance %s to come online", id.String())
|
||
|
info, err := client.WaitForInstanceRunning(id, meta.(*OPCClient).MaxRetryTimeout)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("Error waiting for instance %s to come online: %s", id, err)
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] Created instance %s: %#v", id, info)
|
||
|
|
||
|
attachStorage(
|
||
|
&compute.InstanceName{
|
||
|
Name: info.Name,
|
||
|
ID: info.ID,
|
||
|
},
|
||
|
d, meta)
|
||
|
|
||
|
d.SetId(info.Name)
|
||
|
updateInstanceResourceData(d, info)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func attachStorage(name *compute.InstanceName, d *schema.ResourceData, meta interface{}) error {
|
||
|
storageClient := meta.(*OPCClient).StorageAttachments()
|
||
|
storage := d.Get("storage").(*schema.Set)
|
||
|
updatedStorage := schema.NewSet(storage.F, []interface{}{})
|
||
|
|
||
|
for _, i := range storage.List() {
|
||
|
attrs := i.(map[string]interface{})
|
||
|
attachmentInfo, err := storageClient.CreateStorageAttachment(
|
||
|
attrs["index"].(int),
|
||
|
name,
|
||
|
attrs["volume"].(string))
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] Waiting for storage attachment %#v to come online", attachmentInfo)
|
||
|
storageClient.WaitForStorageAttachmentCreated(attachmentInfo.Name, meta.(*OPCClient).MaxRetryTimeout)
|
||
|
log.Printf("[DEBUG] Storage attachment %s: %s-%s created",
|
||
|
attachmentInfo.Name, attachmentInfo.InstanceName, attachmentInfo.StorageVolumeName)
|
||
|
attrs["name"] = attachmentInfo.Name
|
||
|
updatedStorage.Add(attrs)
|
||
|
}
|
||
|
|
||
|
d.Set("storage", updatedStorage)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func getSSHKeys(d *schema.ResourceData) []string {
|
||
|
sshKeys := []string{}
|
||
|
for _, i := range d.Get("sshKeys").([]interface{}) {
|
||
|
sshKeys = append(sshKeys, i.(string))
|
||
|
}
|
||
|
return sshKeys
|
||
|
}
|
||
|
|
||
|
func getBootOrder(d *schema.ResourceData) []int {
|
||
|
bootOrder := []int{}
|
||
|
for _, i := range d.Get("bootOrder").([]interface{}) {
|
||
|
bootOrder = append(bootOrder, i.(int))
|
||
|
}
|
||
|
return bootOrder
|
||
|
}
|
||
|
|
||
|
func getStorageAttachments(d *schema.ResourceData) []compute.LaunchPlanStorageAttachmentSpec {
|
||
|
storageAttachments := []compute.LaunchPlanStorageAttachmentSpec{}
|
||
|
storage := d.Get("storage").(*schema.Set)
|
||
|
for _, i := range storage.List() {
|
||
|
attrs := i.(map[string]interface{})
|
||
|
storageAttachments = append(storageAttachments, compute.LaunchPlanStorageAttachmentSpec{
|
||
|
Index: attrs["index"].(int),
|
||
|
Volume: attrs["volume"].(string),
|
||
|
})
|
||
|
}
|
||
|
return storageAttachments
|
||
|
}
|
||
|
|
||
|
func updateInstanceResourceData(d *schema.ResourceData, info *compute.InstanceInfo) error {
|
||
|
d.Set("name", info.Name)
|
||
|
d.Set("opcId", info.ID)
|
||
|
d.Set("imageList", info.ImageList)
|
||
|
d.Set("bootOrder", info.BootOrder)
|
||
|
d.Set("sshKeys", info.SSHKeys)
|
||
|
d.Set("label", info.Label)
|
||
|
d.Set("ip", info.IPAddress)
|
||
|
d.Set("vcable", info.VCableID)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func resourceInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
||
|
log.Printf("[DEBUG] Resource data: %#v", d.State())
|
||
|
client := meta.(*OPCClient).Instances()
|
||
|
name := d.Get("name").(string)
|
||
|
instanceName := &compute.InstanceName{
|
||
|
Name: name,
|
||
|
ID: d.Get("opcId").(string),
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] Reading state of instance %s", instanceName)
|
||
|
result, err := client.GetInstance(instanceName)
|
||
|
if err != nil {
|
||
|
// Instance doesn't exist
|
||
|
if compute.WasNotFoundError(err) {
|
||
|
log.Printf("[DEBUG] Instance %s not found", instanceName)
|
||
|
d.SetId("")
|
||
|
return nil
|
||
|
}
|
||
|
return fmt.Errorf("Error reading instance %s: %s", instanceName, err)
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] Read state of instance %s: %#v", instanceName, result)
|
||
|
|
||
|
attachments, err := meta.(*OPCClient).StorageAttachments().GetStorageAttachmentsForInstance(instanceName)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("Error reading storage attachments for instance %s: %s", instanceName, err)
|
||
|
}
|
||
|
updateInstanceResourceData(d, result)
|
||
|
updateAttachmentResourceData(d, attachments)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func updateAttachmentResourceData(d *schema.ResourceData, attachments *[]compute.StorageAttachmentInfo) {
|
||
|
attachmentSet := schema.NewSet(d.Get("storage").(*schema.Set).F, []interface{}{})
|
||
|
for _, attachment := range *attachments {
|
||
|
properties := map[string]interface{}{
|
||
|
"index": attachment.Index,
|
||
|
"volume": attachment.StorageVolumeName,
|
||
|
"name": attachment.Name,
|
||
|
}
|
||
|
attachmentSet.Add(properties)
|
||
|
}
|
||
|
d.Set("storage", attachmentSet)
|
||
|
}
|
||
|
|
||
|
func resourceInstanceDelete(d *schema.ResourceData, meta interface{}) error {
|
||
|
log.Printf("[DEBUG] Resource data: %#v", d.State())
|
||
|
client := meta.(*OPCClient).Instances()
|
||
|
name := d.Get("name").(string)
|
||
|
|
||
|
instanceName := &compute.InstanceName{
|
||
|
Name: name,
|
||
|
ID: d.Get("opcId").(string),
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] Deleting instance %s", instanceName)
|
||
|
if err := client.DeleteInstance(instanceName); err != nil {
|
||
|
return fmt.Errorf("Error deleting instance %s: %s", instanceName, err)
|
||
|
}
|
||
|
if err := client.WaitForInstanceDeleted(instanceName, meta.(*OPCClient).MaxRetryTimeout); err != nil {
|
||
|
return fmt.Errorf("Error deleting instance %s: %s", instanceName, err)
|
||
|
}
|
||
|
|
||
|
for _, attachment := range d.Get("storage").(*schema.Set).List() {
|
||
|
name := attachment.(map[string]interface{})["name"].(string)
|
||
|
log.Printf("[DEBUG] Deleting storage attachment %s", name)
|
||
|
client.StorageAttachments().DeleteStorageAttachment(name)
|
||
|
client.StorageAttachments().WaitForStorageAttachmentDeleted(name, meta.(*OPCClient).MaxRetryTimeout)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|