From 2663bb993a8ec48a5c20ea475dccd5b68d877905 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Tue, 1 Jul 2014 10:10:11 -0700 Subject: [PATCH] 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 -}