Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lambda_function: add layers support to resource and data source #7126

Merged
merged 1 commit into from
Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions aws/data_source_aws_lambda_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ func dataSourceAwsLambdaFunction() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"layers": {
Type: schema.TypeList,
Computed: true,
MaxItems: 5,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"memory_size": {
Type: schema.TypeInt,
Computed: true,
Expand Down
47 changes: 47 additions & 0 deletions aws/data_source_aws_lambda_function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,29 @@ func TestAccDataSourceAWSLambdaFunction_alias(t *testing.T) {
})
}

func TestAccDataSourceAWSLambdaFunction_layers(t *testing.T) {
rString := acctest.RandString(7)
roleName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-role-%s", rString)
policyName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-policy-%s", rString)
sgName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-sg-%s", rString)
funcName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-func-%s", rString)
layerName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-layer-%s", rString)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAWSLambdaFunctionConfigLayers(roleName, policyName, sgName, funcName, layerName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "arn"),
resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "layers.#", "1"),
),
},
},
})
}

func TestAccDataSourceAWSLambdaFunction_vpc(t *testing.T) {
rString := acctest.RandString(7)
roleName := fmt.Sprintf("tf-acctest-d-lambda-function-vpc-role-%s", rString)
Expand Down Expand Up @@ -293,6 +316,30 @@ data "aws_lambda_function" "acctest" {
`, funcName, funcName)
}

func testAccDataSourceAWSLambdaFunctionConfigLayers(roleName, policyName, sgName, funcName, layerName string) string {
return fmt.Sprintf(testAccDataSourceAWSLambdaFunctionConfigBase(roleName, policyName, sgName)+`
resource "aws_lambda_layer_version" "acctest_create" {
filename = "test-fixtures/lambdatest.zip"
layer_name = "%s"
compatible_runtimes = ["nodejs8.10"]
}

resource "aws_lambda_function" "acctest_create" {
function_name = "%s"
description = "%s"
filename = "test-fixtures/lambdatest.zip"
role = "${aws_iam_role.lambda.arn}"
handler = "exports.example"
runtime = "nodejs8.10"
layers = ["${aws_lambda_layer_version.acctest_create.layer_arn}"]
}

data "aws_lambda_function" "acctest" {
function_name = "${aws_lambda_function.acctest_create.function_name}"
}
`, layerName, funcName, funcName)
}

func testAccDataSourceAWSLambdaFunctionConfigVPC(roleName, policyName, sgName, funcName string) string {
return fmt.Sprintf(testAccDataSourceAWSLambdaFunctionConfigBase(roleName, policyName, sgName)+`
resource "aws_lambda_function" "acctest_create" {
Expand Down
24 changes: 24 additions & 0 deletions aws/resource_aws_lambda_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ func resourceAwsLambdaFunction() *schema.Resource {
Type: schema.TypeString,
Required: true,
},
"layers": {
Type: schema.TypeList,
Optional: true,
MaxItems: 5,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateArn,
},
},
"memory_size": {
Type: schema.TypeInt,
Optional: true,
Expand Down Expand Up @@ -317,6 +326,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e
Publish: aws.Bool(d.Get("publish").(bool)),
}

if v, ok := d.GetOk("layers"); ok && len(v.([]interface{})) > 0 {
params.Layers = expandStringList(v.([]interface{}))
}

if v, ok := d.GetOk("dead_letter_config"); ok {
dlcMaps := v.([]interface{})
if len(dlcMaps) == 1 { // Schema guarantees either 0 or 1
Expand Down Expand Up @@ -510,6 +523,12 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err
d.Set("source_code_hash", function.CodeSha256)
d.Set("source_code_size", function.CodeSize)

layers := flattenLambdaLayers(function.Layers)
log.Printf("[INFO] Setting Lambda %s Layers %#v from API", d.Id(), layers)
if err := d.Set("layers", layers); err != nil {
return fmt.Errorf("Error setting layers for Lambda Function (%s): %s", d.Id(), err)
}

config := flattenLambdaVpcConfigResponse(function.VpcConfig)
log.Printf("[INFO] Setting Lambda %s VPC config %#v from API", d.Id(), config)
if err := d.Set("vpc_config", config); err != nil {
Expand Down Expand Up @@ -664,6 +683,11 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e
configReq.KMSKeyArn = aws.String(d.Get("kms_key_arn").(string))
configUpdate = true
}
if d.HasChange("layers") {
layers := d.Get("layers").([]interface{})
configReq.Layers = expandStringList(layers)
configUpdate = true
}
if d.HasChange("dead_letter_config") {
dlcMaps := d.Get("dead_letter_config").([]interface{})
configReq.DeadLetterConfig = &lambda.DeadLetterConfig{
Expand Down
116 changes: 116 additions & 0 deletions aws/resource_aws_lambda_function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,75 @@ func TestAccAWSLambdaFunction_tracingConfig(t *testing.T) {
})
}

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

rString := acctest.RandString(8)
funcName := fmt.Sprintf("tf_acc_lambda_func_layer_%s", rString)
layerName := fmt.Sprintf("tf_acc_layer_lambda_func_layer_%s", rString)
policyName := fmt.Sprintf("tf_acc_policy_lambda_func_layer_%s", rString)
roleName := fmt.Sprintf("tf_acc_role_lambda_func_layer_%s", rString)
sgName := fmt.Sprintf("tf_acc_sg_lambda_func_layer_%s", rString)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLambdaFunctionDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLambdaConfigWithLayers(funcName, layerName, policyName, roleName, sgName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", funcName, &conf),
testAccCheckAwsLambdaFunctionName(&conf, funcName),
testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+funcName),
testAccCheckAWSLambdaFunctionVersion(&conf, "$LATEST"),
resource.TestCheckResourceAttr("aws_lambda_function.lambda_function_test", "layers.#", "1"),
),
},
},
})
}

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

rString := acctest.RandString(8)
funcName := fmt.Sprintf("tf_acc_lambda_func_layer_%s", rString)
layerName := fmt.Sprintf("tf_acc_lambda_layer_%s", rString)
layer2Name := fmt.Sprintf("tf_acc_lambda_layer2_%s", rString)
policyName := fmt.Sprintf("tf_acc_policy_lambda_func_vpc_%s", rString)
roleName := fmt.Sprintf("tf_acc_role_lambda_func_vpc_%s", rString)
sgName := fmt.Sprintf("tf_acc_sg_lambda_func_vpc_%s", rString)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLambdaFunctionDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLambdaConfigWithLayers(funcName, layerName, policyName, roleName, sgName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", funcName, &conf),
testAccCheckAwsLambdaFunctionName(&conf, funcName),
testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+funcName),
testAccCheckAWSLambdaFunctionVersion(&conf, "$LATEST"),
resource.TestCheckResourceAttr("aws_lambda_function.lambda_function_test", "layers.#", "1"),
),
},
{
Config: testAccAWSLambdaConfigWithLayersUpdated(funcName, layerName, layer2Name, policyName, roleName, sgName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", funcName, &conf),
testAccCheckAwsLambdaFunctionName(&conf, funcName),
testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+funcName),
testAccCheckAWSLambdaFunctionVersion(&conf, "$LATEST"),
resource.TestCheckResourceAttr("aws_lambda_function.lambda_function_test", "layers.#", "2"),
),
},
},
})
}

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

Expand Down Expand Up @@ -1888,6 +1957,53 @@ resource "aws_lambda_function" "lambda_function_test" {
`, funcName)
}

func testAccAWSLambdaConfigWithLayers(funcName, layerName, policyName, roleName, sgName string) string {
return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+`
resource "aws_lambda_layer_version" "lambda_function_test" {
filename = "test-fixtures/lambdatest.zip"
layer_name = "%s"
compatible_runtimes = ["nodejs8.10"]
}

resource "aws_lambda_function" "lambda_function_test" {
filename = "test-fixtures/lambdatest.zip"
function_name = "%s"
role = "${aws_iam_role.iam_for_lambda.arn}"
handler = "exports.example"
runtime = "nodejs8.10"
layers = ["${aws_lambda_layer_version.lambda_function_test.layer_arn}"]
}
`, layerName, funcName)
}

func testAccAWSLambdaConfigWithLayersUpdated(funcName, layerName, layer2Name, policyName, roleName, sgName string) string {
return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+`
resource "aws_lambda_layer_version" "lambda_function_test" {
filename = "test-fixtures/lambdatest.zip"
layer_name = "%s"
compatible_runtimes = ["nodejs8.10"]
}

resource "aws_lambda_layer_version" "lambda_function_test_2" {
filename = "test-fixtures/lambdatest_modified.zip"
layer_name = "%s"
compatible_runtimes = ["nodejs8.10"]
}

resource "aws_lambda_function" "lambda_function_test" {
filename = "test-fixtures/lambdatest.zip"
function_name = "%s"
role = "${aws_iam_role.iam_for_lambda.arn}"
handler = "exports.example"
runtime = "nodejs8.10"
layers = [
"${aws_lambda_layer_version.lambda_function_test.layer_arn}",
"${aws_lambda_layer_version.lambda_function_test_2.layer_arn}",
]
}
`, layerName, layer2Name, funcName)
}

func testAccAWSLambdaConfigWithVPC(funcName, policyName, roleName, sgName string) string {
return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+`
resource "aws_lambda_function" "lambda_function_test" {
Expand Down
8 changes: 8 additions & 0 deletions aws/structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -1487,6 +1487,14 @@ func flattenLambdaEnvironment(lambdaEnv *lambda.EnvironmentResponse) []interface
return []interface{}{envs}
}

func flattenLambdaLayers(layers []*lambda.Layer) []interface{} {
arns := make([]*string, len(layers))
for i, layer := range layers {
arns[i] = layer.Arn
}
return flattenStringList(arns)
}

func flattenLambdaVpcConfigResponse(s *lambda.VpcConfigResponse) []map[string]interface{} {
settings := make(map[string]interface{})

Expand Down
1 change: 1 addition & 0 deletions website/docs/d/lambda_function.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ In addition to all arguments above, the following attributes are exported:
* `invoke_arn` - The ARN to be used for invoking Lambda Function from API Gateway.
* `kms_key_arn` - The ARN for the KMS encryption key.
* `last_modified` - The date this resource was last modified.
* `layers` - A list of Lambda Layer ARNs attached to your Lambda Function.
* `memory_size` - Amount of memory in MB your Lambda Function can use at runtime.
* `qualified_arn` - The Amazon Resource Name (ARN) identifying your Lambda Function Version
* `reserved_concurrent_executions` - The amount of reserved concurrent executions for this lambda function.
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/lambda_function.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ large files efficiently.
* `handler` - (Required) The function [entrypoint][3] in your code.
* `role` - (Required) IAM role attached to the Lambda Function. This governs both who / what can invoke your Lambda Function, as well as what resources our Lambda Function has access to. See [Lambda Permission Model][4] for more details.
* `description` - (Optional) Description of what your Lambda Function does.
* `layers` - (Optional) List of Lambda Layer Version ARNs (maximum of 5) to attach to your Lambda Function. See [Lambda Layers][10]
* `memory_size` - (Optional) Amount of memory in MB your Lambda Function can use at runtime. Defaults to `128`. See [Limits][5]
* `runtime` - (Required) See [Runtimes][6] for valid values.
* `timeout` - (Optional) The amount of time your Lambda Function has to run in seconds. Defaults to `3`. See [Limits][5]
Expand Down Expand Up @@ -174,6 +175,7 @@ For **environment** the following attributes are supported:
[7]: http://docs.aws.amazon.com/lambda/latest/dg/vpc.html
[8]: https://docs.aws.amazon.com/lambda/latest/dg/deployment-package-v2.html
[9]: https://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html
[10]: https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html

## Timeouts

Expand Down