From a82489b4457f7eaa11ca88d88b8717806b1766d9 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Mon, 16 Nov 2020 12:28:54 +0800 Subject: [PATCH 01/15] add OCI image support to aws_lambda_function resource --- aws/resource_aws_lambda_function.go | 104 +++++++++++++++++-- aws/resource_aws_lambda_function_test.go | 86 +++++++++++++++ website/docs/r/lambda_function.html.markdown | 16 ++- 3 files changed, 191 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 13070631ed3..2fb3223523b 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -46,22 +46,56 @@ func resourceAwsLambdaFunction() *schema.Resource { "filename": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"s3_bucket", "s3_key", "s3_object_version"}, + ConflictsWith: []string{"s3_bucket", "s3_key", "s3_object_version", "image_uri"}, }, "s3_bucket": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"filename"}, + ConflictsWith: []string{"filename", "image_uri"}, }, "s3_key": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"filename"}, + ConflictsWith: []string{"filename", "image_uri"}, }, "s3_object_version": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"filename"}, + ConflictsWith: []string{"filename", "image_uri"}, + }, + "image_uri": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"filename", "s3_bucket", "s3_key", "s3_object_version"}, + }, + "package_type": { + Type: schema.TypeString, + Optional: true, + Default: lambda.PackageTypeZip, + ValidateFunc: validation.StringInSlice([]string{lambda.PackageTypeZip, lambda.PackageTypeImage}, false), + }, + "image_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "entry_point": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "command": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "working_directory": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, }, "description": { Type: schema.TypeString, @@ -112,7 +146,7 @@ func resourceAwsLambdaFunction() *schema.Resource { }, "handler": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: validation.StringLenBetween(1, 128), }, "layers": { @@ -141,7 +175,7 @@ func resourceAwsLambdaFunction() *schema.Resource { }, "runtime": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: validation.StringInSlice(lambda.Runtime_Values(), false), }, "timeout": { @@ -290,6 +324,7 @@ func hasConfigChanges(d resourceDiffer) bool { return d.HasChange("description") || d.HasChange("handler") || d.HasChange("file_system_config") || + d.HasChange("image_config") || d.HasChange("memory_size") || d.HasChange("role") || d.HasChange("timeout") || @@ -317,9 +352,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e s3Bucket, bucketOk := d.GetOk("s3_bucket") s3Key, keyOk := d.GetOk("s3_key") s3ObjectVersion, versionOk := d.GetOk("s3_object_version") + imageUri, hasImageUri := d.GetOk("image_uri") - if !hasFilename && !bucketOk && !keyOk && !versionOk { - return errors.New("filename or s3_* attributes must be set") + if !hasFilename && !bucketOk && !keyOk && !versionOk && !hasImageUri { + return errors.New("filename, s3_* or image_uri attributes must be set") } var functionCode *lambda.FunctionCode @@ -336,6 +372,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e functionCode = &lambda.FunctionCode{ ZipFile: file, } + } else if hasImageUri { + functionCode = &lambda.FunctionCode{ + ImageUri: aws.String(imageUri.(string)), + } } else { if !bucketOk || !keyOk { return errors.New("s3_bucket and s3_key must all be set while using S3 code source") @@ -349,16 +389,28 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e } } + packageType := aws.String(d.Get("package_type").(string)) + handler, handlerOk := d.GetOk("handler") + runtime, runtimeOk := d.GetOk("runtime") + + if *packageType == lambda.PackageTypeZip && !handlerOk && !runtimeOk { + return errors.New("handler and runtime must be set when PackageType is Zip") + } + params := &lambda.CreateFunctionInput{ Code: functionCode, Description: aws.String(d.Get("description").(string)), FunctionName: aws.String(functionName), - Handler: aws.String(d.Get("handler").(string)), MemorySize: aws.Int64(int64(d.Get("memory_size").(int))), Role: aws.String(iamRole), - Runtime: aws.String(d.Get("runtime").(string)), Timeout: aws.Int64(int64(d.Get("timeout").(int))), Publish: aws.Bool(d.Get("publish").(bool)), + PackageType: aws.String(d.Get("package_type").(string)), + } + + if *packageType == lambda.PackageTypeZip { + params.Handler = aws.String(handler.(string)) + params.Runtime = aws.String(runtime.(string)) } if v, ok := d.GetOk("layers"); ok && len(v.([]interface{})) > 0 { @@ -383,6 +435,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e params.FileSystemConfigs = expandLambdaFileSystemConfigs(v.([]interface{})) } + if v, ok := d.GetOk("image_config"); ok && len(v.([]interface{})) > 0 { + params.ImageConfig = expandLambdaImageConfigs(v.([]interface{})) + } + if v, ok := d.GetOk("vpc_config"); ok && len(v.([]interface{})) > 0 { config := v.([]interface{})[0].(map[string]interface{}) @@ -700,7 +756,9 @@ func needsFunctionCodeUpdate(d resourceDiffer) bool { d.HasChange("source_code_hash") || d.HasChange("s3_bucket") || d.HasChange("s3_key") || - d.HasChange("s3_object_version") + d.HasChange("s3_object_version") || + d.HasChange("image_uri") + } // resourceAwsLambdaFunctionUpdate maps to: @@ -733,6 +791,12 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e configReq.FileSystemConfigs = expandLambdaFileSystemConfigs(v.([]interface{})) } } + if d.HasChange("image_config") { + configReq.ImageConfig = &lambda.ImageConfig{} + if v, ok := d.GetOk("image_config"); ok && len(v.([]interface{})) > 0 { + configReq.ImageConfig = expandLambdaImageConfigs(v.([]interface{})) + } + } if d.HasChange("memory_size") { configReq.MemorySize = aws.Int64(int64(d.Get("memory_size").(int))) } @@ -883,6 +947,8 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Unable to load %q: %w", v.(string), err) } codeReq.ZipFile = file + } else if v, ok := d.GetOk("image_uri"); ok { + codeReq.ImageUri = aws.String(v.(string)) } else { s3Bucket, _ := d.GetOk("s3_bucket") s3Key, _ := d.GetOk("s3_key") @@ -1081,3 +1147,19 @@ func expandLambdaFileSystemConfigs(fscMaps []interface{}) []*lambda.FileSystemCo } return fileSystemConfigs } + +func expandLambdaImageConfigs(imageConfigMaps []interface{}) *lambda.ImageConfig { + imageConfig := &lambda.ImageConfig{} + // only one image_config block is allowed + if len(imageConfigMaps) == 1 && imageConfigMaps[0] != nil { + config := imageConfigMaps[0].(map[string]interface{}) + if len(config["entry_point"].([]interface{})) > 0 { + imageConfig.EntryPoint = expandStringList(config["entry_point"].([]interface{})) + } + if len(config["command"].([]interface{})) > 0 { + imageConfig.Command = expandStringList(config["command"].([]interface{})) + } + imageConfig.WorkingDirectory = aws.String(config["working_directory"].(string)) + } + return imageConfig +} diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index 376c58963d8..e2ad0601ded 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -806,6 +806,56 @@ func TestAccAWSLambdaFunction_FileSystemConfig(t *testing.T) { }) } +func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { + var conf lambda.GetFunctionOutput + resourceName := "aws_lambda_function.test" + + rString := acctest.RandString(8) + funcName := fmt.Sprintf("tf_acc_lambda_func_basic_%s", rString) + policyName := fmt.Sprintf("tf_acc_policy_lambda_func_basic_%s", rString) + roleName := fmt.Sprintf("tf_acc_role_lambda_func_basic_%s", rString) + sgName := fmt.Sprintf("tf_acc_sg_lambda_func_basic_%s", rString) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaFunctionDestroy, + Steps: []resource.TestStep{ + // Ensure a function with lambda file system configuration can be created + { + Config: testAccAWSLambdaImageConfig(funcName, policyName, roleName, sgName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + testAccCheckAwsLambdaFunctionName(&conf, funcName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "lambda", fmt.Sprintf("function:%s", funcName)), + testAccCheckAwsLambdaFunctionInvokeArn(resourceName, &conf), + ), + }, + // Ensure configuration can be imported + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"filename", "publish"}, + }, + // Ensure lambda image code can be updated + { + Config: testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + ), + }, + // Ensure lambda image config can be updated + { + Config: testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + ), + }, + }, + }) +} + func TestAccAWSLambdaFunction_tracingConfig(t *testing.T) { var conf lambda.GetFunctionOutput @@ -2221,6 +2271,42 @@ resource "aws_lambda_function" "test" { `, funcName) } +func testAccAWSLambdaImageConfig(funcName, policyName, roleName, sgName string) string { + return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` +resource "aws_lambda_function" "test" { + image_uri = "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:latest" + function_name = "%s" + role = aws_iam_role.iam_for_lambda.arn + package_type = "Image" +} +`, funcName) +} + +func testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName string) string { + return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` +resource "aws_lambda_function" "test" { + image_uri = "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v1" + function_name = "%s" + role = aws_iam_role.iam_for_lambda.arn + package_type = "Image" +} +`, funcName) +} + +func testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName string) string { + return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` +resource "aws_lambda_function" "test" { + image_uri = "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v2" + function_name = "%s" + role = aws_iam_role.iam_for_lambda.arn + package_type = "Image" + image_config { + command = ["app.another_handler"] + } +} +`, funcName) +} + func testAccAWSLambdaConfigVersionedNodeJs10xRuntime(fileName, funcName, policyName, roleName, sgName string) string { return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` resource "aws_lambda_function" "test" { diff --git a/website/docs/r/lambda_function.html.markdown b/website/docs/r/lambda_function.html.markdown index 18869187a2e..875f0810c72 100644 --- a/website/docs/r/lambda_function.html.markdown +++ b/website/docs/r/lambda_function.html.markdown @@ -206,10 +206,12 @@ large files efficiently. ## Argument Reference -* `filename` - (Optional) The path to the function's deployment package within the local filesystem. If defined, The `s3_`-prefixed options cannot be used. -* `s3_bucket` - (Optional) The S3 bucket location containing the function's deployment package. Conflicts with `filename`. This bucket must reside in the same AWS region where you are creating the Lambda function. -* `s3_key` - (Optional) The S3 key of an object containing the function's deployment package. Conflicts with `filename`. -* `s3_object_version` - (Optional) The object version containing the function's deployment package. Conflicts with `filename`. +* `filename` - (Optional) The path to the function's deployment package within the local filesystem. If defined, The `s3_`-prefixed options and `image_uri` cannot be used. +* `s3_bucket` - (Optional) The S3 bucket location containing the function's deployment package. Conflicts with `filename` and `image_uri`. This bucket must reside in the same AWS region where you are creating the Lambda function. +* `s3_key` - (Optional) The S3 key of an object containing the function's deployment package. Conflicts with `filename` and `image_uri`. +* `s3_object_version` - (Optional) The object version containing the function's deployment package. Conflicts with `filename` and `image_uri`. +* `image_uri` - (Optional) The ECR image URI containing the function's deployment package. Conflicts with `filename`, `s3_bucket`, `s3_key`, and `s3_object_version`. +* `package_type` - (Optional) The Lambda deployment package type. Valid values are `Zip` and `Image`. Defaults to `Zip`. * `function_name` - (Required) A unique name for your Lambda Function. * `dead_letter_config` - (Optional) Nested block to configure the function's *dead letter queue*. See details below. * `handler` - (Required) The function [entrypoint][3] in your code. @@ -227,6 +229,7 @@ large files efficiently. * `source_code_hash` - (Optional) Used to trigger updates. Must be set to a base64-encoded SHA256 hash of the package file specified with either `filename` or `s3_key`. The usual way to set this is `filebase64sha256("file.zip")` (Terraform 0.11.12 and later) or `base64sha256(file("file.zip"))` (Terraform 0.11.11 and earlier), where "file.zip" is the local filename of the lambda function source archive. * `tags` - (Optional) A map of tags to assign to the object. * `file_system_config` - (Optional) The connection settings for an EFS file system. Fields documented below. Before creating or updating Lambda functions with `file_system_config`, EFS mount targets much be in available lifecycle state. Use `depends_on` to explicitly declare this dependency. See [Using Amazon EFS with Lambda][12]. +* `image_config` - (Optional) The Lambda OCI image configurations. Fields documented below. **dead_letter_config** is a child block with a single argument: @@ -259,6 +262,11 @@ For **environment** the following attributes are supported: * `arn` - (Required) The Amazon Resource Name (ARN) of the Amazon EFS Access Point that provides access to the file system. * `local_mount_path` - (Required) The path where the function can access the file system, starting with /mnt/. +**image_config** is a child block with three arguments: + +* `entry_point` - (Optional) The ENTRYPOINT for the docker image. +* `command` - (Optional) The CMD for the docker image. +* `working_directory` - (Optional) The working directory for the docker image. ## Attributes Reference From d2789496a48acb26b3f36e02dde453e4b8f98cb5 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Sat, 28 Nov 2020 22:40:41 +0800 Subject: [PATCH 02/15] address code review comments --- aws/resource_aws_lambda_function.go | 54 +++++++++++++++++++----- aws/resource_aws_lambda_function_test.go | 17 +++++++- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 18508741f53..9aacb283128 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -71,8 +71,9 @@ func resourceAwsLambdaFunction() *schema.Resource { "package_type": { Type: schema.TypeString, Optional: true, + ForceNew: true, Default: lambda.PackageTypeZip, - ValidateFunc: validation.StringInSlice([]string{lambda.PackageTypeZip, lambda.PackageTypeImage}, false), + ValidateFunc: validation.StringInSlice(lambda.PackageType_Values(), false), }, "image_config": { Type: schema.TypeList, @@ -402,11 +403,11 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e } } - packageType := aws.String(d.Get("package_type").(string)) + packageType := d.Get("package_type") handler, handlerOk := d.GetOk("handler") runtime, runtimeOk := d.GetOk("runtime") - if *packageType == lambda.PackageTypeZip && !handlerOk && !runtimeOk { + if packageType == lambda.PackageTypeZip && !handlerOk && !runtimeOk { return errors.New("handler and runtime must be set when PackageType is Zip") } @@ -421,7 +422,7 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e PackageType: aws.String(d.Get("package_type").(string)), } - if *packageType == lambda.PackageTypeZip { + if packageType == lambda.PackageTypeZip { params.Handler = aws.String(handler.(string)) params.Runtime = aws.String(runtime.(string)) } @@ -593,6 +594,9 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err conn := meta.(*AWSClient).lambdaconn ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + // testing + //return errors.New("raise an error for debugging") + params := &lambda.GetFunctionInput{ FunctionName: aws.String(d.Get("function_name").(string)), } @@ -696,6 +700,18 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Error setting file system config for Lambda Function (%s): %w", d.Id(), err) } + // Add Package Type + if err := d.Set("package_type", function.PackageType); err != nil { + return fmt.Errorf("Error setting package type for Lambda Function: %s", err) + } + + // Add Image Configuration + imageConfig := flattenLambdaImageConfig(function.ImageConfigResponse) + log.Printf("[INFO] Setting Lambda %s Image config %#v from API", d.Id(), imageConfig) + if err := d.Set("image_config", imageConfig); err != nil { + return fmt.Errorf("Error setting image config for Lambda Function: %s", err) + } + 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 { @@ -773,15 +789,20 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err FunctionName: aws.String(d.Get("function_name").(string)), } - getCodeSigningConfigOutput, err := conn.GetFunctionCodeSigningConfig(codeSigningConfigInput) - if err != nil { - return fmt.Errorf("error getting Lambda Function (%s) code signing config %w", d.Id(), err) - } + // Code Signing is only supported on zip packaged lambda functions. + if *function.PackageType == lambda.PackageTypeZip { + getCodeSigningConfigOutput, err := conn.GetFunctionCodeSigningConfig(codeSigningConfigInput) + if err != nil { + return fmt.Errorf("error getting Lambda Function (%s) code signing config %w", d.Id(), err) + } - if getCodeSigningConfigOutput == nil || getCodeSigningConfigOutput.CodeSigningConfigArn == nil { - d.Set("code_signing_config_arn", "") + if getCodeSigningConfigOutput == nil || getCodeSigningConfigOutput.CodeSigningConfigArn == nil { + d.Set("code_signing_config_arn", "") + } else { + d.Set("code_signing_config_arn", getCodeSigningConfigOutput.CodeSigningConfigArn) + } } else { - d.Set("code_signing_config_arn", getCodeSigningConfigOutput.CodeSigningConfigArn) + d.Set("code_signing_config_arn", "") } return nil @@ -1249,6 +1270,17 @@ func expandLambdaFileSystemConfigs(fscMaps []interface{}) []*lambda.FileSystemCo return fileSystemConfigs } +func flattenLambdaImageConfig(response *lambda.ImageConfigResponse) []map[string]interface{} { + settings := make(map[string]interface{}) + if response != nil && response.Error != nil { + settings["command"] = response.ImageConfig.Command + settings["entry_point"] = response.ImageConfig.EntryPoint + settings["working_directory"] = response.ImageConfig.WorkingDirectory + } + + return []map[string]interface{}{settings} +} + func expandLambdaImageConfigs(imageConfigMaps []interface{}) *lambda.ImageConfig { imageConfig := &lambda.ImageConfig{} // only one image_config block is allowed diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index a897fa432f6..054d35a27e9 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -85,6 +85,7 @@ func TestAccAWSLambdaFunction_basic(t *testing.T) { testAccCheckAwsLambdaFunctionInvokeArn(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "reserved_concurrent_executions", "-1"), resource.TestCheckResourceAttr(resourceName, "version", LambdaFunctionVersionLatest), + resource.TestCheckResourceAttr(resourceName, "package_type", lambda.PackageTypeZip), testAccCheckResourceAttrRegionalARN(resourceName, "qualified_arn", "lambda", fmt.Sprintf("function:%s:%s", funcName, LambdaFunctionVersionLatest)), ), }, @@ -867,6 +868,7 @@ func TestAccAWSLambdaFunction_FileSystemConfig(t *testing.T) { func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { var conf lambda.GetFunctionOutput resourceName := "aws_lambda_function.test" + dataSourceName := "data.aws_lambda_function.test" rString := acctest.RandString(8) funcName := fmt.Sprintf("tf_acc_lambda_func_basic_%s", rString) @@ -879,7 +881,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckLambdaFunctionDestroy, Steps: []resource.TestStep{ - // Ensure a function with lambda file system configuration can be created + // Ensure a function with lambda image configuration can be created { Config: testAccAWSLambdaImageConfig(funcName, policyName, roleName, sgName), Check: resource.ComposeTestCheckFunc( @@ -887,6 +889,12 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { testAccCheckAwsLambdaFunctionName(&conf, funcName), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "lambda", fmt.Sprintf("function:%s", funcName)), testAccCheckAwsLambdaFunctionInvokeArn(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "package_type", lambda.PackageTypeImage), + resource.TestCheckResourceAttrSet(dataSourceName, "image_uri"), + resource.TestCheckResourceAttr(resourceName, "image_config.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "image_config.0.working_directory"), + resource.TestCheckResourceAttrSet(resourceName, "image_config.0.command"), + resource.TestCheckNoResourceAttr(resourceName, "image_config.0.entry_point"), ), }, // Ensure configuration can be imported @@ -901,6 +909,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Config: testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + resource.TestCheckResourceAttr(resourceName, "image_uri", "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v1"), ), }, // Ensure lambda image config can be updated @@ -908,6 +917,8 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Config: testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + resource.TestCheckResourceAttr(resourceName, "image_uri", "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v2"), + resource.TestCheckResourceAttr(resourceName, "image_config.0.command", "app.another_handler"), ), }, }, @@ -2443,6 +2454,10 @@ resource "aws_lambda_function" "test" { function_name = "%s" role = aws_iam_role.iam_for_lambda.arn package_type = "Image" + image_config { + command = ["app.another_handler"] + working_directory = "/var/task" + } } `, funcName) } From 2d089917e2577ff427f51215e3b787b4431ad8bb Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Mon, 30 Nov 2020 01:42:45 +0800 Subject: [PATCH 03/15] address code review comments --- aws/resource_aws_lambda_function.go | 16 ++++++++++++---- aws/resource_aws_lambda_function_test.go | 13 ++----------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 9aacb283128..af6c0b15689 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -701,6 +701,7 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err } // Add Package Type + log.Printf("[INFO] Setting Lambda %s package type %#v from API", d.Id(), function.PackageType) if err := d.Set("package_type", function.PackageType); err != nil { return fmt.Errorf("Error setting package type for Lambda Function: %s", err) } @@ -712,6 +713,10 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Error setting image config for Lambda Function: %s", err) } + if err := d.Set("image_uri", getFunctionOutput.Code.ImageUri); err != nil { + return fmt.Errorf("Error setting image uri for Lambda Function: %s", err) + } + 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 { @@ -1272,12 +1277,15 @@ func expandLambdaFileSystemConfigs(fscMaps []interface{}) []*lambda.FileSystemCo func flattenLambdaImageConfig(response *lambda.ImageConfigResponse) []map[string]interface{} { settings := make(map[string]interface{}) - if response != nil && response.Error != nil { - settings["command"] = response.ImageConfig.Command - settings["entry_point"] = response.ImageConfig.EntryPoint - settings["working_directory"] = response.ImageConfig.WorkingDirectory + + if response == nil || response.Error != nil { + return nil } + settings["command"] = response.ImageConfig.Command + settings["entry_point"] = response.ImageConfig.EntryPoint + settings["working_directory"] = response.ImageConfig.WorkingDirectory + return []map[string]interface{}{settings} } diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index 054d35a27e9..77717b504ee 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -868,7 +868,6 @@ func TestAccAWSLambdaFunction_FileSystemConfig(t *testing.T) { func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { var conf lambda.GetFunctionOutput resourceName := "aws_lambda_function.test" - dataSourceName := "data.aws_lambda_function.test" rString := acctest.RandString(8) funcName := fmt.Sprintf("tf_acc_lambda_func_basic_%s", rString) @@ -890,11 +889,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { testAccCheckResourceAttrRegionalARN(resourceName, "arn", "lambda", fmt.Sprintf("function:%s", funcName)), testAccCheckAwsLambdaFunctionInvokeArn(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "package_type", lambda.PackageTypeImage), - resource.TestCheckResourceAttrSet(dataSourceName, "image_uri"), - resource.TestCheckResourceAttr(resourceName, "image_config.#", "1"), - resource.TestCheckResourceAttrSet(resourceName, "image_config.0.working_directory"), - resource.TestCheckResourceAttrSet(resourceName, "image_config.0.command"), - resource.TestCheckNoResourceAttr(resourceName, "image_config.0.entry_point"), + resource.TestCheckResourceAttrSet(resourceName, "image_uri"), ), }, // Ensure configuration can be imported @@ -918,7 +913,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), resource.TestCheckResourceAttr(resourceName, "image_uri", "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v2"), - resource.TestCheckResourceAttr(resourceName, "image_config.0.command", "app.another_handler"), + resource.TestCheckResourceAttr(resourceName, "image_config.0.command.0", "app.another_handler"), ), }, }, @@ -2454,10 +2449,6 @@ resource "aws_lambda_function" "test" { function_name = "%s" role = aws_iam_role.iam_for_lambda.arn package_type = "Image" - image_config { - command = ["app.another_handler"] - working_directory = "/var/task" - } } `, funcName) } From 298a59c2e991d1e7499db02fd6e1a1eaf2730389 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Mon, 30 Nov 2020 11:16:27 +0800 Subject: [PATCH 04/15] replace tab with spaces --- aws/resource_aws_lambda_function_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index 77717b504ee..927675d0aac 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -2472,7 +2472,7 @@ resource "aws_lambda_function" "test" { role = aws_iam_role.iam_for_lambda.arn package_type = "Image" image_config { - command = ["app.another_handler"] + command = ["app.another_handler"] } } `, funcName) From 13e93ad507e1cb4eb6183071a9efb515d9a22855 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Mon, 30 Nov 2020 13:32:11 +0800 Subject: [PATCH 05/15] remove debug code --- aws/resource_aws_lambda_function.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 0acd17177d6..a21b8431c70 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -595,9 +595,6 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err conn := meta.(*AWSClient).lambdaconn ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - // testing - //return errors.New("raise an error for debugging") - params := &lambda.GetFunctionInput{ FunctionName: aws.String(d.Get("function_name").(string)), } From 28edd73c5e67e76cf0d88d8dd9ded51039581e35 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Mon, 30 Nov 2020 21:43:44 +0800 Subject: [PATCH 06/15] update test case --- aws/resource_aws_lambda_function_test.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index b7f1703fde1..b020caedcef 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -890,6 +890,10 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { testAccCheckAwsLambdaFunctionInvokeArn(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "package_type", lambda.PackageTypeImage), resource.TestCheckResourceAttrSet(resourceName, "image_uri"), + resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:latest$")), + resource.TestCheckResourceAttr(resourceName, "image_config.0.entry_point.0", "/bootstrap-with-handler"), + resource.TestCheckResourceAttr(resourceName, "image_config.0.command.0", "app.lambda_handler"), + resource.TestCheckResourceAttr(resourceName, "image_config.0.working_directory", "/var/task"), ), }, // Ensure configuration can be imported @@ -904,7 +908,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Config: testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), - resource.TestCheckResourceAttr(resourceName, "image_uri", "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v1"), + resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:v1$")), ), }, // Ensure lambda image config can be updated @@ -912,7 +916,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Config: testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), - resource.TestCheckResourceAttr(resourceName, "image_uri", "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v2"), + resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:v2$")), resource.TestCheckResourceAttr(resourceName, "image_config.0.command.0", "app.another_handler"), ), }, @@ -2449,6 +2453,11 @@ resource "aws_lambda_function" "test" { function_name = "%s" role = aws_iam_role.iam_for_lambda.arn package_type = "Image" + image_config { + entry_point = ["/bootstrap-with-handler"] + command = ["app.lambda_handler"] + working_directory = "/var/task" + } } `, funcName) } From 1eaa4c4c86cb1938f72231065011f8a64dbfb670 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 1 Dec 2020 22:19:16 +0800 Subject: [PATCH 07/15] use %w for error format --- aws/resource_aws_lambda_function.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index a21b8431c70..ec83e4a0e6b 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -701,7 +701,7 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err // Add Package Type log.Printf("[INFO] Setting Lambda %s package type %#v from API", d.Id(), function.PackageType) if err := d.Set("package_type", function.PackageType); err != nil { - return fmt.Errorf("Error setting package type for Lambda Function: %s", err) + return fmt.Errorf("Error setting package type for Lambda Function: %w", err) } // Add Image Configuration From 869fbba9441b84878e1f4ebf9fd91e1db967751d Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 1 Dec 2020 23:14:33 +0800 Subject: [PATCH 08/15] include link to lambda doc --- website/docs/r/lambda_function.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/r/lambda_function.html.markdown b/website/docs/r/lambda_function.html.markdown index d2bda55013e..aca2e8c5719 100644 --- a/website/docs/r/lambda_function.html.markdown +++ b/website/docs/r/lambda_function.html.markdown @@ -234,7 +234,7 @@ large files efficiently. * `tags` - (Optional) A map of tags to assign to the object. * `file_system_config` - (Optional) The connection settings for an EFS file system. Fields documented below. Before creating or updating Lambda functions with `file_system_config`, EFS mount targets much be in available lifecycle state. Use `depends_on` to explicitly declare this dependency. See [Using Amazon EFS with Lambda][12]. * `code_signing_config_arn` - (Optional) Amazon Resource Name (ARN) for a Code Signing Configuration. -* `image_config` - (Optional) The Lambda OCI image configurations. Fields documented below. +* `image_config` - (Optional) The Lambda OCI image configurations. Fields documented below. See [Lambda Support for Container Images](13) **dead_letter_config** is a child block with a single argument: @@ -301,6 +301,7 @@ In addition to all arguments above, the following attributes are exported: [10]: https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html [11]: https://learn.hashicorp.com/terraform/aws/lambda-api-gateway [12]: https://docs.aws.amazon.com/lambda/latest/dg/services-efs.html +[13]: https://docs.aws.amazon.com/lambda/latest/dg/lambda-images.html ## Timeouts From 383064cf772ab38bda28eeb6022e598cf4c6a3ce Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Wed, 2 Dec 2020 00:15:06 +0800 Subject: [PATCH 09/15] Add CustomizeDiff to validate handler and runtime for zip type lambda functions --- aws/resource_aws_lambda_function.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index ec83e4a0e6b..911a8069499 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "io/ioutil" "log" "regexp" @@ -315,10 +316,24 @@ func resourceAwsLambdaFunction() *schema.Resource { "tags": tagsSchema(), }, - CustomizeDiff: updateComputedAttributesOnPublish, + CustomizeDiff: customdiff.Sequence( + checkHandlerRuntimeForZipFunction, + updateComputedAttributesOnPublish, + ), } } +func checkHandlerRuntimeForZipFunction(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { + packageType := d.Get("package_type") + _, handlerOk := d.GetOk("handler") + _, runtimeOk := d.GetOk("runtime") + + if packageType == lambda.PackageTypeZip && !handlerOk && !runtimeOk { + return fmt.Errorf("handler and runtime must be set when PackageType is Zip") + } + return nil +} + func updateComputedAttributesOnPublish(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { configChanged := hasConfigChanges(d) functionCodeUpdated := needsFunctionCodeUpdate(d) From 270c9601dcf71aa1c467690e83edfd31db84c87f Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Wed, 2 Dec 2020 02:27:41 +0800 Subject: [PATCH 10/15] fix link to lambda doc --- website/docs/r/lambda_function.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lambda_function.html.markdown b/website/docs/r/lambda_function.html.markdown index aca2e8c5719..2415385ad2e 100644 --- a/website/docs/r/lambda_function.html.markdown +++ b/website/docs/r/lambda_function.html.markdown @@ -234,7 +234,7 @@ large files efficiently. * `tags` - (Optional) A map of tags to assign to the object. * `file_system_config` - (Optional) The connection settings for an EFS file system. Fields documented below. Before creating or updating Lambda functions with `file_system_config`, EFS mount targets much be in available lifecycle state. Use `depends_on` to explicitly declare this dependency. See [Using Amazon EFS with Lambda][12]. * `code_signing_config_arn` - (Optional) Amazon Resource Name (ARN) for a Code Signing Configuration. -* `image_config` - (Optional) The Lambda OCI image configurations. Fields documented below. See [Lambda Support for Container Images](13) +* `image_config` - (Optional) The Lambda OCI image configurations. Fields documented below. See [Lambda Support for Container Images][13] **dead_letter_config** is a child block with a single argument: From 4f23b1bb1527cd0dbfa727eb6fbc01bd0142d358 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Wed, 2 Dec 2020 02:29:18 +0800 Subject: [PATCH 11/15] update description for the link to lambda doc --- website/docs/r/lambda_function.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lambda_function.html.markdown b/website/docs/r/lambda_function.html.markdown index 2415385ad2e..2fd39b66558 100644 --- a/website/docs/r/lambda_function.html.markdown +++ b/website/docs/r/lambda_function.html.markdown @@ -234,7 +234,7 @@ large files efficiently. * `tags` - (Optional) A map of tags to assign to the object. * `file_system_config` - (Optional) The connection settings for an EFS file system. Fields documented below. Before creating or updating Lambda functions with `file_system_config`, EFS mount targets much be in available lifecycle state. Use `depends_on` to explicitly declare this dependency. See [Using Amazon EFS with Lambda][12]. * `code_signing_config_arn` - (Optional) Amazon Resource Name (ARN) for a Code Signing Configuration. -* `image_config` - (Optional) The Lambda OCI image configurations. Fields documented below. See [Lambda Support for Container Images][13] +* `image_config` - (Optional) The Lambda OCI image configurations. Fields documented below. See [Using container images with Lambda][13] **dead_letter_config** is a child block with a single argument: From 58a86d0644bf808af4c0e299f302911c817c3520 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Wed, 2 Dec 2020 03:44:00 +0800 Subject: [PATCH 12/15] fetch lambda image ids from environment variables. --- aws/resource_aws_lambda_function_test.go | 39 ++++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index b020caedcef..7c34dc4590c 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -865,10 +865,20 @@ func TestAccAWSLambdaFunction_FileSystemConfig(t *testing.T) { }) } +func testAccLambdaImagePreCheck(t *testing.T) { + if (os.Getenv("AWS_LAMBDA_IMAGE_LATEST_ID") == "") || (os.Getenv("AWS_LAMBDA_IMAGE_V1_ID") == "") || (os.Getenv("AWS_LAMBDA_IMAGE_V2_ID") == "") { + t.Skip("AWS_LAMBDA_IMAGE_LATEST_ID, AWS_LAMBDA_IMAGE_V1_ID and AWS_LAMBDA_IMAGE_V2_ID env vars must be set for Lambda Container Image Support acceptance tests. ") + } +} + func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { var conf lambda.GetFunctionOutput resourceName := "aws_lambda_function.test" + imageLatestID := os.Getenv("AWS_LAMBDA_IMAGE_LATEST_ID") + imageV1ID := os.Getenv("AWS_LAMBDA_IMAGE_V1_ID") + imageV2ID := os.Getenv("AWS_LAMBDA_IMAGE_V2_ID") + rString := acctest.RandString(8) funcName := fmt.Sprintf("tf_acc_lambda_func_basic_%s", rString) policyName := fmt.Sprintf("tf_acc_policy_lambda_func_basic_%s", rString) @@ -876,13 +886,16 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { sgName := fmt.Sprintf("tf_acc_sg_lambda_func_basic_%s", rString) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccLambdaImagePreCheck(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckLambdaFunctionDestroy, Steps: []resource.TestStep{ // Ensure a function with lambda image configuration can be created { - Config: testAccAWSLambdaImageConfig(funcName, policyName, roleName, sgName), + Config: testAccAWSLambdaImageConfig(funcName, policyName, roleName, sgName, imageLatestID), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), testAccCheckAwsLambdaFunctionName(&conf, funcName), @@ -905,7 +918,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { }, // Ensure lambda image code can be updated { - Config: testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName), + Config: testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName, imageV1ID), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:v1$")), @@ -913,7 +926,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { }, // Ensure lambda image config can be updated { - Config: testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName), + Config: testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName, imageV2ID), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:v2$")), @@ -2446,10 +2459,10 @@ resource "aws_lambda_function" "test" { `, funcName) } -func testAccAWSLambdaImageConfig(funcName, policyName, roleName, sgName string) string { +func testAccAWSLambdaImageConfig(funcName, policyName, roleName, sgName, imageID string) string { return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` resource "aws_lambda_function" "test" { - image_uri = "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:latest" + image_uri = "%s" function_name = "%s" role = aws_iam_role.iam_for_lambda.arn package_type = "Image" @@ -2459,24 +2472,24 @@ resource "aws_lambda_function" "test" { working_directory = "/var/task" } } -`, funcName) +`, imageID, funcName) } -func testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName string) string { +func testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName, imageID string) string { return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` resource "aws_lambda_function" "test" { - image_uri = "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v1" + image_uri = "%s" function_name = "%s" role = aws_iam_role.iam_for_lambda.arn package_type = "Image" } -`, funcName) +`, imageID, funcName) } -func testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName string) string { +func testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName, imageID string) string { return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` resource "aws_lambda_function" "test" { - image_uri = "373534280245.dkr.ecr.sa-east-1.amazonaws.com/lambda-image-function:v2" + image_uri = "%s" function_name = "%s" role = aws_iam_role.iam_for_lambda.arn package_type = "Image" @@ -2484,7 +2497,7 @@ resource "aws_lambda_function" "test" { command = ["app.another_handler"] } } -`, funcName) +`, imageID, funcName) } func testAccAWSLambdaConfigVersionedNodeJs10xRuntime(fileName, funcName, policyName, roleName, sgName string) string { From 44bd1846d9bb30077b38899f2a8501852301e2dd Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Wed, 2 Dec 2020 04:34:21 +0800 Subject: [PATCH 13/15] fix formatting --- aws/resource_aws_lambda_function_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index 7c34dc4590c..78b9c255b6e 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -2467,8 +2467,8 @@ resource "aws_lambda_function" "test" { role = aws_iam_role.iam_for_lambda.arn package_type = "Image" image_config { - entry_point = ["/bootstrap-with-handler"] - command = ["app.lambda_handler"] + entry_point = ["/bootstrap-with-handler"] + command = ["app.lambda_handler"] working_directory = "/var/task" } } From 6b9f1f70a4159dde6da651eafca90a5b19b80f36 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Wed, 2 Dec 2020 04:49:36 +0800 Subject: [PATCH 14/15] update import order --- aws/resource_aws_lambda_function.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 911a8069499..ee298898dff 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "io/ioutil" "log" "regexp" @@ -15,6 +14,7 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/lambda" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" From eba45145c4d1d996ae98bb2a6c65d16571ee408c Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Wed, 2 Dec 2020 05:03:16 +0800 Subject: [PATCH 15/15] update test cases --- aws/resource_aws_lambda_function_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index 78b9c255b6e..a2c9e2c0936 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -348,7 +348,7 @@ func TestAccAWSLambdaFunction_expectFilenameAndS3Attributes(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSLambdaConfigWithoutFilenameAndS3Attributes(funcName, policyName, roleName, sgName), - ExpectError: regexp.MustCompile(`filename or s3_\* attributes must be set`), + ExpectError: regexp.MustCompile(`filename, s3_\* or image_uri attributes must be set`), }, }, }) @@ -902,8 +902,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { testAccCheckResourceAttrRegionalARN(resourceName, "arn", "lambda", fmt.Sprintf("function:%s", funcName)), testAccCheckAwsLambdaFunctionInvokeArn(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "package_type", lambda.PackageTypeImage), - resource.TestCheckResourceAttrSet(resourceName, "image_uri"), - resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:latest$")), + resource.TestCheckResourceAttr(resourceName, "image_uri", imageLatestID), resource.TestCheckResourceAttr(resourceName, "image_config.0.entry_point.0", "/bootstrap-with-handler"), resource.TestCheckResourceAttr(resourceName, "image_config.0.command.0", "app.lambda_handler"), resource.TestCheckResourceAttr(resourceName, "image_config.0.working_directory", "/var/task"), @@ -921,7 +920,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Config: testAccAWSLambdaImageConfigUpdateCode(funcName, policyName, roleName, sgName, imageV1ID), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), - resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:v1$")), + resource.TestCheckResourceAttr(resourceName, "image_uri", imageV1ID), ), }, // Ensure lambda image config can be updated @@ -929,7 +928,7 @@ func TestAccAWSLambdaFunction_imageConfig(t *testing.T) { Config: testAccAWSLambdaImageConfigUpdateConfig(funcName, policyName, roleName, sgName, imageV2ID), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), - resource.TestMatchResourceAttr(resourceName, "image_uri", regexp.MustCompile("lambda-image-function:v2$")), + resource.TestCheckResourceAttr(resourceName, "image_uri", imageV2ID), resource.TestCheckResourceAttr(resourceName, "image_config.0.command.0", "app.another_handler"), ), },