Skip to content

Commit

Permalink
r/lambda_layer_version: Add Lambda Layer Version resource
Browse files Browse the repository at this point in the history
  • Loading branch information
acburdine committed Jan 12, 2019
1 parent 6e8d594 commit d57edca
Show file tree
Hide file tree
Showing 6 changed files with 723 additions and 19 deletions.
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ func Provider() terraform.ResourceProvider {
"aws_lambda_event_source_mapping": resourceAwsLambdaEventSourceMapping(),
"aws_lambda_alias": resourceAwsLambdaAlias(),
"aws_lambda_permission": resourceAwsLambdaPermission(),
"aws_lambda_layer_version": resourceAwsLambdaLayerVersion(),
"aws_launch_configuration": resourceAwsLaunchConfiguration(),
"aws_launch_template": resourceAwsLaunchTemplate(),
"aws_licensemanager_association": resourceAwsLicenseManagerAssociation(),
Expand Down
40 changes: 21 additions & 19 deletions aws/resource_aws_lambda_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ import (

const awsMutexLambdaKey = `aws_lambda_function`

var validLambdaRuntimes = []string{
// lambda.RuntimeNodejs has reached end of life since October 2016 so not included here
lambda.RuntimeDotnetcore10,
lambda.RuntimeDotnetcore20,
lambda.RuntimeDotnetcore21,
lambda.RuntimeGo1X,
lambda.RuntimeJava8,
lambda.RuntimeNodejs43,
lambda.RuntimeNodejs43Edge,
lambda.RuntimeNodejs610,
lambda.RuntimeNodejs810,
lambda.RuntimeProvided,
lambda.RuntimePython27,
lambda.RuntimePython36,
lambda.RuntimePython37,
lambda.RuntimeRuby25,
}

func resourceAwsLambdaFunction() *schema.Resource {
return &schema.Resource{
Create: resourceAwsLambdaFunctionCreate,
Expand Down Expand Up @@ -101,25 +119,9 @@ func resourceAwsLambdaFunction() *schema.Resource {
Required: true,
},
"runtime": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
// lambda.RuntimeNodejs has reached end of life since October 2016 so not included here
lambda.RuntimeDotnetcore10,
lambda.RuntimeDotnetcore20,
lambda.RuntimeDotnetcore21,
lambda.RuntimeGo1X,
lambda.RuntimeJava8,
lambda.RuntimeNodejs43,
lambda.RuntimeNodejs43Edge,
lambda.RuntimeNodejs610,
lambda.RuntimeNodejs810,
lambda.RuntimeProvided,
lambda.RuntimePython27,
lambda.RuntimePython36,
lambda.RuntimePython37,
lambda.RuntimeRuby25,
}, false),
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(validLambdaRuntimes, false),
},
"timeout": {
Type: schema.TypeInt,
Expand Down
261 changes: 261 additions & 0 deletions aws/resource_aws_lambda_layer_version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
package aws

import (
"errors"
"fmt"
"log"
"strconv"
"strings"

"github.com/aws/aws-sdk-go/aws"
arn2 "github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/lambda"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

const awsMutexLambdaLayerKey = `aws_lambda_layer_version`

func resourceAwsLambdaLayerVersion() *schema.Resource {
return &schema.Resource{
Create: resourceAwsLambdaLayerVersionPublish,
Read: resourceAwsLambdaLayerVersionRead,
Delete: resourceAwsLambdaLayerVersionDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"layer_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"filename": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"s3_bucket", "s3_key", "s3_object_version"},
},
"s3_bucket": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"filename"},
},
"s3_key": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"filename"},
},
"s3_object_version": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"filename"},
},
"compatible_runtimes": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
MinItems: 0,
MaxItems: 5,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(validLambdaRuntimes, false),
},
},
"description": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"license_info": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(0, 512),
},

"arn": {
Type: schema.TypeString,
Computed: true,
},
"layer_arn": {
Type: schema.TypeString,
Computed: true,
},
"created_date": {
Type: schema.TypeString,
Computed: true,
},
"source_code_hash": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},
"source_code_size": {
Type: schema.TypeInt,
Computed: true,
},
"version": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAwsLambdaLayerVersionPublish(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).lambdaconn

layerName := d.Get("layer_name").(string)
filename, hasFilename := d.GetOk("filename")
s3Bucket, bucketOk := d.GetOk("s3_bucket")
s3Key, keyOk := d.GetOk("s3_key")
s3ObjectVersion, versionOk := d.GetOk("s3_object_version")

if !hasFilename && !bucketOk && !keyOk && !versionOk {
return errors.New("filename or s3_* attributes must be set")
}

var layerContent *lambda.LayerVersionContentInput
if hasFilename {
awsMutexKV.Lock(awsMutexLambdaLayerKey)
defer awsMutexKV.Unlock(awsMutexLambdaLayerKey)
file, err := loadFileContent(filename.(string))
if err != nil {
return fmt.Errorf("Unable to load %q: %s", filename.(string), err)
}
layerContent = &lambda.LayerVersionContentInput{
ZipFile: file,
}
} else {
if !bucketOk || !keyOk {
return errors.New("s3_bucket and s3_key must all be set while using s3 code source")
}
layerContent = &lambda.LayerVersionContentInput{
S3Bucket: aws.String(s3Bucket.(string)),
S3Key: aws.String(s3Key.(string)),
}
if versionOk {
layerContent.S3ObjectVersion = aws.String(s3ObjectVersion.(string))
}
}

params := &lambda.PublishLayerVersionInput{
Content: layerContent,
Description: aws.String(d.Get("description").(string)),
LayerName: aws.String(layerName),
LicenseInfo: aws.String(d.Get("license_info").(string)),
}

if v, ok := d.GetOk("compatible_runtimes"); ok && v.(*schema.Set).Len() > 0 {
params.CompatibleRuntimes = expandStringList(v.(*schema.Set).List())
}

log.Printf("[DEBUG] Publishing Lambda layer: %s", params)
result, err := conn.PublishLayerVersion(params)
if err != nil {
return fmt.Errorf("Error creating lambda layer: %s", err)
}

d.SetId(aws.StringValue(result.LayerVersionArn))
return resourceAwsLambdaLayerVersionRead(d, meta)
}

func resourceAwsLambdaLayerVersionRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).lambdaconn

layerName, version, err := resourceAwsLambdaLayerVersionParseId(d.Id())
if err != nil {
return fmt.Errorf("Error parsing lambda layer ID: %s", err)
}

layerVersion, err := conn.GetLayerVersion(&lambda.GetLayerVersionInput{
LayerName: aws.String(layerName),
VersionNumber: aws.Int64(version),
})

if isAWSErr(err, lambda.ErrCodeResourceNotFoundException, "") {
log.Printf("[WARN] Lambda Layer Version (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading Lambda Layer version (%s): %s", d.Id(), err)
}

if err := d.Set("layer_name", layerName); err != nil {
return fmt.Errorf("Error setting lambda layer name: %s", err)
}
if err := d.Set("version", strconv.FormatInt(version, 10)); err != nil {
return fmt.Errorf("Error setting lambda layer version: %s", err)
}
if err := d.Set("arn", layerVersion.LayerArn); err != nil {
return fmt.Errorf("Error setting lambda layer arn: %s", err)
}
if err := d.Set("layer_arn", layerVersion.LayerVersionArn); err != nil {
return fmt.Errorf("Error setting lambda layer qualified arn: %s", err)
}
if err := d.Set("description", layerVersion.Description); err != nil {
return fmt.Errorf("Error setting lambda layer description: %s", err)
}
if err := d.Set("license_info", layerVersion.LicenseInfo); err != nil {
return fmt.Errorf("Error setting lambda layer license info: %s", err)
}
if err := d.Set("created_date", layerVersion.CreatedDate); err != nil {
return fmt.Errorf("Error setting lambda layer created date: %s", err)
}
if err := d.Set("source_code_hash", layerVersion.Content.CodeSha256); err != nil {
return fmt.Errorf("Error setting lambda layer source code hash: %s", err)
}
if err := d.Set("source_code_size", layerVersion.Content.CodeSize); err != nil {
return fmt.Errorf("Error setting lambda layer source code size: %s", err)
}
if err := d.Set("compatible_runtimes", flattenStringList(layerVersion.CompatibleRuntimes)); err != nil {
return fmt.Errorf("Error setting lambda layer compatible runtimes: %s", err)
}

return nil
}

func resourceAwsLambdaLayerVersionDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).lambdaconn

version, err := strconv.ParseInt(d.Get("version").(string), 10, 64)
if err != nil {
return fmt.Errorf("Error parsing lambda layer version: %s", err)
}

_, err = conn.DeleteLayerVersion(&lambda.DeleteLayerVersionInput{
LayerName: aws.String(d.Get("layer_name").(string)),
VersionNumber: aws.Int64(version),
})
if err != nil {
return fmt.Errorf("error deleting Lambda Layer Version (%s): %s", d.Id(), err)
}

log.Printf("[DEBUG] Lambda layer %q deleted", d.Get("arn").(string))
return nil
}

func resourceAwsLambdaLayerVersionParseId(id string) (layerName string, version int64, err error) {
arn, err := arn2.Parse(id)
if err != nil {
return
}
parts := strings.Split(arn.Resource, ":")
if len(parts) != 3 || parts[0] != "layer" {
err = fmt.Errorf("lambda_layer ID must be a valid Layer ARN")
return
}

layerName = parts[1]
version, err = strconv.ParseInt(parts[2], 10, 64)
return
}
Loading

0 comments on commit d57edca

Please sign in to comment.