Skip to content

Commit

Permalink
feat: Terraform example (aws-powertools#1478)
Browse files Browse the repository at this point in the history
  • Loading branch information
skal111 authored Oct 23, 2023
1 parent 5e3a4e6 commit 34fc20e
Show file tree
Hide file tree
Showing 14 changed files with 689 additions and 1 deletion.
29 changes: 29 additions & 0 deletions .github/workflows/pr_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ jobs:
env:
JAVA: ${{ matrix.java }}
AWS_REGION: eu-west-1
permissions:
id-token: write # needed to interact with GitHub's OIDC Token endpoint.
contents: read
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Setup java
Expand All @@ -68,6 +71,32 @@ jobs:
run: |
cd examples/powertools-examples-core/gradle
./gradlew build
- name: Setup Terraform
if: ${{ matrix.java == '11' }}
uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 #v2.0.3
- name: Setup AWS credentials
uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
- name: Terraform validate
if: ${{ matrix.java == '11' }}
run: |
terraform -version
cd examples/powertools-examples-core/terraform
terraform init -backend=false
terraform validate
terraform plan
- name: Setup Terraform lint
if: ${{ matrix.java == '11' }}
uses: terraform-linters/setup-tflint@a5a1af8c6551fb10c53f1cd4ba62359f1973746f # v3.1.1
- name: Terraform lint
if: ${{ matrix.java == '11' }}
run: |
tflint --version
cd examples/powertools-examples-core/terraform
tflint --init
tflint -f compact
- name: Upload coverage to Codecov
uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
if: ${{ matrix.java == '11' }} # publish results once
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,6 @@ example/HelloWorldFunction/build
/example/.gradle/
/example/.java-version
.gradle
build/
build/
.terraform*
terraform.tfstate*
1 change: 1 addition & 0 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<module>powertools-examples-core/cdk/app</module>
<module>powertools-examples-core/cdk/infra</module>
<module>powertools-examples-core/serverless</module>
<module>powertools-examples-core/terraform</module>
<module>powertools-examples-idempotency</module>
<module>powertools-examples-parameters</module>
<module>powertools-examples-serialization</module>
Expand Down
1 change: 1 addition & 0 deletions examples/powertools-examples-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ We provide examples for the following infrastructure-as-code tools:
* [AWS SAM](sam/)
* [AWS CDK](cdk/)
* [Serverless framework](serverless/)
* [Terraform](terraform/)

We also provide an example showing the integration of SAM, Powertools, and Gradle:

Expand Down
3 changes: 3 additions & 0 deletions examples/powertools-examples-core/terraform/.tflint.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
rule "terraform_required_version" {
enabled = false
}
27 changes: 27 additions & 0 deletions examples/powertools-examples-core/terraform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Powertools for AWS Lambda (Java) - Core Utilities Example with Terraform

This project demonstrates the Lambda for Powertools Java module deployed using [Terraform](https://www.terraform.io/).
For general information on the deployed example itself, you can refer to the parent [README](../README.md).
To install Terraform if you don't have it yet, you can follow the [Install Terraform Guide](https://developer.hashicorp.com/terraform/downloads?product_intent=terraform).

## Configuration
Terraform uses [main.tf](./main.tf) to define the application's AWS resources.
This file defines the Lambda function to be deployed as well as API Gateway for it.

It is a [Maven](https://maven.apache.org/) based project, so you can open this project with any Maven compatible Java IDE to build and run tests.


## Deploy the sample application

To deploy the app, simply run the following commands:
```bash
terraform init
mvn package && terraform apply
```

## Useful commands

To destroy the app
```bash
terraform destroy
```
94 changes: 94 additions & 0 deletions examples/powertools-examples-core/terraform/infra/api-gateway.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
resource "aws_api_gateway_rest_api" "hello_world_api" {
name = "hello_world_api"
description = "API Gateway endpoint URL for Prod stage for Hello World function"
}

resource "aws_api_gateway_resource" "hello_resource" {
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
parent_id = "${aws_api_gateway_rest_api.hello_world_api.root_resource_id}"
path_part = "hello"
}

resource "aws_api_gateway_resource" "hello_stream_resource" {
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
parent_id = "${aws_api_gateway_rest_api.hello_world_api.root_resource_id}"
path_part = "hellostream"
}

resource "aws_api_gateway_method" "hello_get_method" {
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
resource_id = "${aws_api_gateway_resource.hello_resource.id}"
http_method = "GET"
authorization = "NONE"
}

resource "aws_api_gateway_method" "hello_stream_get_method" {
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
resource_id = "${aws_api_gateway_resource.hello_stream_resource.id}"
http_method = "GET"
authorization = "NONE"
}

resource "aws_api_gateway_integration" "java_lambda_integration" {
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
resource_id = "${aws_api_gateway_resource.hello_resource.id}"
http_method = "${aws_api_gateway_method.hello_get_method.http_method}"

integration_http_method = "POST"
type = "AWS_PROXY"
uri = "${aws_lambda_function.hello_world_lambda.invoke_arn}"
}

resource "aws_api_gateway_integration" "java_stream_lambda_integration" {
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
resource_id = "${aws_api_gateway_resource.hello_stream_resource.id}"
http_method = "${aws_api_gateway_method.hello_stream_get_method.http_method}"

integration_http_method = "POST"
type = "AWS_PROXY"
uri = "${aws_lambda_function.hello_world_stream_lambda.invoke_arn}"
}

resource "aws_api_gateway_deployment" "prod_deployment" {
depends_on = [aws_api_gateway_integration.java_lambda_integration, aws_api_gateway_integration.java_stream_lambda_integration]
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
stage_name = "prod"
}

# Allows API gateway to invoke lambda
resource "aws_lambda_permission" "hello_world_lambda_invoke" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.hello_world_lambda.function_name}"
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/${aws_api_gateway_deployment.prod_deployment.stage_name}/GET/hello"
}

# Allows API gateway to invoke lambda
resource "aws_lambda_permission" "hello_world_lambda_testinvoke" {
statement_id = "AllowAPIGatewayTestInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.hello_world_lambda.function_name}"
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/test-invoke-stage/GET/hello"
}

# Allows API gateway to invoke lambda
resource "aws_lambda_permission" "hello_world_stream_lambda_invoke" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.hello_world_stream_lambda.function_name}"
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/${aws_api_gateway_deployment.prod_deployment.stage_name}/GET/hellostream"
}

# Allows API gateway to invoke lambda
resource "aws_lambda_permission" "hello_world_stream_lambda_testinvoke" {
statement_id = "AllowAPIGatewayTestInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.hello_world_stream_lambda.function_name}"
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/test-invoke-stage/GET/hellostream"
}

output "invoke" {value=aws_api_gateway_deployment.prod_deployment.invoke_url}
95 changes: 95 additions & 0 deletions examples/powertools-examples-core/terraform/infra/lambda.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
resource "aws_lambda_function" "hello_world_lambda" {
runtime = "java11"
filename = "target/helloworld-lambda.jar"
source_code_hash = filebase64sha256("target/helloworld-lambda.jar")
function_name = "hello_world_lambda"

handler = "helloworld.App"
description = "Powertools example, deployed by Terraform"
timeout = 20
memory_size = 512
role = "${aws_iam_role.iam_role_for_lambda.arn}"
tracing_config {
mode = "Active"
}
depends_on = [aws_cloudwatch_log_group.log_group]
}

resource "aws_lambda_function" "hello_world_stream_lambda" {
runtime = "java11"
filename = "target/helloworld-lambda.jar"
source_code_hash = filebase64sha256("target/helloworld-lambda.jar")
function_name = "hello_world_stream_lambda"

handler = "helloworld.AppStream"
description = "Powertools example, deployed by Terraform"
timeout = 20
memory_size = 512
role = "${aws_iam_role.iam_role_for_lambda.arn}"
tracing_config {
mode = "Active"
}
depends_on = [aws_cloudwatch_log_group.log_group]
}

# Create a log group for the lambda
resource "aws_cloudwatch_log_group" "log_group" {
name = "/aws/lambda/hello_world_lambda"
}

# Create a log group for the lambda
resource "aws_cloudwatch_log_group" "log_group_stream" {
name = "/aws/lambda/hello_world_stream_lambda"
}

# lambda role
resource "aws_iam_role" "iam_role_for_lambda" {
name = "lambda-invoke-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

# lambda policy, allow logs to be published to CloudWatch, and traces to Xray
resource "aws_iam_policy" "iam_policy_for_lambda" {
name = "lambda-invoke-policy"
path = "/"

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LambdaPolicy",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"xray:PutTelemetryRecords",
"xray:PutTraceSegments"
],
"Resource": "*"
}
]
}
EOF
}

# Attach the policy to the role
resource "aws_iam_role_policy_attachment" "aws_iam_role_policy_attachment" {
role = "${aws_iam_role.iam_role_for_lambda.name}"
policy_arn = "${aws_iam_policy.iam_policy_for_lambda.arn}"
}
22 changes: 22 additions & 0 deletions examples/powertools-examples-core/terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

# terraform modules
module "powertools_for_java_lambda" {
source = "./infra/"
}

output "api_url" {
value = module.powertools_for_java_lambda.invoke
description = "URL where the API gateway can be invoked"
}

# Configure the AWS Provider
provider "aws" {
}
Loading

0 comments on commit 34fc20e

Please sign in to comment.