github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_lightsail_instance.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/aws/awserr"
    11  	"github.com/aws/aws-sdk-go/service/lightsail"
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  )
    15  
    16  func resourceAwsLightsailInstance() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceAwsLightsailInstanceCreate,
    19  		Read:   resourceAwsLightsailInstanceRead,
    20  		Delete: resourceAwsLightsailInstanceDelete,
    21  		Importer: &schema.ResourceImporter{
    22  			State: schema.ImportStatePassthrough,
    23  		},
    24  
    25  		Schema: map[string]*schema.Schema{
    26  			"name": {
    27  				Type:     schema.TypeString,
    28  				Required: true,
    29  				ForceNew: true,
    30  			},
    31  			"availability_zone": {
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  				ForceNew: true,
    35  			},
    36  			"blueprint_id": {
    37  				Type:     schema.TypeString,
    38  				Required: true,
    39  				ForceNew: true,
    40  			},
    41  			"bundle_id": {
    42  				Type:     schema.TypeString,
    43  				Required: true,
    44  				ForceNew: true,
    45  			},
    46  
    47  			// Optional attributes
    48  			"key_pair_name": {
    49  				// Not compatible with aws_key_pair (yet)
    50  				// We'll need a new aws_lightsail_key_pair resource
    51  				Type:     schema.TypeString,
    52  				Optional: true,
    53  				ForceNew: true,
    54  				DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
    55  					if old == "LightsailDefaultKeyPair" && new == "" {
    56  						return true
    57  					}
    58  					return false
    59  				},
    60  			},
    61  
    62  			// cannot be retrieved from the API
    63  			"user_data": {
    64  				Type:     schema.TypeString,
    65  				Optional: true,
    66  				ForceNew: true,
    67  			},
    68  
    69  			// additional info returned from the API
    70  			"arn": {
    71  				Type:     schema.TypeString,
    72  				Computed: true,
    73  			},
    74  			"created_at": {
    75  				Type:     schema.TypeString,
    76  				Computed: true,
    77  			},
    78  			"cpu_count": {
    79  				Type:     schema.TypeInt,
    80  				Computed: true,
    81  			},
    82  			"ram_size": {
    83  				Type:     schema.TypeInt,
    84  				Computed: true,
    85  			},
    86  			"ipv6_address": {
    87  				Type:     schema.TypeString,
    88  				Computed: true,
    89  			},
    90  			"is_static_ip": {
    91  				Type:     schema.TypeBool,
    92  				Computed: true,
    93  			},
    94  			"private_ip_address": {
    95  				Type:     schema.TypeString,
    96  				Computed: true,
    97  			},
    98  			"public_ip_address": {
    99  				Type:     schema.TypeString,
   100  				Computed: true,
   101  			},
   102  			"username": {
   103  				Type:     schema.TypeString,
   104  				Computed: true,
   105  			},
   106  		},
   107  	}
   108  }
   109  
   110  func resourceAwsLightsailInstanceCreate(d *schema.ResourceData, meta interface{}) error {
   111  	conn := meta.(*AWSClient).lightsailconn
   112  
   113  	iName := d.Get("name").(string)
   114  
   115  	req := lightsail.CreateInstancesInput{
   116  		AvailabilityZone: aws.String(d.Get("availability_zone").(string)),
   117  		BlueprintId:      aws.String(d.Get("blueprint_id").(string)),
   118  		BundleId:         aws.String(d.Get("bundle_id").(string)),
   119  		InstanceNames:    aws.StringSlice([]string{iName}),
   120  	}
   121  
   122  	if v, ok := d.GetOk("key_pair_name"); ok {
   123  		req.KeyPairName = aws.String(v.(string))
   124  	}
   125  	if v, ok := d.GetOk("user_data"); ok {
   126  		req.UserData = aws.String(v.(string))
   127  	}
   128  
   129  	resp, err := conn.CreateInstances(&req)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	if len(resp.Operations) == 0 {
   135  		return fmt.Errorf("[ERR] No operations found for CreateInstance request")
   136  	}
   137  
   138  	op := resp.Operations[0]
   139  	d.SetId(d.Get("name").(string))
   140  
   141  	stateConf := &resource.StateChangeConf{
   142  		Pending:    []string{"Started"},
   143  		Target:     []string{"Completed", "Succeeded"},
   144  		Refresh:    resourceAwsLightsailOperationRefreshFunc(op.Id, meta),
   145  		Timeout:    10 * time.Minute,
   146  		Delay:      5 * time.Second,
   147  		MinTimeout: 3 * time.Second,
   148  	}
   149  
   150  	_, err = stateConf.WaitForState()
   151  	if err != nil {
   152  		// We don't return an error here because the Create call succeded
   153  		log.Printf("[ERR] Error waiting for instance (%s) to become ready: %s", d.Id(), err)
   154  	}
   155  
   156  	return resourceAwsLightsailInstanceRead(d, meta)
   157  }
   158  
   159  func resourceAwsLightsailInstanceRead(d *schema.ResourceData, meta interface{}) error {
   160  	conn := meta.(*AWSClient).lightsailconn
   161  	resp, err := conn.GetInstance(&lightsail.GetInstanceInput{
   162  		InstanceName: aws.String(d.Id()),
   163  	})
   164  
   165  	if err != nil {
   166  		if awsErr, ok := err.(awserr.Error); ok {
   167  			if awsErr.Code() == "NotFoundException" {
   168  				log.Printf("[WARN] Lightsail Instance (%s) not found, removing from state", d.Id())
   169  				d.SetId("")
   170  				return nil
   171  			}
   172  			return err
   173  		}
   174  		return err
   175  	}
   176  
   177  	if resp == nil {
   178  		log.Printf("[WARN] Lightsail Instance (%s) not found, nil response from server, removing from state", d.Id())
   179  		d.SetId("")
   180  		return nil
   181  	}
   182  
   183  	i := resp.Instance
   184  
   185  	d.Set("availability_zone", i.Location.AvailabilityZone)
   186  	d.Set("blueprint_id", i.BlueprintId)
   187  	d.Set("bundle_id", i.BundleId)
   188  	d.Set("key_pair_name", i.SshKeyName)
   189  	d.Set("name", i.Name)
   190  
   191  	// additional attributes
   192  	d.Set("arn", i.Arn)
   193  	d.Set("username", i.Username)
   194  	d.Set("created_at", i.CreatedAt.Format(time.RFC3339))
   195  	d.Set("cpu_count", i.Hardware.CpuCount)
   196  	d.Set("ram_size", strconv.FormatFloat(*i.Hardware.RamSizeInGb, 'f', 0, 64))
   197  	d.Set("ipv6_address", i.Ipv6Address)
   198  	d.Set("is_static_ip", i.IsStaticIp)
   199  	d.Set("private_ip_address", i.PrivateIpAddress)
   200  	d.Set("public_ip_address", i.PublicIpAddress)
   201  
   202  	return nil
   203  }
   204  
   205  func resourceAwsLightsailInstanceDelete(d *schema.ResourceData, meta interface{}) error {
   206  	conn := meta.(*AWSClient).lightsailconn
   207  	resp, err := conn.DeleteInstance(&lightsail.DeleteInstanceInput{
   208  		InstanceName: aws.String(d.Id()),
   209  	})
   210  
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	op := resp.Operations[0]
   216  
   217  	stateConf := &resource.StateChangeConf{
   218  		Pending:    []string{"Started"},
   219  		Target:     []string{"Completed", "Succeeded"},
   220  		Refresh:    resourceAwsLightsailOperationRefreshFunc(op.Id, meta),
   221  		Timeout:    10 * time.Minute,
   222  		Delay:      5 * time.Second,
   223  		MinTimeout: 3 * time.Second,
   224  	}
   225  
   226  	_, err = stateConf.WaitForState()
   227  	if err != nil {
   228  		return fmt.Errorf(
   229  			"Error waiting for instance (%s) to become destroyed: %s",
   230  			d.Id(), err)
   231  	}
   232  
   233  	d.SetId("")
   234  	return nil
   235  }
   236  
   237  // method to check the status of an Operation, which is returned from
   238  // Create/Delete methods.
   239  // Status's are an aws.OperationStatus enum:
   240  // - NotStarted
   241  // - Started
   242  // - Failed
   243  // - Completed
   244  // - Succeeded (not documented?)
   245  func resourceAwsLightsailOperationRefreshFunc(
   246  	oid *string, meta interface{}) resource.StateRefreshFunc {
   247  	return func() (interface{}, string, error) {
   248  		conn := meta.(*AWSClient).lightsailconn
   249  		log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", *oid)
   250  		o, err := conn.GetOperation(&lightsail.GetOperationInput{
   251  			OperationId: oid,
   252  		})
   253  		if err != nil {
   254  			return o, "FAILED", err
   255  		}
   256  
   257  		if o.Operation == nil {
   258  			return nil, "Failed", fmt.Errorf("[ERR] Error retrieving Operation info for operation (%s)", *oid)
   259  		}
   260  
   261  		log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", *oid, *o.Operation.Status)
   262  		return o, *o.Operation.Status, nil
   263  	}
   264  }