From 4c9a4ad04145745882119aa1f9cc1b8704d26679 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Fri, 27 Jun 2014 12:47:19 -0400 Subject: [PATCH 01/13] providers/aws: add elb layout, move instance into it's own namespace --- builtin/providers/aws/resource_aws_elb.go | 56 +++++++ .../providers/aws/resource_aws_instance.go | 152 +++++++++++++++++ builtin/providers/aws/resource_provider.go | 4 + builtin/providers/aws/resources.go | 154 +----------------- 4 files changed, 218 insertions(+), 148 deletions(-) create mode 100644 builtin/providers/aws/resource_aws_elb.go create mode 100644 builtin/providers/aws/resource_aws_instance.go diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go new file mode 100644 index 000000000..b5226c6ed --- /dev/null +++ b/builtin/providers/aws/resource_aws_elb.go @@ -0,0 +1,56 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/diff" + "github.com/hashicorp/terraform/terraform" + "github.com/pearkes/goamz/elb" +) + +func resource_aws_elb_create( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + p := meta.(*ResourceProvider) + elbconn := p.elbconn + + // Merge the diff into the state so that we have all the attributes + // properly. + rs := s.MergeDiff(d) + + // Create + + return +} + +func resource_aws_elb_destroy( + s *terraform.ResourceState, + meta interface{}) error { + p := meta.(*ResourceProvider) + elbconn := p.elbconn + + // destroy + + return +} + +func resource_aws_elb_diff( + s *terraform.ResourceState, + c *terraform.ResourceConfig, + meta interface{}) (*terraform.ResourceDiff, error) { + + // diff +} + +func resource_aws_elb_refresh( + s *terraform.ResourceState, + meta interface{}) (*terraform.ResourceState, error) { + p := meta.(*ResourceProvider) + elbconn := p.elbconn + + // retrieve elb health status and describe instances? + + return +} diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go new file mode 100644 index 000000000..b18c42fda --- /dev/null +++ b/builtin/providers/aws/resource_aws_instance.go @@ -0,0 +1,152 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/diff" + "github.com/hashicorp/terraform/terraform" + "github.com/mitchellh/goamz/ec2" +) + +func resource_aws_instance_create( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + p := meta.(*ResourceProvider) + ec2conn := p.ec2conn + + // Merge the diff into the state so that we have all the attributes + // properly. + rs := s.MergeDiff(d) + + // Create the instance + runOpts := &ec2.RunInstances{ + ImageId: rs.Attributes["ami"], + InstanceType: rs.Attributes["instance_type"], + } + log.Printf("[DEBUG] Run configuration: %#v", runOpts) + runResp, err := ec2conn.RunInstances(runOpts) + if err != nil { + return nil, fmt.Errorf("Error launching source instance: %s", err) + } + + instance := &runResp.Instances[0] + log.Printf("[INFO] Instance ID: %s", instance.InstanceId) + + // Store the resulting ID so we can look this up later + rs.ID = instance.InstanceId + + // Wait for the instance to become running so we can get some attributes + // that aren't available until later. + log.Printf( + "[DEBUG] Waiting for instance (%s) to become running", + instance.InstanceId) + instanceRaw, err := WaitForState(&StateChangeConf{ + Pending: []string{"pending"}, + Target: "running", + Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId), + }) + if err != nil { + return rs, fmt.Errorf( + "Error waiting for instance (%s) to become ready: %s", + instance.InstanceId, err) + } + instance = instanceRaw.(*ec2.Instance) + + // Set our attributes + return resource_aws_instance_update_state(rs, instance) +} + +func resource_aws_instance_destroy( + s *terraform.ResourceState, + meta interface{}) error { + p := meta.(*ResourceProvider) + ec2conn := p.ec2conn + + log.Printf("[INFO] Terminating instance: %s", s.ID) + if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil { + return fmt.Errorf("Error terminating instance: %s", err) + } + + log.Printf( + "[DEBUG] Waiting for instance (%s) to become terminated", + s.ID) + _, err := WaitForState(&StateChangeConf{ + Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"}, + Target: "terminated", + Refresh: InstanceStateRefreshFunc(ec2conn, s.ID), + }) + if err != nil { + return fmt.Errorf( + "Error waiting for instance (%s) to terminate: %s", + s.ID, err) + } + + return nil +} + +func resource_aws_instance_diff( + s *terraform.ResourceState, + c *terraform.ResourceConfig, + meta interface{}) (*terraform.ResourceDiff, error) { + b := &diff.ResourceBuilder{ + CreateComputedAttrs: []string{ + "public_dns", + "public_ip", + "private_dns", + "private_ip", + }, + + RequiresNewAttrs: []string{ + "ami", + "availability_zone", + "instance_type", + }, + } + + return b.Diff(s, c) +} + +func resource_aws_instance_refresh( + s *terraform.ResourceState, + meta interface{}) (*terraform.ResourceState, error) { + p := meta.(*ResourceProvider) + ec2conn := p.ec2conn + + resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter()) + if err != nil { + // If the instance was not found, return nil so that we can show + // that the instance is gone. + if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" { + return nil, nil + } + + // Some other error, report it + return s, err + } + + // If nothing was found, then return no state + if len(resp.Reservations) == 0 { + return nil, nil + } + + instance := &resp.Reservations[0].Instances[0] + + // If the instance is terminated, then it is gone + if instance.State.Name == "terminated" { + return nil, nil + } + + return resource_aws_instance_update_state(s, instance) +} + +func resource_aws_instance_update_state( + s *terraform.ResourceState, + instance *ec2.Instance) (*terraform.ResourceState, error) { + s.Attributes["public_dns"] = instance.DNSName + s.Attributes["public_ip"] = instance.PublicIpAddress + s.Attributes["private_dns"] = instance.PrivateDNSName + s.Attributes["private_ip"] = instance.PrivateIpAddress + return s, nil +} diff --git a/builtin/providers/aws/resource_provider.go b/builtin/providers/aws/resource_provider.go index 4b4d3b6bb..850b4d705 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -7,12 +7,14 @@ import ( "github.com/hashicorp/terraform/helper/multierror" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/goamz/ec2" + "github.com/pearkes/goamz/elb" ) type ResourceProvider struct { Config Config ec2conn *ec2.EC2 + elbconn *elb.ELB } func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) { @@ -47,6 +49,8 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { if len(errs) == 0 { log.Println("Initializing EC2 connection") p.ec2conn = ec2.New(auth, region) + log.Println("Initializing ELB connection") + p.elbconn = elb.New(auth, region) } if len(errs) > 0 { diff --git a/builtin/providers/aws/resources.go b/builtin/providers/aws/resources.go index b3a4d7769..77820baed 100644 --- a/builtin/providers/aws/resources.go +++ b/builtin/providers/aws/resources.go @@ -1,13 +1,7 @@ package aws import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/helper/diff" "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/terraform" - "github.com/mitchellh/goamz/ec2" ) // resourceMap is the mapping of resources we support to their basic @@ -23,148 +17,12 @@ func init() { Diff: resource_aws_instance_diff, Refresh: resource_aws_instance_refresh, }, + "aws_elastic_load_balancer": resource.Resource{ + Create: resource_aws_elb_create, + Destroy: resource_aws_elb_destroy, + Diff: resource_aws_elb_diff, + Refresh: resource_aws_elb_refresh, + }, }, } } - -func resource_aws_instance_create( - s *terraform.ResourceState, - d *terraform.ResourceDiff, - meta interface{}) (*terraform.ResourceState, error) { - p := meta.(*ResourceProvider) - ec2conn := p.ec2conn - - // Merge the diff into the state so that we have all the attributes - // properly. - rs := s.MergeDiff(d) - - // Create the instance - runOpts := &ec2.RunInstances{ - ImageId: rs.Attributes["ami"], - InstanceType: rs.Attributes["instance_type"], - } - log.Printf("[DEBUG] Run configuration: %#v", runOpts) - runResp, err := ec2conn.RunInstances(runOpts) - if err != nil { - return nil, fmt.Errorf("Error launching source instance: %s", err) - } - - instance := &runResp.Instances[0] - log.Printf("[INFO] Instance ID: %s", instance.InstanceId) - - // Store the resulting ID so we can look this up later - rs.ID = instance.InstanceId - - // Wait for the instance to become running so we can get some attributes - // that aren't available until later. - log.Printf( - "[DEBUG] Waiting for instance (%s) to become running", - instance.InstanceId) - instanceRaw, err := WaitForState(&StateChangeConf{ - Pending: []string{"pending"}, - Target: "running", - Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId), - }) - if err != nil { - return rs, fmt.Errorf( - "Error waiting for instance (%s) to become ready: %s", - instance.InstanceId, err) - } - instance = instanceRaw.(*ec2.Instance) - - // Set our attributes - return resource_aws_instance_update_state(rs, instance) -} - -func resource_aws_instance_destroy( - s *terraform.ResourceState, - meta interface{}) error { - p := meta.(*ResourceProvider) - ec2conn := p.ec2conn - - log.Printf("[INFO] Terminating instance: %s", s.ID) - if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil { - return fmt.Errorf("Error terminating instance: %s", err) - } - - log.Printf( - "[DEBUG] Waiting for instance (%s) to become terminated", - s.ID) - _, err := WaitForState(&StateChangeConf{ - Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"}, - Target: "terminated", - Refresh: InstanceStateRefreshFunc(ec2conn, s.ID), - }) - if err != nil { - return fmt.Errorf( - "Error waiting for instance (%s) to terminate: %s", - s.ID, err) - } - - return nil -} - -func resource_aws_instance_diff( - s *terraform.ResourceState, - c *terraform.ResourceConfig, - meta interface{}) (*terraform.ResourceDiff, error) { - b := &diff.ResourceBuilder{ - Attrs: map[string]diff.AttrType{ - "ami": diff.AttrTypeCreate, - "availability_zone": diff.AttrTypeCreate, - "instance_type": diff.AttrTypeCreate, - }, - - ComputedAttrs: []string{ - "public_dns", - "public_ip", - "private_dns", - "private_ip", - }, - } - - return b.Diff(s, c) -} - -func resource_aws_instance_refresh( - s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { - p := meta.(*ResourceProvider) - ec2conn := p.ec2conn - - resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter()) - if err != nil { - // If the instance was not found, return nil so that we can show - // that the instance is gone. - if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" { - return nil, nil - } - - // Some other error, report it - return s, err - } - - // If nothing was found, then return no state - if len(resp.Reservations) == 0 { - return nil, nil - } - - instance := &resp.Reservations[0].Instances[0] - - // If the instance is terminated, then it is gone - if instance.State.Name == "terminated" { - return nil, nil - } - - return resource_aws_instance_update_state(s, instance) -} - -func resource_aws_instance_update_state( - s *terraform.ResourceState, - instance *ec2.Instance) (*terraform.ResourceState, error) { - s.Attributes["public_dns"] = instance.DNSName - s.Attributes["public_ip"] = instance.PublicIpAddress - s.Attributes["private_dns"] = instance.PrivateDNSName - s.Attributes["private_ip"] = instance.PrivateIpAddress - return s, nil -} From a6d4acaa15b7cbe4178817b4f996fb5144920b73 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Fri, 27 Jun 2014 12:55:24 -0400 Subject: [PATCH 02/13] providers/aws: use mitchellh/goamz --- builtin/providers/aws/resource_aws_elb.go | 2 +- builtin/providers/aws/resource_provider.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index b5226c6ed..271af776e 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform/helper/diff" "github.com/hashicorp/terraform/terraform" - "github.com/pearkes/goamz/elb" + "github.com/mitchellh/goamz/elb" ) func resource_aws_elb_create( diff --git a/builtin/providers/aws/resource_provider.go b/builtin/providers/aws/resource_provider.go index 850b4d705..b9b011f79 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform/helper/multierror" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/goamz/ec2" - "github.com/pearkes/goamz/elb" + "github.com/mitchellh/goamz/elb" ) type ResourceProvider struct { From eb7c8c07c884ddc17e3cfacaf16aef8024cf4b75 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Mon, 30 Jun 2014 18:03:27 -0700 Subject: [PATCH 03/13] helpers/resource: add wait helper --- helper/resource/wait.go | 100 +++++++++++++++++++++++++++++++++++ helper/resource/wait_test.go | 74 ++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 helper/resource/wait.go create mode 100644 helper/resource/wait_test.go diff --git a/helper/resource/wait.go b/helper/resource/wait.go new file mode 100644 index 000000000..407ce5085 --- /dev/null +++ b/helper/resource/wait.go @@ -0,0 +1,100 @@ +package resource + +import ( + "errors" + "fmt" + "log" + "time" +) + +// StateRefreshFunc is a function type used for StateChangeConf that is +// responsible for refreshing the item being watched for a state change. +// +// It returns three results. `result` is any object that will be returned +// as the final object after waiting for state change. This allows you to +// return the final updated object, for example an EC2 instance after refreshing +// it. +// +// `state` is the latest state of that object. And `err` is any error that +// may have happened while refreshing the state. +type StateRefreshFunc func() (result interface{}, state string, err error) + +// StateChangeConf is the configuration struct used for `WaitForState`. +type StateChangeConf struct { + Pending []string // States that are "allowed" and will continue trying + Refresh StateRefreshFunc // Refreshes the current state + Target string // Target state + Timeout time.Duration // The amount of time to wait before timeout +} + +type waitResult struct { + obj interface{} + err error +} + +// WaitForState watches an object and waits for it to achieve the state +// specified in the configuration using the specified Refresh() func, +// waiting the number of seconds specified in the timeout configuration. +func (conf *StateChangeConf) WaitForState() (i interface{}, err error) { + log.Printf("Waiting for state to become: %s", conf.Target) + + notfoundTick := 0 + + result := make(chan waitResult, 1) + + go func() { + for { + var currentState string + i, currentState, err = conf.Refresh() + if err != nil { + result <- waitResult{nil, err} + return + } + + if i == nil { + // If we didn't find the resource, check if we have been + // not finding it for awhile, and if so, report an error. + notfoundTick += 1 + if notfoundTick > 20 { + result <- waitResult{nil, errors.New("couldn't find resource")} + return + } + } else { + // Reset the counter for when a resource isn't found + notfoundTick = 0 + + if currentState == conf.Target { + result <- waitResult{i, nil} + return + } + + found := false + for _, allowed := range conf.Pending { + if currentState == allowed { + found = true + break + } + } + + if !found { + result <- waitResult{nil, fmt.Errorf("unexpected state '%s', wanted target '%s'", currentState, conf.Target)} + return + } + } + } + + // Wait between refreshes + time.Sleep(2 * time.Second) + }() + + select { + case waitResult := <-result: + err := waitResult.err + i = waitResult.obj + return i, err + case <-time.After(conf.Timeout): + err := fmt.Errorf("timeout while waiting for state to become '%s'", conf.Target) + i = nil + return i, err + } +} diff --git a/helper/resource/wait_test.go b/helper/resource/wait_test.go new file mode 100644 index 000000000..964b1bb7c --- /dev/null +++ b/helper/resource/wait_test.go @@ -0,0 +1,74 @@ +package resource + +import ( + "errors" + "testing" + "time" +) + +type nullObject struct{} + +func FailedStateRefreshFunc() StateRefreshFunc { + return func() (interface{}, string, error) { + return nil, "", errors.New("failed") + } +} + +func TimeoutStateRefreshFunc() StateRefreshFunc { + return func() (interface{}, string, error) { + time.Sleep(100 * time.Second) + return nil, "", errors.New("failed") + } +} + +func SuccessfulStateRefreshFunc() StateRefreshFunc { + return func() (interface{}, string, error) { + return &nullObject{}, "running", nil + } +} + +func TestWaitForState_timeout(t *testing.T) { + conf := &StateChangeConf{ + Pending: []string{"pending", "incomplete"}, + Target: "running", + Refresh: TimeoutStateRefreshFunc(), + Timeout: 1 * time.Millisecond, + } + + _, err := conf.WaitForState() + + if err == nil && err.Error() != "timeout while waiting for state to become 'running'" { + t.Fatalf("err: %s", err) + } + +} + +func TestWaitForState_success(t *testing.T) { + conf := &StateChangeConf{ + Pending: []string{"pending", "incomplete"}, + Target: "running", + Refresh: SuccessfulStateRefreshFunc(), + Timeout: 200 * time.Second, + } + + _, err := conf.WaitForState() + + if err != nil { + t.Fatalf("err: %s", err) + } +} + +func TestWaitForState_failure(t *testing.T) { + conf := &StateChangeConf{ + Pending: []string{"pending", "incomplete"}, + Target: "running", + Refresh: FailedStateRefreshFunc(), + Timeout: 200 * time.Second, + } + + _, err := conf.WaitForState() + + if err == nil && err.Error() != "failed" { + t.Fatalf("err: %s", err) + } +} From 5ae69778a1521266ee14e78cd141094cd4da42df Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Mon, 30 Jun 2014 18:18:36 -0700 Subject: [PATCH 04/13] helper/resource: wait should return obj --- helper/resource/wait_test.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/helper/resource/wait_test.go b/helper/resource/wait_test.go index 964b1bb7c..f12c037a5 100644 --- a/helper/resource/wait_test.go +++ b/helper/resource/wait_test.go @@ -35,12 +35,16 @@ func TestWaitForState_timeout(t *testing.T) { Timeout: 1 * time.Millisecond, } - _, err := conf.WaitForState() + obj, err := conf.WaitForState() if err == nil && err.Error() != "timeout while waiting for state to become 'running'" { t.Fatalf("err: %s", err) } + if obj != nil { + t.Fatalf("should not return obj") + } + } func TestWaitForState_success(t *testing.T) { @@ -51,11 +55,16 @@ func TestWaitForState_success(t *testing.T) { Timeout: 200 * time.Second, } - _, err := conf.WaitForState() + obj, err := conf.WaitForState() if err != nil { t.Fatalf("err: %s", err) } + + if obj == nil { + t.Fatalf("should return obj") + } + } func TestWaitForState_failure(t *testing.T) { @@ -66,9 +75,13 @@ func TestWaitForState_failure(t *testing.T) { Timeout: 200 * time.Second, } - _, err := conf.WaitForState() + obj, err := conf.WaitForState() if err == nil && err.Error() != "failed" { t.Fatalf("err: %s", err) } + + if obj != nil { + t.Fatalf("should not return obj") + } } From 2663bb993a8ec48a5c20ea475dccd5b68d877905 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Tue, 1 Jul 2014 10:10:11 -0700 Subject: [PATCH 05/13] providers/aws: use wait helper --- .../providers/aws/resource_aws_instance.go | 46 +++++++- builtin/providers/aws/state.go | 104 ------------------ 2 files changed, 42 insertions(+), 108 deletions(-) delete mode 100644 builtin/providers/aws/state.go diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index b18c42fda..1bd18acec 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -3,8 +3,10 @@ package aws import ( "fmt" "log" + "time" "github.com/hashicorp/terraform/helper/diff" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/goamz/ec2" ) @@ -42,16 +44,22 @@ func resource_aws_instance_create( log.Printf( "[DEBUG] Waiting for instance (%s) to become running", instance.InstanceId) - instanceRaw, err := WaitForState(&StateChangeConf{ + + stateConf := &resource.StateChangeConf{ Pending: []string{"pending"}, Target: "running", Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId), - }) + Timeout: 10 * time.Minute, + } + + instanceRaw, err := stateConf.WaitForState() + if err != nil { return rs, fmt.Errorf( "Error waiting for instance (%s) to become ready: %s", instance.InstanceId, err) } + instance = instanceRaw.(*ec2.Instance) // Set our attributes @@ -72,11 +80,15 @@ func resource_aws_instance_destroy( log.Printf( "[DEBUG] Waiting for instance (%s) to become terminated", s.ID) - _, err := WaitForState(&StateChangeConf{ + + stateConf := &resource.StateChangeConf{ Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"}, Target: "terminated", Refresh: InstanceStateRefreshFunc(ec2conn, s.ID), - }) + } + + _, err := stateConf.WaitForState() + if err != nil { return fmt.Errorf( "Error waiting for instance (%s) to terminate: %s", @@ -150,3 +162,29 @@ func resource_aws_instance_update_state( s.Attributes["private_ip"] = instance.PrivateIpAddress return s, nil } + +// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// an EC2 instance. +func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter()) + if err != nil { + if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" { + // Set this to nil as if we didn't find anything. + resp = nil + } else { + log.Printf("Error on InstanceStateRefresh: %s", err) + return nil, "", err + } + } + + if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 { + // Sometimes AWS just has consistency issues and doesn't see + // our instance yet. Return an empty state. + return nil, "", nil + } + + i := &resp.Reservations[0].Instances[0] + return i, i.State.Name, nil + } +} diff --git a/builtin/providers/aws/state.go b/builtin/providers/aws/state.go deleted file mode 100644 index cf076ddf4..000000000 --- a/builtin/providers/aws/state.go +++ /dev/null @@ -1,104 +0,0 @@ -package aws - -import ( - "errors" - "fmt" - "log" - "time" - - "github.com/mitchellh/goamz/ec2" -) - -// StateRefreshFunc is a function type used for StateChangeConf that is -// responsible for refreshing the item being watched for a state change. -// -// It returns three results. `result` is any object that will be returned -// as the final object after waiting for state change. This allows you to -// return the final updated object, for example an EC2 instance after refreshing -// it. -// -// `state` is the latest state of that object. And `err` is any error that -// may have happened while refreshing the state. -type StateRefreshFunc func() (result interface{}, state string, err error) - -// StateChangeConf is the configuration struct used for `WaitForState`. -type StateChangeConf struct { - Pending []string - Refresh StateRefreshFunc - Target string -} - -// InstanceStateRefreshFunc returns a StateRefreshFunc that is used to watch -// an EC2 instance. -func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) StateRefreshFunc { - return func() (interface{}, string, error) { - resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter()) - if err != nil { - if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" { - // Set this to nil as if we didn't find anything. - resp = nil - } else { - log.Printf("Error on InstanceStateRefresh: %s", err) - return nil, "", err - } - } - - if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 { - // Sometimes AWS just has consistency issues and doesn't see - // our instance yet. Return an empty state. - return nil, "", nil - } - - i := &resp.Reservations[0].Instances[0] - return i, i.State.Name, nil - } -} - -// WaitForState watches an object and waits for it to achieve a certain -// state. -func WaitForState(conf *StateChangeConf) (i interface{}, err error) { - log.Printf("Waiting for state to become: %s", conf.Target) - - notfoundTick := 0 - - for { - var currentState string - i, currentState, err = conf.Refresh() - if err != nil { - return - } - - if i == nil { - // If we didn't find the resource, check if we have been - // not finding it for awhile, and if so, report an error. - notfoundTick += 1 - if notfoundTick > 20 { - return nil, errors.New("couldn't find resource") - } - } else { - // Reset the counter for when a resource isn't found - notfoundTick = 0 - - if currentState == conf.Target { - return - } - - found := false - for _, allowed := range conf.Pending { - if currentState == allowed { - found = true - break - } - } - - if !found { - fmt.Errorf("unexpected state '%s', wanted target '%s'", currentState, conf.Target) - return - } - } - - time.Sleep(2 * time.Second) - } - - return -} From fd4eeac7dca63012d4b979faaad7eba5360160cd Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Tue, 1 Jul 2014 10:11:11 -0700 Subject: [PATCH 06/13] providers/aws: timeout in state change conf --- builtin/providers/aws/resource_aws_instance.go | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index 1bd18acec..a1c9e3858 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -85,6 +85,7 @@ func resource_aws_instance_destroy( Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"}, Target: "terminated", Refresh: InstanceStateRefreshFunc(ec2conn, s.ID), + Timeout: 10 * time.Minute, } _, err := stateConf.WaitForState() From a2815e50eb3424d95b47106bdd843b974f4ac938 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Tue, 1 Jul 2014 11:56:04 -0700 Subject: [PATCH 07/13] providers/aws: first pass at elb support --- builtin/providers/aws/resource_aws_elb.go | 80 ++++++++++++++++++----- builtin/providers/aws/resources.go | 2 +- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 271af776e..4a4364e6b 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -20,20 +20,63 @@ func resource_aws_elb_create( // properly. rs := s.MergeDiff(d) - // Create + // The name specified for the ELB. This is also our unique ID + // we save to state if the creation is succesful (amazon verifies + // it is unique) + elbName := rs.Attributes["name"] - return + // Provision the elb + elbOpts := &elb.CreateLoadBalancer{ + LoadBalancerName: elbName, + } + log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) + + _, err := elbconn.CreateLoadBalancer(elbOpts) + if err != nil { + return nil, fmt.Errorf("Error creating ELB: %s", err) + } + + // Assign the elb's unique identifer for use later + rs.ID = elbName + log.Printf("[INFO] ELB ID: %s", elbName) + + // Filter by our name + describeElbOpts := &elb.DescribeLoadBalancer{ + Names: []string{elbName}, + } + + // Retrieve the ELB properties for updating the state + describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts) + if err != nil { + return nil, fmt.Errorf("Error retrieving ELB: %s", err) + } + + // Verify AWS returned our ELB + if len(describeResp.LoadBalancers) != 1 || + describeResp.LoadBalancers[0].LoadBalancerName != elbName { + if err != nil { + return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers) + } + } + loadBalancer := describeResp.LoadBalancers[0] + + return resource_aws_elb_update_state(rs, &loadBalancer) } func resource_aws_elb_destroy( s *terraform.ResourceState, meta interface{}) error { - p := meta.(*ResourceProvider) - elbconn := p.elbconn - // destroy + return nil +} - return +func resource_aws_elb_refresh( + s *terraform.ResourceState, + meta interface{}) (*terraform.ResourceState, error) { + + loadBalancer := &elb.LoadBalancer{} + + return resource_aws_elb_update_state(s, loadBalancer) } func resource_aws_elb_diff( @@ -41,16 +84,23 @@ func resource_aws_elb_diff( c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { - // diff + b := &diff.ResourceBuilder{ + CreateComputedAttrs: []string{ + "dns_name", + }, + + RequiresNewAttrs: []string{ + "name", + }, + } + + return b.Diff(s, c) } -func resource_aws_elb_refresh( +func resource_aws_elb_update_state( s *terraform.ResourceState, - meta interface{}) (*terraform.ResourceState, error) { - p := meta.(*ResourceProvider) - elbconn := p.elbconn - - // retrieve elb health status and describe instances? - - return + balancer *elb.LoadBalancer) (*terraform.ResourceState, error) { + s.Attributes["name"] = balancer.LoadBalancerName + s.Attributes["dns_name"] = balancer.DNSName + return s, nil } diff --git a/builtin/providers/aws/resources.go b/builtin/providers/aws/resources.go index 77820baed..aff7a581a 100644 --- a/builtin/providers/aws/resources.go +++ b/builtin/providers/aws/resources.go @@ -17,7 +17,7 @@ func init() { Diff: resource_aws_instance_diff, Refresh: resource_aws_instance_refresh, }, - "aws_elastic_load_balancer": resource.Resource{ + "aws_elb": resource.Resource{ Create: resource_aws_elb_create, Destroy: resource_aws_elb_destroy, Diff: resource_aws_elb_diff, From 5d25de017cf1e70d441cdf5d84185d8b8cc960be Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 1 Jul 2014 16:22:24 -0700 Subject: [PATCH 08/13] providers/aws: fix for latest ResourceBuilder API --- builtin/providers/aws/resource_aws_elb.go | 8 ++++---- builtin/providers/aws/resource_aws_instance.go | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 4a4364e6b..87894873d 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -85,12 +85,12 @@ func resource_aws_elb_diff( meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ - CreateComputedAttrs: []string{ - "dns_name", + Attrs: map[string]diff.AttrType{ + "name": diff.AttrTypeCreate, }, - RequiresNewAttrs: []string{ - "name", + ComputedAttrs: []string{ + "dns_name", }, } diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index a1c9e3858..cf40918a0 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -104,18 +104,18 @@ func resource_aws_instance_diff( c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { b := &diff.ResourceBuilder{ - CreateComputedAttrs: []string{ + Attrs: map[string]diff.AttrType{ + "ami": diff.AttrTypeCreate, + "availability_zone": diff.AttrTypeCreate, + "instance_type": diff.AttrTypeCreate, + }, + + ComputedAttrs: []string{ "public_dns", "public_ip", "private_dns", "private_ip", }, - - RequiresNewAttrs: []string{ - "ami", - "availability_zone", - "instance_type", - }, } return b.Diff(s, c) From 339355b2f1ed1b0e9b0e91a4bb790c17edfe0a62 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Wed, 2 Jul 2014 12:03:58 -0700 Subject: [PATCH 09/13] providers/aws: elb hack --- builtin/providers/aws/resource_aws_elb.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 87894873d..d82865fd7 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -24,11 +24,26 @@ func resource_aws_elb_create( // we save to state if the creation is succesful (amazon verifies // it is unique) elbName := rs.Attributes["name"] + // v := flatmap.Expand(rs.Attributes, "listener") + // log.Println(v) // Provision the elb elbOpts := &elb.CreateLoadBalancer{ LoadBalancerName: elbName, + Listeners: []elb.Listener{ + elb.Listener{ + InstancePort: 8000, + InstanceProtocol: "http", + LoadBalancerPort: 80, + Protocol: "http", + }, + }, + AvailZone: []string{ + "us-east-1a", + "us-east-1b", + }, } + log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) _, err := elbconn.CreateLoadBalancer(elbOpts) @@ -40,7 +55,6 @@ func resource_aws_elb_create( rs.ID = elbName log.Printf("[INFO] ELB ID: %s", elbName) - // Filter by our name describeElbOpts := &elb.DescribeLoadBalancer{ Names: []string{elbName}, } @@ -86,7 +100,8 @@ func resource_aws_elb_diff( b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ - "name": diff.AttrTypeCreate, + "name": diff.AttrTypeCreate, + "availability_zone": diff.AttrTypeCreate, }, ComputedAttrs: []string{ From 1b6faa0eb9379cb3474a57c92e866644accbce69 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Wed, 2 Jul 2014 15:55:28 -0700 Subject: [PATCH 10/13] providers/aws: helper for expanding listeners --- builtin/providers/aws/resource_aws_elb.go | 18 +++++------ builtin/providers/aws/structure.go | 28 ++++++++++++++++ builtin/providers/aws/structure_test.go | 39 +++++++++++++++++++++++ 3 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 builtin/providers/aws/structure.go create mode 100644 builtin/providers/aws/structure_test.go diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index d82865fd7..3128f8a76 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -4,6 +4,7 @@ import ( "fmt" "log" + "github.com/hashicorp/terraform/flatmap" "github.com/hashicorp/terraform/helper/diff" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/goamz/elb" @@ -24,20 +25,15 @@ func resource_aws_elb_create( // we save to state if the creation is succesful (amazon verifies // it is unique) elbName := rs.Attributes["name"] - // v := flatmap.Expand(rs.Attributes, "listener") - // log.Println(v) + + // Expand the "listener" array to goamz compat []elb.Listener + v := flatmap.Expand(rs.Attributes, "listener").([]interface{}) + listeners := expandListeners(v) // Provision the elb elbOpts := &elb.CreateLoadBalancer{ LoadBalancerName: elbName, - Listeners: []elb.Listener{ - elb.Listener{ - InstancePort: 8000, - InstanceProtocol: "http", - LoadBalancerPort: 80, - Protocol: "http", - }, - }, + Listeners: listeners, AvailZone: []string{ "us-east-1a", "us-east-1b", @@ -102,10 +98,12 @@ func resource_aws_elb_diff( Attrs: map[string]diff.AttrType{ "name": diff.AttrTypeCreate, "availability_zone": diff.AttrTypeCreate, + "listener": diff.AttrTypeCreate, }, ComputedAttrs: []string{ "dns_name", + "instances", }, } diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go new file mode 100644 index 000000000..44ab80519 --- /dev/null +++ b/builtin/providers/aws/structure.go @@ -0,0 +1,28 @@ +package aws + +import ( + "github.com/mitchellh/goamz/elb" +) + +// Takes the result of flatmap.Expand for an array of listeners and +// returns ELB API compatible objects +func expandListeners(configured []interface{}) []elb.Listener { + listeners := make([]elb.Listener, 0, len(configured)) + + // Loop over our configured listeners and create + // an array of goamz compatabile objects + for _, listener := range configured { + newL := listener.(map[string]interface{}) + + l := elb.Listener{ + InstancePort: int64(newL["instance_port"].(int)), + InstanceProtocol: newL["instance_protocol"].(string), + LoadBalancerPort: int64(newL["lb_port"].(int)), + Protocol: newL["lb_protocol"].(string), + } + + listeners = append(listeners, l) + } + + return listeners +} diff --git a/builtin/providers/aws/structure_test.go b/builtin/providers/aws/structure_test.go new file mode 100644 index 000000000..28283a676 --- /dev/null +++ b/builtin/providers/aws/structure_test.go @@ -0,0 +1,39 @@ +package aws + +import ( + "reflect" + "testing" + + "github.com/hashicorp/terraform/flatmap" + "github.com/mitchellh/goamz/elb" +) + +// Returns test configuration +func testConf() map[string]string { + return map[string]string{ + "listener.#": "1", + "listener.0.lb_port": "80", + "listener.0.lb_protocol": "http", + "listener.0.instance_port": "8000", + "listener.0.instance_protocol": "http", + } +} + +func Test_expandListeners(t *testing.T) { + expanded := flatmap.Expand(testConf(), "listener").([]interface{}) + listeners := expandListeners(expanded) + expected := elb.Listener{ + InstancePort: 8000, + LoadBalancerPort: 80, + InstanceProtocol: "http", + Protocol: "http", + } + + if !reflect.DeepEqual(listeners[0], expected) { + t.Fatalf( + "Got:\n\n%#v\n\nExpected:\n\n%#v\n", + listeners[0], + expected) + } + +} From 0f64ff93877a747e7a6db25209c62db2ca904497 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Wed, 2 Jul 2014 16:57:57 -0700 Subject: [PATCH 11/13] providers/aws: availability_zones and expandList --- builtin/providers/aws/resource_aws_elb.go | 10 +++++----- builtin/providers/aws/structure.go | 10 ++++++++++ builtin/providers/aws/structure_test.go | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index 3128f8a76..e7c2caba5 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -30,14 +30,14 @@ func resource_aws_elb_create( v := flatmap.Expand(rs.Attributes, "listener").([]interface{}) listeners := expandListeners(v) + v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{}) + zones := expandStringList(v) + // Provision the elb elbOpts := &elb.CreateLoadBalancer{ LoadBalancerName: elbName, Listeners: listeners, - AvailZone: []string{ - "us-east-1a", - "us-east-1b", - }, + AvailZone: zones, } log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) @@ -103,7 +103,7 @@ func resource_aws_elb_diff( ComputedAttrs: []string{ "dns_name", - "instances", + "instances ", }, } diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 44ab80519..0f2b4800a 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -26,3 +26,13 @@ func expandListeners(configured []interface{}) []elb.Listener { return listeners } + +// Takes the result of flatmap.Expand for an array of strings +// and returns a []string +func expandStringList(configured []interface{}) []string { + vs := make([]string, 0, len(configured)) + for _, v := range configured { + vs = append(vs, v.(string)) + } + return vs +} diff --git a/builtin/providers/aws/structure_test.go b/builtin/providers/aws/structure_test.go index 28283a676..d534e4c24 100644 --- a/builtin/providers/aws/structure_test.go +++ b/builtin/providers/aws/structure_test.go @@ -16,6 +16,9 @@ func testConf() map[string]string { "listener.0.lb_protocol": "http", "listener.0.instance_port": "8000", "listener.0.instance_protocol": "http", + "availability_zones.#": "2", + "availability_zones.0": "us-east-1a", + "availability_zones.1": "us-east-1b", } } @@ -37,3 +40,20 @@ func Test_expandListeners(t *testing.T) { } } + +func Test_expandStringList(t *testing.T) { + expanded := flatmap.Expand(testConf(), "availability_zones").([]interface{}) + stringList := expandStringList(expanded) + expected := []string{ + "us-east-1a", + "us-east-1b", + } + + if !reflect.DeepEqual(stringList, expected) { + t.Fatalf( + "Got:\n\n%#v\n\nExpected:\n\n%#v\n", + stringList, + expected) + } + +} From d484ebadcd867af54093000f2f8a33f18a6b835e Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Wed, 2 Jul 2014 22:40:55 -0700 Subject: [PATCH 12/13] providers/aws: update --- builtin/providers/aws/resource_aws_elb.go | 34 ++++++++++++++++++++++- builtin/providers/aws/resources.go | 1 + 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index e7c2caba5..b77cb6c12 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -68,11 +68,43 @@ func resource_aws_elb_create( return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers) } } + loadBalancer := describeResp.LoadBalancers[0] + // If we have any instances, we need to register them + v = flatmap.Expand(rs.Attributes, "instances").([]interface{}) + instances := expandStringList(v) + + if len(instances) > 0 { + registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{ + LoadBalancerName: elbName, + Instances: instances, + } + + registerResp, err := elbconn.RegisterInstancesWithLoadBalancer(registerInstancesOpts) + } + return resource_aws_elb_update_state(rs, &loadBalancer) } +func resource_aws_elb_update( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + // p := meta.(*ResourceProvider) + // elbconn := p.elbconn + + // Merge the diff into the state so that we have all the attributes + // properly. + rs := s.MergeDiff(d) + + log.Println(rs) + + rs.Attributes + + return nil, nil +} + func resource_aws_elb_destroy( s *terraform.ResourceState, meta interface{}) error { @@ -99,11 +131,11 @@ func resource_aws_elb_diff( "name": diff.AttrTypeCreate, "availability_zone": diff.AttrTypeCreate, "listener": diff.AttrTypeCreate, + "instances": diff.AttrTypeUpdate, }, ComputedAttrs: []string{ "dns_name", - "instances ", }, } diff --git a/builtin/providers/aws/resources.go b/builtin/providers/aws/resources.go index aff7a581a..2703f024c 100644 --- a/builtin/providers/aws/resources.go +++ b/builtin/providers/aws/resources.go @@ -19,6 +19,7 @@ func init() { }, "aws_elb": resource.Resource{ Create: resource_aws_elb_create, + Update: resource_aws_elb_update, Destroy: resource_aws_elb_destroy, Diff: resource_aws_elb_diff, Refresh: resource_aws_elb_refresh, From 69acd6272a59211acf0f62a35ef4e261a19f704c Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Fri, 4 Jul 2014 19:03:01 -0400 Subject: [PATCH 13/13] providers/aws: elb instance registration --- builtin/providers/aws/resource_aws_elb.go | 52 +++++++++---------- .../providers/aws/resource_aws_instance.go | 2 + 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index b77cb6c12..a306feefb 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -51,26 +51,6 @@ func resource_aws_elb_create( rs.ID = elbName log.Printf("[INFO] ELB ID: %s", elbName) - describeElbOpts := &elb.DescribeLoadBalancer{ - Names: []string{elbName}, - } - - // Retrieve the ELB properties for updating the state - describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts) - if err != nil { - return nil, fmt.Errorf("Error retrieving ELB: %s", err) - } - - // Verify AWS returned our ELB - if len(describeResp.LoadBalancers) != 1 || - describeResp.LoadBalancers[0].LoadBalancerName != elbName { - if err != nil { - return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers) - } - } - - loadBalancer := describeResp.LoadBalancers[0] - // If we have any instances, we need to register them v = flatmap.Expand(rs.Attributes, "instances").([]interface{}) instances := expandStringList(v) @@ -81,7 +61,31 @@ func resource_aws_elb_create( Instances: instances, } - registerResp, err := elbconn.RegisterInstancesWithLoadBalancer(registerInstancesOpts) + _, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts) + + if err != nil { + return nil, fmt.Errorf("Failure registering instances: %s", err) + } + } + + describeElbOpts := &elb.DescribeLoadBalancer{ + Names: []string{elbName}, + } + + // Retrieve the ELB properties for updating the state + describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts) + if err != nil { + return nil, fmt.Errorf("Error retrieving ELB: %s", err) + } + + loadBalancer := describeResp.LoadBalancers[0] + + // Verify AWS returned our ELB + if len(describeResp.LoadBalancers) != 1 || + describeResp.LoadBalancers[0].LoadBalancerName != elbName { + if err != nil { + return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers) + } } return resource_aws_elb_update_state(rs, &loadBalancer) @@ -96,11 +100,7 @@ func resource_aws_elb_update( // Merge the diff into the state so that we have all the attributes // properly. - rs := s.MergeDiff(d) - - log.Println(rs) - - rs.Attributes + // rs := s.MergeDiff(d) return nil, nil } diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index cf40918a0..af5acfb22 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -115,6 +115,7 @@ func resource_aws_instance_diff( "public_ip", "private_dns", "private_ip", + "instance_id", }, } @@ -161,6 +162,7 @@ func resource_aws_instance_update_state( s.Attributes["public_ip"] = instance.PublicIpAddress s.Attributes["private_dns"] = instance.PrivateDNSName s.Attributes["private_ip"] = instance.PrivateIpAddress + s.Attributes["instance_id"] = instance.InstanceId return s, nil }