From bf8931b1aba05cbaa5639ddc9575a447a09341fc Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Thu, 2 Jun 2016 00:50:43 +0100 Subject: [PATCH] provider/aws: Mark Lambda function as gone when it's gone (#6924) * helper/error: Introduce TimeoutError & UnexpectedStateError * provider/aws: Mark Lambda function as gone when it's gone --- .../aws/resource_aws_lambda_permission.go | 23 +++++++++++- helper/resource/error.go | 35 +++++++++++++++++++ helper/resource/state.go | 22 ++++++------ 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/builtin/providers/aws/resource_aws_lambda_permission.go b/builtin/providers/aws/resource_aws_lambda_permission.go index 584176764..ea6a2f0be 100644 --- a/builtin/providers/aws/resource_aws_lambda_permission.go +++ b/builtin/providers/aws/resource_aws_lambda_permission.go @@ -189,7 +189,24 @@ func resourceAwsLambdaPermissionRead(d *schema.ResourceData, meta interface{}) e statement, err = findLambdaPolicyStatementById(&policy, d.Id()) return resource.RetryableError(err) }) + if err != nil { + // Missing whole policy or Lambda function (API error) + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "ResourceNotFoundException" { + log.Printf("[WARN] No Lambda Permission Policy found: %v", input) + d.SetId("") + return nil + } + } + + // Missing permission inside valid policy + if nfErr, ok := err.(*resource.NotFoundError); ok { + log.Printf("[WARN] %s", nfErr) + d.SetId("") + return nil + } + return err } @@ -313,7 +330,11 @@ func findLambdaPolicyStatementById(policy *LambdaPolicy, id string) ( } } - return nil, fmt.Errorf("Failed to find statement %q in Lambda policy:\n%s", id, policy.Statement) + return nil, &resource.NotFoundError{ + LastRequest: id, + LastResponse: policy, + Message: fmt.Sprintf("Failed to find statement %q in Lambda policy:\n%s", id, policy.Statement), + } } func getQualifierFromLambdaAliasOrVersionArn(arn string) (string, error) { diff --git a/helper/resource/error.go b/helper/resource/error.go index 706a40b1c..f13d4c405 100644 --- a/helper/resource/error.go +++ b/helper/resource/error.go @@ -1,5 +1,10 @@ package resource +import ( + "fmt" + "strings" +) + type NotFoundError struct { LastError error LastRequest interface{} @@ -15,3 +20,33 @@ func (e *NotFoundError) Error() string { return "couldn't find resource" } + +// UnexpectedStateError is returned when Refresh returns a state that's neither in Target nor Pending +type UnexpectedStateError struct { + LastError error + State string + ExpectedState []string +} + +func (e *UnexpectedStateError) Error() string { + return fmt.Sprintf( + "unexpected state '%s', wanted target '%s'. last error: %s", + e.State, + strings.Join(e.ExpectedState, ", "), + e.LastError, + ) +} + +// TimeoutError is returned when WaitForState times out +type TimeoutError struct { + LastError error + ExpectedState []string +} + +func (e *TimeoutError) Error() string { + return fmt.Sprintf( + "timeout while waiting for state to become '%s'. last error: %s", + strings.Join(e.ExpectedState, ", "), + e.LastError, + ) +} diff --git a/helper/resource/state.go b/helper/resource/state.go index 9c20b5721..7f8680fed 100644 --- a/helper/resource/state.go +++ b/helper/resource/state.go @@ -1,8 +1,6 @@ package resource import ( - "errors" - "fmt" "log" "math" "time" @@ -109,7 +107,9 @@ func (conf *StateChangeConf) WaitForState() (interface{}, error) { // not finding it for awhile, and if so, report an error. notfoundTick += 1 if notfoundTick > conf.NotFoundChecks { - resulterr = errors.New("couldn't find resource") + resulterr = &NotFoundError{ + LastError: resulterr, + } return } } else { @@ -138,10 +138,11 @@ func (conf *StateChangeConf) WaitForState() (interface{}, error) { } if !found { - resulterr = fmt.Errorf( - "unexpected state '%s', wanted target '%s'", - currentState, - conf.Target) + resulterr = &UnexpectedStateError{ + LastError: resulterr, + State: currentState, + ExpectedState: conf.Target, + } return } } @@ -152,8 +153,9 @@ func (conf *StateChangeConf) WaitForState() (interface{}, error) { case <-doneCh: return result, resulterr case <-time.After(conf.Timeout): - return nil, fmt.Errorf( - "timeout while waiting for state to become '%s'", - conf.Target) + return nil, &TimeoutError{ + LastError: resulterr, + ExpectedState: conf.Target, + } } }