Skip to content

Commit bc60bd4

Browse files
Merge hashicorp#12188: AWS Lambda DeadLetterConfig support
2 parents e8338bd + db9fbe6 commit bc60bd4

3 files changed

Lines changed: 115 additions & 0 deletions

File tree

‎builtin/providers/aws/resource_aws_lambda_function.go‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,22 @@ func resourceAwsLambdaFunction() *schema.Resource {
5858
Type: schema.TypeString,
5959
Optional: true,
6060
},
61+
"dead_letter_config": {
62+
Type: schema.TypeList,
63+
Optional: true,
64+
ForceNew: true,
65+
MinItems: 0,
66+
MaxItems: 1,
67+
Elem: &schema.Resource{
68+
Schema: map[string]*schema.Schema{
69+
"target_arn": {
70+
Type: schema.TypeString,
71+
Required: true,
72+
ValidateFunc: validateArn,
73+
},
74+
},
75+
},
76+
},
6177
"function_name": {
6278
Type: schema.TypeString,
6379
Required: true,
@@ -222,6 +238,16 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e
222238
Publish: aws.Bool(d.Get("publish").(bool)),
223239
}
224240

241+
if v, ok := d.GetOk("dead_letter_config"); ok {
242+
dlcMaps := v.([]interface{})
243+
if len(dlcMaps) == 1 { // Schema guarantees either 0 or 1
244+
dlcMap := dlcMaps[0].(map[string]interface{})
245+
params.DeadLetterConfig = &lambda.DeadLetterConfig{
246+
TargetArn: aws.String(dlcMap["target_arn"].(string)),
247+
}
248+
}
249+
}
250+
225251
if v, ok := d.GetOk("vpc_config"); ok {
226252
config, err := validateVPCConfig(v)
227253
if err != nil {
@@ -343,6 +369,16 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err
343369
log.Printf("[ERR] Error setting environment for Lambda Function (%s): %s", d.Id(), err)
344370
}
345371

372+
if function.DeadLetterConfig != nil && function.DeadLetterConfig.TargetArn != nil {
373+
d.Set("dead_letter_config", []interface{}{
374+
map[string]interface{}{
375+
"target_arn": *function.DeadLetterConfig.TargetArn,
376+
},
377+
})
378+
} else {
379+
d.Set("dead_letter_config", []interface{}{})
380+
}
381+
346382
// List is sorted from oldest to latest
347383
// so this may get costly over time :'(
348384
var lastVersion, lastQualifiedArn string
@@ -485,6 +521,16 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e
485521
configReq.KMSKeyArn = aws.String(d.Get("kms_key_arn").(string))
486522
configUpdate = true
487523
}
524+
if d.HasChange("dead_letter_config") {
525+
dlcMaps := d.Get("dead_letter_config").([]interface{})
526+
if len(dlcMaps) == 1 { // Schema guarantees either 0 or 1
527+
dlcMap := dlcMaps[0].(map[string]interface{})
528+
configReq.DeadLetterConfig = &lambda.DeadLetterConfig{
529+
TargetArn: aws.String(dlcMap["target_arn"].(string)),
530+
}
531+
configUpdate = true
532+
}
533+
}
488534
if d.HasChange("environment") {
489535
if v, ok := d.GetOk("environment"); ok {
490536
environments := v.([]interface{})

‎builtin/providers/aws/resource_aws_lambda_function_test.go‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,37 @@ func TestAccAWSLambdaFunction_versioned(t *testing.T) {
172172
})
173173
}
174174

175+
func TestAccAWSLambdaFunction_DeadLetterConfig(t *testing.T) {
176+
var conf lambda.GetFunctionOutput
177+
178+
rSt := acctest.RandString(5)
179+
rName := fmt.Sprintf("tf_test_%s", rSt)
180+
181+
resource.Test(t, resource.TestCase{
182+
PreCheck: func() { testAccPreCheck(t) },
183+
Providers: testAccProviders,
184+
CheckDestroy: testAccCheckLambdaFunctionDestroy,
185+
Steps: []resource.TestStep{
186+
{
187+
Config: testAccAWSLambdaConfigWithDeadLetterConfig(rName, rSt),
188+
Check: resource.ComposeTestCheckFunc(
189+
testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", rName, &conf),
190+
testAccCheckAwsLambdaFunctionName(&conf, rName),
191+
testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+rName),
192+
func(s *terraform.State) error {
193+
if !strings.HasSuffix(*conf.Configuration.DeadLetterConfig.TargetArn, ":"+rName) {
194+
return fmt.Errorf(
195+
"Expected DeadLetterConfig.TargetArn %s to have suffix %s", *conf.Configuration.DeadLetterConfig.TargetArn, ":"+rName,
196+
)
197+
}
198+
return nil
199+
},
200+
),
201+
},
202+
},
203+
})
204+
}
205+
175206
func TestAccAWSLambdaFunction_VPC(t *testing.T) {
176207
var conf lambda.GetFunctionOutput
177208

@@ -681,6 +712,15 @@ resource "aws_iam_role_policy" "iam_policy_for_lambda" {
681712
"Resource": [
682713
"*"
683714
]
715+
},
716+
{
717+
"Effect": "Allow",
718+
"Action": [
719+
"SNS:Publish"
720+
],
721+
"Resource": [
722+
"*"
723+
]
684724
}
685725
]
686726
}
@@ -879,6 +919,27 @@ resource "aws_lambda_function" "lambda_function_test" {
879919
`, rName)
880920
}
881921

922+
func testAccAWSLambdaConfigWithDeadLetterConfig(rName, rSt string) string {
923+
return fmt.Sprintf(baseAccAWSLambdaConfig(rSt)+`
924+
resource "aws_lambda_function" "lambda_function_test" {
925+
filename = "test-fixtures/lambdatest.zip"
926+
function_name = "%s"
927+
role = "${aws_iam_role.iam_for_lambda.arn}"
928+
handler = "exports.example"
929+
runtime = "nodejs4.3"
930+
931+
dead_letter_config {
932+
target_arn = "${aws_sns_topic.lambda_function_test.arn}"
933+
}
934+
}
935+
936+
resource "aws_sns_topic" "lambda_function_test" {
937+
name = "%s"
938+
}
939+
940+
`, rName, rName)
941+
}
942+
882943
func testAccAWSLambdaConfigWithVPC(rName, rSt string) string {
883944
return fmt.Sprintf(baseAccAWSLambdaConfig(rSt)+`
884945
resource "aws_lambda_function" "lambda_function_test" {

‎website/source/docs/providers/aws/r/lambda_function.html.markdown‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ resource "aws_lambda_function" "test_lambda" {
5757
* `s3_key` - (Optional) The S3 key of a [zip file][2] containing your lambda function source code. Conflicts with `filename`.
5858
* `s3_object_version` - (Optional) The object version of your lambda function source code. Conflicts with `filename`.
5959
* `function_name` - (Required) A unique name for your Lambda Function.
60+
* `dead_letter_config` - (Optional) Nested block to configure the function's *dead letter queue*. See details below.
6061
* `handler` - (Required) The function [entrypoint][3] in your code.
6162
* `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.
6263
* `description` - (Optional) Description of what your Lambda Function does.
@@ -70,6 +71,13 @@ resource "aws_lambda_function" "test_lambda" {
7071
* `source_code_hash` - (Optional) Used to trigger updates. This is only useful in conjunction with `filename`.
7172
The only useful value is `${base64sha256(file("file.zip"))}`.
7273

74+
**dead\_letter\_config** is a child block with a single argument:
75+
76+
* `target_arn` - (Required) The ARN of an SNS topic or SQS queue to notify when an invocation fails. If this
77+
option is used, the function's IAM role must be granted suitable access to write to the target object,
78+
which means allowing either the `sns:Publish` or `sqs:SendMessage` action on this ARN, depending on
79+
which service is targeted.
80+
7381
**vpc\_config** requires the following:
7482

7583
* `subnet_ids` - (Required) A list of subnet IDs associated with the Lambda function.

0 commit comments

Comments
 (0)