Skip to content

Commit 34fc20e

Browse files
authored
feat: Terraform example (#1478)
1 parent 5e3a4e6 commit 34fc20e

File tree

14 files changed

+689
-1
lines changed

14 files changed

+689
-1
lines changed

.github/workflows/pr_build.yml

+29
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ jobs:
5353
env:
5454
JAVA: ${{ matrix.java }}
5555
AWS_REGION: eu-west-1
56+
permissions:
57+
id-token: write # needed to interact with GitHub's OIDC Token endpoint.
58+
contents: read
5659
steps:
5760
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
5861
- name: Setup java
@@ -68,6 +71,32 @@ jobs:
6871
run: |
6972
cd examples/powertools-examples-core/gradle
7073
./gradlew build
74+
- name: Setup Terraform
75+
if: ${{ matrix.java == '11' }}
76+
uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 #v2.0.3
77+
- name: Setup AWS credentials
78+
uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0
79+
with:
80+
role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }}
81+
aws-region: ${{ env.AWS_REGION }}
82+
- name: Terraform validate
83+
if: ${{ matrix.java == '11' }}
84+
run: |
85+
terraform -version
86+
cd examples/powertools-examples-core/terraform
87+
terraform init -backend=false
88+
terraform validate
89+
terraform plan
90+
- name: Setup Terraform lint
91+
if: ${{ matrix.java == '11' }}
92+
uses: terraform-linters/setup-tflint@a5a1af8c6551fb10c53f1cd4ba62359f1973746f # v3.1.1
93+
- name: Terraform lint
94+
if: ${{ matrix.java == '11' }}
95+
run: |
96+
tflint --version
97+
cd examples/powertools-examples-core/terraform
98+
tflint --init
99+
tflint -f compact
71100
- name: Upload coverage to Codecov
72101
uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
73102
if: ${{ matrix.java == '11' }} # publish results once

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,6 @@ example/HelloWorldFunction/build
108108
/example/.gradle/
109109
/example/.java-version
110110
.gradle
111-
build/
111+
build/
112+
.terraform*
113+
terraform.tfstate*

examples/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<module>powertools-examples-core/cdk/app</module>
3434
<module>powertools-examples-core/cdk/infra</module>
3535
<module>powertools-examples-core/serverless</module>
36+
<module>powertools-examples-core/terraform</module>
3637
<module>powertools-examples-idempotency</module>
3738
<module>powertools-examples-parameters</module>
3839
<module>powertools-examples-serialization</module>

examples/powertools-examples-core/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ We provide examples for the following infrastructure-as-code tools:
1010
* [AWS SAM](sam/)
1111
* [AWS CDK](cdk/)
1212
* [Serverless framework](serverless/)
13+
* [Terraform](terraform/)
1314

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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
rule "terraform_required_version" {
2+
enabled = false
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Powertools for AWS Lambda (Java) - Core Utilities Example with Terraform
2+
3+
This project demonstrates the Lambda for Powertools Java module deployed using [Terraform](https://www.terraform.io/).
4+
For general information on the deployed example itself, you can refer to the parent [README](../README.md).
5+
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).
6+
7+
## Configuration
8+
Terraform uses [main.tf](./main.tf) to define the application's AWS resources.
9+
This file defines the Lambda function to be deployed as well as API Gateway for it.
10+
11+
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.
12+
13+
14+
## Deploy the sample application
15+
16+
To deploy the app, simply run the following commands:
17+
```bash
18+
terraform init
19+
mvn package && terraform apply
20+
```
21+
22+
## Useful commands
23+
24+
To destroy the app
25+
```bash
26+
terraform destroy
27+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
resource "aws_api_gateway_rest_api" "hello_world_api" {
2+
name = "hello_world_api"
3+
description = "API Gateway endpoint URL for Prod stage for Hello World function"
4+
}
5+
6+
resource "aws_api_gateway_resource" "hello_resource" {
7+
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
8+
parent_id = "${aws_api_gateway_rest_api.hello_world_api.root_resource_id}"
9+
path_part = "hello"
10+
}
11+
12+
resource "aws_api_gateway_resource" "hello_stream_resource" {
13+
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
14+
parent_id = "${aws_api_gateway_rest_api.hello_world_api.root_resource_id}"
15+
path_part = "hellostream"
16+
}
17+
18+
resource "aws_api_gateway_method" "hello_get_method" {
19+
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
20+
resource_id = "${aws_api_gateway_resource.hello_resource.id}"
21+
http_method = "GET"
22+
authorization = "NONE"
23+
}
24+
25+
resource "aws_api_gateway_method" "hello_stream_get_method" {
26+
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
27+
resource_id = "${aws_api_gateway_resource.hello_stream_resource.id}"
28+
http_method = "GET"
29+
authorization = "NONE"
30+
}
31+
32+
resource "aws_api_gateway_integration" "java_lambda_integration" {
33+
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
34+
resource_id = "${aws_api_gateway_resource.hello_resource.id}"
35+
http_method = "${aws_api_gateway_method.hello_get_method.http_method}"
36+
37+
integration_http_method = "POST"
38+
type = "AWS_PROXY"
39+
uri = "${aws_lambda_function.hello_world_lambda.invoke_arn}"
40+
}
41+
42+
resource "aws_api_gateway_integration" "java_stream_lambda_integration" {
43+
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
44+
resource_id = "${aws_api_gateway_resource.hello_stream_resource.id}"
45+
http_method = "${aws_api_gateway_method.hello_stream_get_method.http_method}"
46+
47+
integration_http_method = "POST"
48+
type = "AWS_PROXY"
49+
uri = "${aws_lambda_function.hello_world_stream_lambda.invoke_arn}"
50+
}
51+
52+
resource "aws_api_gateway_deployment" "prod_deployment" {
53+
depends_on = [aws_api_gateway_integration.java_lambda_integration, aws_api_gateway_integration.java_stream_lambda_integration]
54+
rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}"
55+
stage_name = "prod"
56+
}
57+
58+
# Allows API gateway to invoke lambda
59+
resource "aws_lambda_permission" "hello_world_lambda_invoke" {
60+
statement_id = "AllowAPIGatewayInvoke"
61+
action = "lambda:InvokeFunction"
62+
function_name = "${aws_lambda_function.hello_world_lambda.function_name}"
63+
principal = "apigateway.amazonaws.com"
64+
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/${aws_api_gateway_deployment.prod_deployment.stage_name}/GET/hello"
65+
}
66+
67+
# Allows API gateway to invoke lambda
68+
resource "aws_lambda_permission" "hello_world_lambda_testinvoke" {
69+
statement_id = "AllowAPIGatewayTestInvoke"
70+
action = "lambda:InvokeFunction"
71+
function_name = "${aws_lambda_function.hello_world_lambda.function_name}"
72+
principal = "apigateway.amazonaws.com"
73+
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/test-invoke-stage/GET/hello"
74+
}
75+
76+
# Allows API gateway to invoke lambda
77+
resource "aws_lambda_permission" "hello_world_stream_lambda_invoke" {
78+
statement_id = "AllowAPIGatewayInvoke"
79+
action = "lambda:InvokeFunction"
80+
function_name = "${aws_lambda_function.hello_world_stream_lambda.function_name}"
81+
principal = "apigateway.amazonaws.com"
82+
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/${aws_api_gateway_deployment.prod_deployment.stage_name}/GET/hellostream"
83+
}
84+
85+
# Allows API gateway to invoke lambda
86+
resource "aws_lambda_permission" "hello_world_stream_lambda_testinvoke" {
87+
statement_id = "AllowAPIGatewayTestInvoke"
88+
action = "lambda:InvokeFunction"
89+
function_name = "${aws_lambda_function.hello_world_stream_lambda.function_name}"
90+
principal = "apigateway.amazonaws.com"
91+
source_arn = "${aws_api_gateway_rest_api.hello_world_api.execution_arn}/test-invoke-stage/GET/hellostream"
92+
}
93+
94+
output "invoke" {value=aws_api_gateway_deployment.prod_deployment.invoke_url}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
resource "aws_lambda_function" "hello_world_lambda" {
2+
runtime = "java11"
3+
filename = "target/helloworld-lambda.jar"
4+
source_code_hash = filebase64sha256("target/helloworld-lambda.jar")
5+
function_name = "hello_world_lambda"
6+
7+
handler = "helloworld.App"
8+
description = "Powertools example, deployed by Terraform"
9+
timeout = 20
10+
memory_size = 512
11+
role = "${aws_iam_role.iam_role_for_lambda.arn}"
12+
tracing_config {
13+
mode = "Active"
14+
}
15+
depends_on = [aws_cloudwatch_log_group.log_group]
16+
}
17+
18+
resource "aws_lambda_function" "hello_world_stream_lambda" {
19+
runtime = "java11"
20+
filename = "target/helloworld-lambda.jar"
21+
source_code_hash = filebase64sha256("target/helloworld-lambda.jar")
22+
function_name = "hello_world_stream_lambda"
23+
24+
handler = "helloworld.AppStream"
25+
description = "Powertools example, deployed by Terraform"
26+
timeout = 20
27+
memory_size = 512
28+
role = "${aws_iam_role.iam_role_for_lambda.arn}"
29+
tracing_config {
30+
mode = "Active"
31+
}
32+
depends_on = [aws_cloudwatch_log_group.log_group]
33+
}
34+
35+
# Create a log group for the lambda
36+
resource "aws_cloudwatch_log_group" "log_group" {
37+
name = "/aws/lambda/hello_world_lambda"
38+
}
39+
40+
# Create a log group for the lambda
41+
resource "aws_cloudwatch_log_group" "log_group_stream" {
42+
name = "/aws/lambda/hello_world_stream_lambda"
43+
}
44+
45+
# lambda role
46+
resource "aws_iam_role" "iam_role_for_lambda" {
47+
name = "lambda-invoke-role"
48+
assume_role_policy = <<EOF
49+
{
50+
"Version": "2012-10-17",
51+
"Statement": [
52+
{
53+
"Action": "sts:AssumeRole",
54+
"Principal": {
55+
"Service": "lambda.amazonaws.com"
56+
},
57+
"Effect": "Allow",
58+
"Sid": ""
59+
}
60+
]
61+
}
62+
EOF
63+
}
64+
65+
# lambda policy, allow logs to be published to CloudWatch, and traces to Xray
66+
resource "aws_iam_policy" "iam_policy_for_lambda" {
67+
name = "lambda-invoke-policy"
68+
path = "/"
69+
70+
policy = <<EOF
71+
{
72+
"Version": "2012-10-17",
73+
"Statement": [
74+
{
75+
"Sid": "LambdaPolicy",
76+
"Effect": "Allow",
77+
"Action": [
78+
"logs:CreateLogGroup",
79+
"logs:CreateLogStream",
80+
"logs:PutLogEvents",
81+
"xray:PutTelemetryRecords",
82+
"xray:PutTraceSegments"
83+
],
84+
"Resource": "*"
85+
}
86+
]
87+
}
88+
EOF
89+
}
90+
91+
# Attach the policy to the role
92+
resource "aws_iam_role_policy_attachment" "aws_iam_role_policy_attachment" {
93+
role = "${aws_iam_role.iam_role_for_lambda.name}"
94+
policy_arn = "${aws_iam_policy.iam_policy_for_lambda.arn}"
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
terraform {
2+
required_providers {
3+
aws = {
4+
source = "hashicorp/aws"
5+
version = "~> 5.0"
6+
}
7+
}
8+
}
9+
10+
# terraform modules
11+
module "powertools_for_java_lambda" {
12+
source = "./infra/"
13+
}
14+
15+
output "api_url" {
16+
value = module.powertools_for_java_lambda.invoke
17+
description = "URL where the API gateway can be invoked"
18+
}
19+
20+
# Configure the AWS Provider
21+
provider "aws" {
22+
}

0 commit comments

Comments
 (0)