github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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 }