Skip to content

Commit

Permalink
Merge pull request #3032 from mdlavin/recompute-function-version-on-p…
Browse files Browse the repository at this point in the history
…ublish

resource/aws_lambda_function: Recompute Lambda function version and qualified_arn on publish
  • Loading branch information
bflad authored Feb 24, 2018
2 parents 90a2654 + 963dddf commit 093716e
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 5 deletions.
24 changes: 23 additions & 1 deletion aws/resource_aws_lambda_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,21 @@ func resourceAwsLambdaFunction() *schema.Resource {

"tags": tagsSchema(),
},

CustomizeDiff: updateComputedAttributesOnPublish,
}
}

func updateComputedAttributesOnPublish(d *schema.ResourceDiff, meta interface{}) error {
if needsFunctionCodeUpdate(d) {
d.SetNewComputed("last_modified")
publish := d.Get("publish").(bool)
if publish {
d.SetNewComputed("version")
d.SetNewComputed("qualified_arn")
}
}
return nil
}

// resourceAwsLambdaFunction maps to:
Expand Down Expand Up @@ -525,6 +539,14 @@ func resourceAwsLambdaFunctionDelete(d *schema.ResourceData, meta interface{}) e
return nil
}

type resourceDiffer interface {
HasChange(string) bool
}

func needsFunctionCodeUpdate(d resourceDiffer) bool {
return d.HasChange("filename") || d.HasChange("source_code_hash") || d.HasChange("s3_bucket") || d.HasChange("s3_key") || d.HasChange("s3_object_version")
}

// resourceAwsLambdaFunctionUpdate maps to:
// UpdateFunctionCode in the API / SDK
func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) error {
Expand Down Expand Up @@ -672,7 +694,7 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e
d.SetPartial("timeout")
}

if d.HasChange("filename") || d.HasChange("source_code_hash") || d.HasChange("s3_bucket") || d.HasChange("s3_key") || d.HasChange("s3_object_version") {
if needsFunctionCodeUpdate(d) {
codeReq := &lambda.UpdateFunctionCodeInput{
FunctionName: aws.String(d.Id()),
Publish: aws.Bool(d.Get("publish").(bool)),
Expand Down
124 changes: 120 additions & 4 deletions aws/resource_aws_lambda_function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"regexp"
"strings"
"testing"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/lambda"
Expand Down Expand Up @@ -287,7 +288,7 @@ func TestAccAWSLambdaFunction_versioned(t *testing.T) {
CheckDestroy: testAccCheckLambdaFunctionDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLambdaConfigVersioned(funcName, policyName, roleName, sgName),
Config: testAccAWSLambdaConfigVersioned("test-fixtures/lambdatest.zip", funcName, policyName, roleName, sgName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", funcName, &conf),
testAccCheckAwsLambdaFunctionName(&conf, funcName),
Expand All @@ -302,6 +303,58 @@ func TestAccAWSLambdaFunction_versioned(t *testing.T) {
})
}

func TestAccAWSLambdaFunction_versionedUpdate(t *testing.T) {
var conf lambda.GetFunctionOutput

path, zipFile, err := createTempFile("lambda_localUpdate")
if err != nil {
t.Fatal(err)
}
defer os.Remove(path)

rString := acctest.RandString(8)
funcName := fmt.Sprintf("tf_acc_lambda_func_versioned_%s", rString)
policyName := fmt.Sprintf("tf_acc_policy_lambda_func_versioned_%s", rString)
roleName := fmt.Sprintf("tf_acc_role_lambda_func_versioned_%s", rString)
sgName := fmt.Sprintf("tf_acc_sg_lambda_func_versioned_%s", rString)

var timeBeforeUpdate time.Time

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLambdaFunctionDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLambdaConfigVersioned("test-fixtures/lambdatest.zip", funcName, policyName, roleName, sgName),
},
{
PreConfig: func() {
testAccCreateZipFromFiles(map[string]string{"test-fixtures/lambda_func_modified.js": "lambda.js"}, zipFile)
timeBeforeUpdate = time.Now()
},
Config: testAccAWSLambdaConfigVersioned(path, funcName, policyName, roleName, sgName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", funcName, &conf),
testAccCheckAwsLambdaFunctionName(&conf, funcName),
testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+funcName),
resource.TestMatchResourceAttr("aws_lambda_function.lambda_function_test", "version",
regexp.MustCompile("^2$")),
resource.TestMatchResourceAttr("data.template_file.function_version", "rendered",
regexp.MustCompile("^2$")),
resource.TestMatchResourceAttr("aws_lambda_function.lambda_function_test", "qualified_arn",
regexp.MustCompile(":"+funcName+":[0-9]+$")),
resource.TestMatchResourceAttr("data.template_file.qualified_arn", "rendered",
regexp.MustCompile(fmt.Sprintf(":function:%s:2$", funcName))),
func(s *terraform.State) error {
return testAccCheckAttributeIsDateAfter(s, "data.template_file.last_modified", "rendered", timeBeforeUpdate)
},
),
},
},
})
}

func TestAccAWSLambdaFunction_DeadLetterConfig(t *testing.T) {
var conf lambda.GetFunctionOutput

Expand Down Expand Up @@ -572,6 +625,8 @@ func TestAccAWSLambdaFunction_localUpdate(t *testing.T) {
funcName := fmt.Sprintf("tf_acc_lambda_func_local_upd_%s", rString)
roleName := fmt.Sprintf("tf_acc_role_lambda_func_local_upd_%s", rString)

var timeBeforeUpdate time.Time

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Expand All @@ -592,13 +647,17 @@ func TestAccAWSLambdaFunction_localUpdate(t *testing.T) {
{
PreConfig: func() {
testAccCreateZipFromFiles(map[string]string{"test-fixtures/lambda_func_modified.js": "lambda.js"}, zipFile)
timeBeforeUpdate = time.Now()
},
Config: genAWSLambdaFunctionConfig_local(path, roleName, funcName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_local", funcName, &conf),
testAccCheckAwsLambdaFunctionName(&conf, funcName),
testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, funcName),
testAccCheckAwsLambdaSourceCodeHash(&conf, "0tdaP9H9hsk9c2CycSwOG/sa/x5JyAmSYunA/ce99Pg="),
func(s *terraform.State) error {
return testAccCheckAttributeIsDateAfter(s, "data.template_file.last_modified", "rendered", timeBeforeUpdate)
},
),
},
},
Expand Down Expand Up @@ -1050,6 +1109,30 @@ func testAccCheckAwsLambdaSourceCodeHash(function *lambda.GetFunctionOutput, exp
}
}

func testAccCheckAttributeIsDateAfter(s *terraform.State, name string, key string, before time.Time) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Resource %s not found", name)
}

v, ok := rs.Primary.Attributes[key]
if !ok {
return fmt.Errorf("%s: Attribute '%s' not found", name, key)
}

const ISO8601UTC = "2006-01-02T15:04:05Z0700"
timeValue, err := time.Parse(ISO8601UTC, v)
if err != nil {
return err
}

if !before.Before(timeValue) {
return fmt.Errorf("Expected time attribute %s.%s with value %s was not before %s", name, key, v, before.Format(ISO8601UTC))
}

return nil
}

func testAccCreateZipFromFiles(files map[string]string, zipFile *os.File) error {
zipFile.Truncate(0)
zipFile.Seek(0, 0)
Expand Down Expand Up @@ -1387,17 +1470,41 @@ resource "aws_lambda_function" "lambda_function_test" {
`, keyDesc, funcName)
}

func testAccAWSLambdaConfigVersioned(funcName, policyName, roleName, sgName string) string {
func testAccAWSLambdaConfigVersioned(fileName, funcName, policyName, roleName, sgName string) string {
return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+`
resource "aws_lambda_function" "lambda_function_test" {
filename = "test-fixtures/lambdatest.zip"
filename = "%s"
function_name = "%s"
publish = true
role = "${aws_iam_role.iam_for_lambda.arn}"
handler = "exports.example"
runtime = "nodejs4.3"
}
`, funcName)
data "template_file" "function_version" {
template = "$${function_version}"
vars {
function_version = "${aws_lambda_function.lambda_function_test.version}"
}
}
data "template_file" "last_modified" {
template = "$${last_modified}"
vars {
last_modified = "${aws_lambda_function.lambda_function_test.last_modified}"
}
}
data "template_file" "qualified_arn" {
template = "$${qualified_arn}"
vars {
qualified_arn = "${aws_lambda_function.lambda_function_test.qualified_arn}"
}
}
`, fileName, funcName)
}

func testAccAWSLambdaConfigWithTracingConfig(funcName, policyName, roleName, sgName string) string {
Expand Down Expand Up @@ -1723,6 +1830,15 @@ resource "aws_lambda_function" "lambda_function_local" {
handler = "exports.example"
runtime = "nodejs4.3"
}
data "template_file" "last_modified" {
template = "$${last_modified}"
vars {
last_modified = "${aws_lambda_function.lambda_function_local.last_modified}"
}
}
`, roleName, filePath, filePath, funcName)
}

Expand Down

0 comments on commit 093716e

Please sign in to comment.