@@ -14,6 +14,7 @@ import (
1414 "github.com/aws/aws-sdk-go/aws/awserr"
1515 "github.com/aws/aws-sdk-go/aws/endpoints"
1616 "github.com/aws/aws-sdk-go/service/lambda"
17+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
1718 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1819 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1920 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -47,22 +48,57 @@ func resourceAwsLambdaFunction() *schema.Resource {
4748 "filename" : {
4849 Type : schema .TypeString ,
4950 Optional : true ,
50- ConflictsWith : []string {"s3_bucket" , "s3_key" , "s3_object_version" },
51+ ConflictsWith : []string {"s3_bucket" , "s3_key" , "s3_object_version" , "image_uri" },
5152 },
5253 "s3_bucket" : {
5354 Type : schema .TypeString ,
5455 Optional : true ,
55- ConflictsWith : []string {"filename" },
56+ ConflictsWith : []string {"filename" , "image_uri" },
5657 },
5758 "s3_key" : {
5859 Type : schema .TypeString ,
5960 Optional : true ,
60- ConflictsWith : []string {"filename" },
61+ ConflictsWith : []string {"filename" , "image_uri" },
6162 },
6263 "s3_object_version" : {
6364 Type : schema .TypeString ,
6465 Optional : true ,
65- ConflictsWith : []string {"filename" },
66+ ConflictsWith : []string {"filename" , "image_uri" },
67+ },
68+ "image_uri" : {
69+ Type : schema .TypeString ,
70+ Optional : true ,
71+ ConflictsWith : []string {"filename" , "s3_bucket" , "s3_key" , "s3_object_version" },
72+ },
73+ "package_type" : {
74+ Type : schema .TypeString ,
75+ Optional : true ,
76+ ForceNew : true ,
77+ Default : lambda .PackageTypeZip ,
78+ ValidateFunc : validation .StringInSlice (lambda .PackageType_Values (), false ),
79+ },
80+ "image_config" : {
81+ Type : schema .TypeList ,
82+ Optional : true ,
83+ MaxItems : 1 ,
84+ Elem : & schema.Resource {
85+ Schema : map [string ]* schema.Schema {
86+ "entry_point" : {
87+ Type : schema .TypeList ,
88+ Optional : true ,
89+ Elem : & schema.Schema {Type : schema .TypeString },
90+ },
91+ "command" : {
92+ Type : schema .TypeList ,
93+ Optional : true ,
94+ Elem : & schema.Schema {Type : schema .TypeString },
95+ },
96+ "working_directory" : {
97+ Type : schema .TypeString ,
98+ Optional : true ,
99+ },
100+ },
101+ },
66102 },
67103 "code_signing_config_arn" : {
68104 Type : schema .TypeString ,
@@ -126,7 +162,7 @@ func resourceAwsLambdaFunction() *schema.Resource {
126162 },
127163 "handler" : {
128164 Type : schema .TypeString ,
129- Required : true ,
165+ Optional : true ,
130166 ValidateFunc : validation .StringLenBetween (1 , 128 ),
131167 },
132168 "layers" : {
@@ -155,7 +191,7 @@ func resourceAwsLambdaFunction() *schema.Resource {
155191 },
156192 "runtime" : {
157193 Type : schema .TypeString ,
158- Required : true ,
194+ Optional : true ,
159195 ValidateFunc : validation .StringInSlice (lambda .Runtime_Values (), false ),
160196 },
161197 "timeout" : {
@@ -280,10 +316,24 @@ func resourceAwsLambdaFunction() *schema.Resource {
280316 "tags" : tagsSchema (),
281317 },
282318
283- CustomizeDiff : updateComputedAttributesOnPublish ,
319+ CustomizeDiff : customdiff .Sequence (
320+ checkHandlerRuntimeForZipFunction ,
321+ updateComputedAttributesOnPublish ,
322+ ),
284323 }
285324}
286325
326+ func checkHandlerRuntimeForZipFunction (_ context.Context , d * schema.ResourceDiff , meta interface {}) error {
327+ packageType := d .Get ("package_type" )
328+ _ , handlerOk := d .GetOk ("handler" )
329+ _ , runtimeOk := d .GetOk ("runtime" )
330+
331+ if packageType == lambda .PackageTypeZip && ! handlerOk && ! runtimeOk {
332+ return fmt .Errorf ("handler and runtime must be set when PackageType is Zip" )
333+ }
334+ return nil
335+ }
336+
287337func updateComputedAttributesOnPublish (_ context.Context , d * schema.ResourceDiff , meta interface {}) error {
288338 configChanged := hasConfigChanges (d )
289339 functionCodeUpdated := needsFunctionCodeUpdate (d )
@@ -304,6 +354,7 @@ func hasConfigChanges(d resourceDiffer) bool {
304354 return d .HasChange ("description" ) ||
305355 d .HasChange ("handler" ) ||
306356 d .HasChange ("file_system_config" ) ||
357+ d .HasChange ("image_config" ) ||
307358 d .HasChange ("memory_size" ) ||
308359 d .HasChange ("role" ) ||
309360 d .HasChange ("timeout" ) ||
@@ -331,9 +382,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e
331382 s3Bucket , bucketOk := d .GetOk ("s3_bucket" )
332383 s3Key , keyOk := d .GetOk ("s3_key" )
333384 s3ObjectVersion , versionOk := d .GetOk ("s3_object_version" )
385+ imageUri , hasImageUri := d .GetOk ("image_uri" )
334386
335- if ! hasFilename && ! bucketOk && ! keyOk && ! versionOk {
336- return errors .New ("filename or s3_* attributes must be set" )
387+ if ! hasFilename && ! bucketOk && ! keyOk && ! versionOk && ! hasImageUri {
388+ return errors .New ("filename, s3_* or image_uri attributes must be set" )
337389 }
338390
339391 var functionCode * lambda.FunctionCode
@@ -350,6 +402,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e
350402 functionCode = & lambda.FunctionCode {
351403 ZipFile : file ,
352404 }
405+ } else if hasImageUri {
406+ functionCode = & lambda.FunctionCode {
407+ ImageUri : aws .String (imageUri .(string )),
408+ }
353409 } else {
354410 if ! bucketOk || ! keyOk {
355411 return errors .New ("s3_bucket and s3_key must all be set while using S3 code source" )
@@ -363,16 +419,28 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e
363419 }
364420 }
365421
422+ packageType := d .Get ("package_type" )
423+ handler , handlerOk := d .GetOk ("handler" )
424+ runtime , runtimeOk := d .GetOk ("runtime" )
425+
426+ if packageType == lambda .PackageTypeZip && ! handlerOk && ! runtimeOk {
427+ return errors .New ("handler and runtime must be set when PackageType is Zip" )
428+ }
429+
366430 params := & lambda.CreateFunctionInput {
367431 Code : functionCode ,
368432 Description : aws .String (d .Get ("description" ).(string )),
369433 FunctionName : aws .String (functionName ),
370- Handler : aws .String (d .Get ("handler" ).(string )),
371434 MemorySize : aws .Int64 (int64 (d .Get ("memory_size" ).(int ))),
372435 Role : aws .String (iamRole ),
373- Runtime : aws .String (d .Get ("runtime" ).(string )),
374436 Timeout : aws .Int64 (int64 (d .Get ("timeout" ).(int ))),
375437 Publish : aws .Bool (d .Get ("publish" ).(bool )),
438+ PackageType : aws .String (d .Get ("package_type" ).(string )),
439+ }
440+
441+ if packageType == lambda .PackageTypeZip {
442+ params .Handler = aws .String (handler .(string ))
443+ params .Runtime = aws .String (runtime .(string ))
376444 }
377445
378446 if v , ok := d .GetOk ("code_signing_config_arn" ); ok {
@@ -401,6 +469,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e
401469 params .FileSystemConfigs = expandLambdaFileSystemConfigs (v .([]interface {}))
402470 }
403471
472+ if v , ok := d .GetOk ("image_config" ); ok && len (v .([]interface {})) > 0 {
473+ params .ImageConfig = expandLambdaImageConfigs (v .([]interface {}))
474+ }
475+
404476 if v , ok := d .GetOk ("vpc_config" ); ok && len (v .([]interface {})) > 0 {
405477 config := v .([]interface {})[0 ].(map [string ]interface {})
406478
@@ -641,6 +713,23 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err
641713 return fmt .Errorf ("Error setting file system config for Lambda Function (%s): %w" , d .Id (), err )
642714 }
643715
716+ // Add Package Type
717+ log .Printf ("[INFO] Setting Lambda %s package type %#v from API" , d .Id (), function .PackageType )
718+ if err := d .Set ("package_type" , function .PackageType ); err != nil {
719+ return fmt .Errorf ("Error setting package type for Lambda Function: %w" , err )
720+ }
721+
722+ // Add Image Configuration
723+ imageConfig := flattenLambdaImageConfig (function .ImageConfigResponse )
724+ log .Printf ("[INFO] Setting Lambda %s Image config %#v from API" , d .Id (), imageConfig )
725+ if err := d .Set ("image_config" , imageConfig ); err != nil {
726+ return fmt .Errorf ("Error setting image config for Lambda Function: %s" , err )
727+ }
728+
729+ if err := d .Set ("image_uri" , getFunctionOutput .Code .ImageUri ); err != nil {
730+ return fmt .Errorf ("Error setting image uri for Lambda Function: %s" , err )
731+ }
732+
644733 layers := flattenLambdaLayers (function .Layers )
645734 log .Printf ("[INFO] Setting Lambda %s Layers %#v from API" , d .Id (), layers )
646735 if err := d .Set ("layers" , layers ); err != nil {
@@ -723,15 +812,20 @@ func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) err
723812 FunctionName : aws .String (d .Get ("function_name" ).(string )),
724813 }
725814
726- getCodeSigningConfigOutput , err := conn .GetFunctionCodeSigningConfig (codeSigningConfigInput )
727- if err != nil {
728- return fmt .Errorf ("error getting Lambda Function (%s) code signing config %w" , d .Id (), err )
729- }
815+ // Code Signing is only supported on zip packaged lambda functions.
816+ if * function .PackageType == lambda .PackageTypeZip {
817+ getCodeSigningConfigOutput , err := conn .GetFunctionCodeSigningConfig (codeSigningConfigInput )
818+ if err != nil {
819+ return fmt .Errorf ("error getting Lambda Function (%s) code signing config %w" , d .Id (), err )
820+ }
730821
731- if getCodeSigningConfigOutput == nil || getCodeSigningConfigOutput .CodeSigningConfigArn == nil {
732- d .Set ("code_signing_config_arn" , "" )
822+ if getCodeSigningConfigOutput == nil || getCodeSigningConfigOutput .CodeSigningConfigArn == nil {
823+ d .Set ("code_signing_config_arn" , "" )
824+ } else {
825+ d .Set ("code_signing_config_arn" , getCodeSigningConfigOutput .CodeSigningConfigArn )
826+ }
733827 } else {
734- d .Set ("code_signing_config_arn" , getCodeSigningConfigOutput . CodeSigningConfigArn )
828+ d .Set ("code_signing_config_arn" , "" )
735829 }
736830
737831 return nil
@@ -779,7 +873,9 @@ func needsFunctionCodeUpdate(d resourceDiffer) bool {
779873 d .HasChange ("source_code_hash" ) ||
780874 d .HasChange ("s3_bucket" ) ||
781875 d .HasChange ("s3_key" ) ||
782- d .HasChange ("s3_object_version" )
876+ d .HasChange ("s3_object_version" ) ||
877+ d .HasChange ("image_uri" )
878+
783879}
784880
785881// resourceAwsLambdaFunctionUpdate maps to:
@@ -840,6 +936,12 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e
840936 configReq .FileSystemConfigs = expandLambdaFileSystemConfigs (v .([]interface {}))
841937 }
842938 }
939+ if d .HasChange ("image_config" ) {
940+ configReq .ImageConfig = & lambda.ImageConfig {}
941+ if v , ok := d .GetOk ("image_config" ); ok && len (v .([]interface {})) > 0 {
942+ configReq .ImageConfig = expandLambdaImageConfigs (v .([]interface {}))
943+ }
944+ }
843945 if d .HasChange ("memory_size" ) {
844946 configReq .MemorySize = aws .Int64 (int64 (d .Get ("memory_size" ).(int )))
845947 }
@@ -990,6 +1092,8 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e
9901092 return fmt .Errorf ("Unable to load %q: %w" , v .(string ), err )
9911093 }
9921094 codeReq .ZipFile = file
1095+ } else if v , ok := d .GetOk ("image_uri" ); ok {
1096+ codeReq .ImageUri = aws .String (v .(string ))
9931097 } else {
9941098 s3Bucket , _ := d .GetOk ("s3_bucket" )
9951099 s3Key , _ := d .GetOk ("s3_key" )
@@ -1188,3 +1292,33 @@ func expandLambdaFileSystemConfigs(fscMaps []interface{}) []*lambda.FileSystemCo
11881292 }
11891293 return fileSystemConfigs
11901294}
1295+
1296+ func flattenLambdaImageConfig (response * lambda.ImageConfigResponse ) []map [string ]interface {} {
1297+ settings := make (map [string ]interface {})
1298+
1299+ if response == nil || response .Error != nil {
1300+ return nil
1301+ }
1302+
1303+ settings ["command" ] = response .ImageConfig .Command
1304+ settings ["entry_point" ] = response .ImageConfig .EntryPoint
1305+ settings ["working_directory" ] = response .ImageConfig .WorkingDirectory
1306+
1307+ return []map [string ]interface {}{settings }
1308+ }
1309+
1310+ func expandLambdaImageConfigs (imageConfigMaps []interface {}) * lambda.ImageConfig {
1311+ imageConfig := & lambda.ImageConfig {}
1312+ // only one image_config block is allowed
1313+ if len (imageConfigMaps ) == 1 && imageConfigMaps [0 ] != nil {
1314+ config := imageConfigMaps [0 ].(map [string ]interface {})
1315+ if len (config ["entry_point" ].([]interface {})) > 0 {
1316+ imageConfig .EntryPoint = expandStringList (config ["entry_point" ].([]interface {}))
1317+ }
1318+ if len (config ["command" ].([]interface {})) > 0 {
1319+ imageConfig .Command = expandStringList (config ["command" ].([]interface {}))
1320+ }
1321+ imageConfig .WorkingDirectory = aws .String (config ["working_directory" ].(string ))
1322+ }
1323+ return imageConfig
1324+ }
0 commit comments