Skip to content

Commit

Permalink
feat(lambda)!: create lambda from a container image (#105)
Browse files Browse the repository at this point in the history
* feat(lambda): added image input

This reverts commit 746c740.

* ci: lambda requires aws provider 3.19

* fix(lambda): set aws_lambda_function package_type

* ci: lambda requires aws provider 3.19

* fix(lambda): don't pass layers, handler or runtime when using a container image

* refactor(lambda): add vpc_config block only when needed

minimizes the impact of hashicorp/terraform-provider-aws#15952

* feat(lambda): added publish variable

so you can disable publishing versions, eg. as a workaround for the perpetual diff problem

* feat(rds/postgres/management_lambda): disabled lambda version publishing

as a workaround for the perpetual diff problem

* docs: example lambdas should no longer be affected by perpetual diffs
  • Loading branch information
mskrajnowski committed Jun 10, 2021
1 parent 67f8ba9 commit ccabfcf
Show file tree
Hide file tree
Showing 14 changed files with 68 additions and 40 deletions.
3 changes: 0 additions & 3 deletions cloudfront/examples/basic/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "us-east-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

# 1. Setup a cloudfront origin, eg. an S3 bucket with some objects
Expand Down
3 changes: 0 additions & 3 deletions cloudfront/examples/basic_auth/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "us-east-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

# 1. Setup a cloudfront origin, eg. an S3 bucket with some objects
Expand Down
3 changes: 0 additions & 3 deletions cloudfront/examples/response_headers/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "us-east-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

# 1. Setup a cloudfront origin, eg. an S3 bucket with some objects
Expand Down
3 changes: 0 additions & 3 deletions cloudfront/examples/single_page_app/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "us-east-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

# 1. Setup a cloudfront origin, eg. an S3 bucket with some objects
Expand Down
3 changes: 0 additions & 3 deletions cloudfront/examples/static_website/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "us-east-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

# 1. Setup a cloudfront origin, eg. an S3 bucket with some objects
Expand Down
28 changes: 24 additions & 4 deletions lambda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,36 @@

Creates an AWS Lambda function

## Perpetual `aws_lambda_function` diffs

As reported in https://github.com/hashicorp/terraform-provider-aws/issues/15952, whenever you create a lambda function that both:

- publishes versions on any code/configuration change by specifying `publish = true` (which is the default)
- is placed in a VPC by providing `security_group_ids` and `subnet_ids`

`terraform plan` will always report that the lambda `version` and `qualified_arn` will change, even though neither the lambda source or its configuration changed.

In other words the plan will never be empty and terraform will never show "No changes. Infrastructure is up-to-date."

There's no good workaround for this. You will have to either:

- disable publishing versions with `publish = false` and switch to always using the latest version
- remove the lambda function from the VPC if it's possible to refactor the code so it doesn't have to have access to private subnets

<!-- prettier-ignore-start -->
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.12, <0.14 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 2.40.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.19.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 2.40.0 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 3.19.0 |

## Modules

Expand Down Expand Up @@ -47,13 +64,15 @@ Creates an AWS Lambda function
| <a name="input_files"></a> [files](#input\_files) | **Deprecated. Use the `zip` module and `package_path` input instead.**<br><br> Source code map. Either `files` or `files_dir` has to be specified | `map(string)` | `null` | no |
| <a name="input_files_dir"></a> [files\_dir](#input\_files\_dir) | **Deprecated. Use the `zip` module and `package_path` input instead.**<br><br> Source code directory path. Either `files` or `files_dir` has to be specified | `string` | `null` | no |
| <a name="input_handler"></a> [handler](#input\_handler) | Path to the event handler | `string` | `"index.handler"` | no |
| <a name="input_image"></a> [image](#input\_image) | URI of a container image with the Lambda's source. Either `package_path`, `package_s3` or `image` is required. | `string` | `null` | no |
| <a name="input_layer_qualified_arns"></a> [layer\_qualified\_arns](#input\_layer\_qualified\_arns) | Lambda layers to include | `list(string)` | `[]` | no |
| <a name="input_memory_size"></a> [memory\_size](#input\_memory\_size) | Amount of memory in MB your Lambda Function can use at runtime | `number` | `128` | no |
| <a name="input_name"></a> [name](#input\_name) | Lambda name | `string` | n/a | yes |
| <a name="input_package_path"></a> [package\_path](#input\_package\_path) | Path to the zip that contains the Lambda's source. Either `package_path` or `package_s3` is required. | `string` | `null` | no |
| <a name="input_package_s3"></a> [package\_s3](#input\_package\_s3) | S3 zip object that contains the Lambda's source. Either `package_path` or `package_s3` is required. | <pre>object({<br> bucket = string<br> key = string<br> })</pre> | `null` | no |
| <a name="input_package_path"></a> [package\_path](#input\_package\_path) | Path to the zip that contains the Lambda's source. Either `package_path`, `package_s3` or `image` is required. | `string` | `null` | no |
| <a name="input_package_s3"></a> [package\_s3](#input\_package\_s3) | S3 zip object that contains the Lambda's source. Either `package_path`, `package_s3` or `image` is required. | <pre>object({<br> bucket = string<br> key = string<br> })</pre> | `null` | no |
| <a name="input_package_s3_version"></a> [package\_s3\_version](#input\_package\_s3\_version) | Version number of the S3 object to use | `string` | `null` | no |
| <a name="input_policy_arns"></a> [policy\_arns](#input\_policy\_arns) | Additional policy ARNs to attach to the Lambda role | `map(string)` | `{}` | no |
| <a name="input_publish"></a> [publish](#input\_publish) | Whether to create lambda versions when it's created and on any code or configuration changes.<br>When disabled the only available version will be `$LATEST`. | `bool` | `true` | no |
| <a name="input_runtime"></a> [runtime](#input\_runtime) | [Runtime](https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html#SSS-CreateFunction-request-Runtime) | `string` | `"nodejs12.x"` | no |
| <a name="input_security_group_ids"></a> [security\_group\_ids](#input\_security\_group\_ids) | Security groups to assign | `list(string)` | `null` | no |
| <a name="input_subnet_ids"></a> [subnet\_ids](#input\_subnet\_ids) | Subnet ids to place the lambda in | `list(string)` | `null` | no |
Expand All @@ -72,3 +91,4 @@ Creates an AWS Lambda function
| <a name="output_version"></a> [version](#output\_version) | Latest published version of the Lambda Function |
| <a name="output_widgets"></a> [widgets](#output\_widgets) | Cloudwatch dashboard widgets |
<!-- END_TF_DOCS -->
<!-- prettier-ignore-end -->
3 changes: 0 additions & 3 deletions lambda/examples/basic/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "eu-west-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

# Source code defined in terraform --------------------------------------------
Expand Down
3 changes: 0 additions & 3 deletions lambda/examples/invoke/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "eu-west-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

module "lambda_invoke" {
Expand Down
10 changes: 7 additions & 3 deletions lambda/examples/vpc/main.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
provider "aws" {
region = "eu-west-1"

# https://github.com/hashicorp/terraform-provider-aws/issues/15952
version = "3.12.0"
}

module "vpc" {
Expand Down Expand Up @@ -30,4 +27,11 @@ module "lambda_vpc" {

security_group_ids = [data.aws_security_group.default.id]
subnet_ids = [module.vpc.private_subnet_ids[0]]

# Workaround for https://github.com/hashicorp/terraform-provider-aws/issues/15952
publish = false
}

output "lambda_vpc" {
value = module.lambda_vpc
}
22 changes: 15 additions & 7 deletions lambda/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,19 @@ resource "aws_lambda_function" "lambda" {

function_name = var.name

package_type = var.image != null ? "Image" : "Zip"
image_uri = var.image

filename = local.create_package ? module.package.output_path : var.package_path
s3_bucket = var.package_s3 != null ? var.package_s3.bucket : null
s3_key = var.package_s3 != null ? var.package_s3.key : null
s3_object_version = var.package_s3_version

layers = var.layer_qualified_arns
handler = var.handler
runtime = var.runtime
publish = true
layers = var.image == null ? var.layer_qualified_arns : null
handler = var.image == null ? var.handler : null
runtime = var.image == null ? var.runtime : null

publish = var.publish
timeout = var.timeout
memory_size = var.memory_size
role = aws_iam_role.lambda[0].arn
Expand All @@ -100,9 +104,13 @@ resource "aws_lambda_function" "lambda" {
}
}

vpc_config {
subnet_ids = coalesce(var.subnet_ids, [])
security_group_ids = coalesce(var.security_group_ids, [])
dynamic "vpc_config" {
for_each = toset(var.subnet_ids != null || var.security_group_ids != null ? ["vpc_config"] : [])

content {
subnet_ids = coalesce(var.subnet_ids, [])
security_group_ids = coalesce(var.security_group_ids, [])
}
}

tags = var.tags
Expand Down
18 changes: 16 additions & 2 deletions lambda/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,22 @@ variable "name" {
type = string
}

variable "publish" {
description = <<-EOT
Whether to create lambda versions when it's created and on any code or configuration changes.
When disabled the only available version will be `$LATEST`.
EOT
type = bool
default = true
}
variable "package_path" {
description = "Path to the zip that contains the Lambda's source. Either `package_path` or `package_s3` is required."
description = "Path to the zip that contains the Lambda's source. Either `package_path`, `package_s3` or `image` is required."
type = string
default = null
}

variable "package_s3" {
description = "S3 zip object that contains the Lambda's source. Either `package_path` or `package_s3` is required."
description = "S3 zip object that contains the Lambda's source. Either `package_path`, `package_s3` or `image` is required."
type = object({
bucket = string
key = string
Expand All @@ -36,6 +44,12 @@ variable "package_s3_version" {
default = null
}

variable "image" {
description = "URI of a container image with the Lambda's source. Either `package_path`, `package_s3` or `image` is required."
type = string
default = null
}

variable "files" {
description = <<EOT
**Deprecated. Use the `zip` module and `package_path` input instead.**
Expand Down
2 changes: 1 addition & 1 deletion lambda/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ terraform {
required_version = ">= 0.12, <0.14"

required_providers {
aws = ">= 2.40.0"
aws = ">= 3.19.0"
}
}
4 changes: 4 additions & 0 deletions rds/postgres/management_lambda/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module "lambda" {
name = var.name
tags = var.tags


files_dir = "${path.module}/dist"
handler = "index.handler"
security_group_ids = var.create ? aws_security_group.lambda.*.id : null
Expand All @@ -35,4 +36,7 @@ module "lambda" {
environment_variables = {
DATABASE_URL = var.database_url
}

# Workaround for https://github.com/hashicorp/terraform-provider-aws/issues/15952
publish = false
}
3 changes: 1 addition & 2 deletions versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ terraform {

# Make sure all providers needed by any module are listed
required_providers {
# https://github.com/hashicorp/terraform-provider-aws/issues/15952
aws = "3.12.0"
aws = "3.19.0"

archive = "2.1.0"
null = "3.1.0"
Expand Down

0 comments on commit ccabfcf

Please sign in to comment.