Add step-functions, update lambda and fix bugs

Co-authored-by: Ezequiel Bellver <ebellver@itba.edu.ar>
This commit is contained in:
Santiago Lo Coco 2022-12-01 19:26:34 -03:00
parent d7cbbb2cf6
commit adad6f5386
24 changed files with 275 additions and 47 deletions

View File

@ -121,21 +121,11 @@ Los servicios que deben ser corregidos (asociados a la entrega del TP3) son los
<tr>
<td>Bellver, Ezequiel</td>
<td>61268</td>
<td>25%</td>
</tr>
<tr>
<td>Burgos, Satiago Eduardo</td>
<td>55193</td>
<td>25%</td>
<td>50%</td>
</tr>
<tr>
<td>Lo Coco, Santiago</td>
<td>61301</td>
<td>25%</td>
</tr>
<tr>
<td>Oillataguerre, Amparo</td>
<td>58714</td>
<td>25%</td>
<td>50%</td>
</tr>
</table>

16
run.sh
View File

@ -8,23 +8,37 @@ usage: ${0##*/} [command]
-p Show changes required by the current terraform config.
-a Create or update infraestructure.
-d Destroy infraestructure.
-l Create zip files of the lambdas.
EOF
exit 1
}
RUN=
while getopts "hvpad" OPTION; do
while getopts "hvpadl" OPTION; do
case $OPTION in
a) RUN=apply ;;
v) RUN=validate ;;
p) RUN=plan ;;
d) RUN=destroy ;;
l) RUN=lambda ;;
*) usage ;;
esac
done
dir="$PWD"
if [ "$RUN" = 'lambda' ]; then
cd "$dir/terraform/resources/lambda" || exit
lambdas=$(find -H . -maxdepth 1 -mindepth 1 -type d -printf "%f\n")
for lambda in $lambdas; do
cd $lambda || exit
zip $lambda.zip lambda_handler.py
mv $lambda.zip ..
cd ..
done
exit
fi
cd "$dir/terraform/organization" || exit
terraform init

View File

@ -1,9 +0,0 @@
# ------------------------------------------------------------------------------
# Amazon EventBridge variables
# ------------------------------------------------------------------------------
variable "tags" {
description = "A mapping of tags to assign to the resource"
type = map(string)
default = {}
}

View File

@ -2,9 +2,14 @@
# Lambda outputs
# --------------------------------------------------------------------
output "function_invoke_arn" {
description = "The invoke ARN of the Lambda Function"
value = aws_lambda_function.this.invoke_arn
}
output "function_arn" {
description = "The ARN of the Lambda Function"
value = aws_lambda_function.this.invoke_arn
value = aws_lambda_function.this.arn
}
output "function_name" {

View File

@ -0,0 +1,12 @@
# ------------------------------------------------------------------------------
# Amazon Step Functions
# ------------------------------------------------------------------------------
resource "aws_sfn_state_machine" "this" {
name = var.name
definition = var.definition
role_arn = var.role_arn
type = upper(var.type)
}

View File

@ -1,3 +1,8 @@
# ------------------------------------------------------------------------------
# Amazon EventBridge
# Amazon Step Function outputs
# ------------------------------------------------------------------------------
output "name" {
description = "The name of the Step Function"
value = aws_sfn_state_machine.this.name
}

View File

@ -0,0 +1,29 @@
# ------------------------------------------------------------------------------
# Amazon Step Function variables
# ------------------------------------------------------------------------------
variable "tags" {
description = "A mapping of tags to assign to the resource"
type = map(string)
default = {}
}
variable "name" {
description = "The state machine name."
type = string
}
variable "definition" {
description = "The Step Function definition."
type = string
}
variable "type" {
description = "Determines whether a Standard or Express state machine is created.."
type = string
}
variable "role_arn" {
description = "The Step Function role."
type = string
}

View File

@ -14,7 +14,7 @@ module "apigw" {
lambda = [
{
function_arn = module.lambda["lambdaDB"].function_arn
function_arn = module.lambda["lambdaDB"].function_invoke_arn
function_name = module.lambda["lambdaDB"].function_name
source_arn = "arn:aws:execute-api:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}"
}
@ -40,7 +40,7 @@ module "apigw" {
integration_http_method = "POST",
type = "AWS_PROXY",
credentials = null,
uri = module.lambda["lambdaDB"].function_arn,
uri = module.lambda["lambdaDB"].function_invoke_arn,
request_parameters = {},
request_templates = {},
},

View File

@ -51,3 +51,17 @@ data "aws_iam_policy_document" "sns" {
resources = ["arn:aws:sns:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:${module.sns.name}"]
}
}
data "aws_iam_policy_document" "stepfunctions" {
statement {
effect = "Allow"
actions = [
"states:StartExecution",
]
principals {
type = "AWS"
identifiers = ["*"]
}
resources = ["arn:aws:states:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:stateMachine:${module.stepfunctions.name}"]
}
}

View File

@ -57,7 +57,7 @@ locals {
role = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/LabRole"
handler = "lambda_handler.main"
runtime = "python3.9",
security_group_ids = aws_security_group.dynamodb_sg.id
security_group_ids = aws_security_group.stepfunctions_sg.id
},
lambdaDB = {
package = "${local.path}/lambda/lambdaDB.zip"
@ -75,6 +75,30 @@ locals {
runtime = "python3.9",
security_group_ids = aws_security_group.sns_sg.id
}
lambdaGET = {
package = "${local.path}/lambda/lambdaGET.zip"
function_name = "AWSLambdaHandlerGETg3"
role = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/LabRole"
handler = "lambda_handler.main"
runtime = "python3.7",
security_group_ids = aws_security_group.sns_sg.id
}
lambdaUpdate = {
package = "${local.path}/lambda/lambdaUpdate.zip"
function_name = "AWSLambdaHandlerUpdateg3"
role = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/LabRole"
handler = "lambda_handler.main"
runtime = "python3.9",
security_group_ids = aws_security_group.dynamodb_sg.id
}
lambdaError = {
package = "${local.path}/lambda/lambdaError.zip"
function_name = "AWSLambdaHandlerSNSErrorg3"
role = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/LabRole"
handler = "lambda_handler.main"
runtime = "python3.9",
security_group_ids = aws_security_group.sns_sg.id
}
}
private_inbound = [
@ -91,9 +115,9 @@ locals {
{
rule_number = 100
rule_action = "allow"
from_port = 443
to_port = 443
protocol = "tcp"
from_port = 0
to_port = 65535
protocol = 6
cidr_block = "0.0.0.0/0"
}
]

View File

@ -0,0 +1,66 @@
module "stepfunctions" {
source = "../modules/stepfunctions"
providers = {
aws = aws.aws
}
name = "AWSStepFunctions-g3"
role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/LabRole"
definition = <<EOF
{
"StartAt": "GetFromMLApi",
"States": {
"GetFromMLApi": {
"Type": "Task",
"Resource": "${module.lambda["lambdaGET"].function_arn}",
"Next": "UpdateDynamoDB",
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "SendError"
}
]
},
"UpdateDynamoDB": {
"Type": "Task",
"Resource": "${module.lambda["lambdaUpdate"].function_arn}",
"Next": "SendEmail",
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "SendError"
}
]
},
"SendEmail": {
"Type": "Task",
"Resource": "${module.lambda["lambdaSNS"].function_arn}",
"End": true,
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "SendError"
}
]
},
"SendError": {
"Type": "Task",
"Resource": "${module.lambda["lambdaError"].function_arn}",
"Next": "ErrorWorkflow"
},
"ErrorWorkflow": {
"Type": "Fail"
}
}
}
EOF
type = "standard"
}

View File

@ -65,6 +65,15 @@ module "vpc_endpoints" {
tags = { Name = "sns-vpc-endpoint" }
subnet_ids = module.vpc.private_subnets
security_group_ids = [aws_security_group.sns_sg.id]
},
stepfunctions = {
service = "states"
service_type = "Interface"
route_table_ids = flatten([module.vpc.private_route_table_ids])
policy = data.aws_iam_policy_document.stepfunctions.json
tags = { Name = "stepfunctions-vpc-endpoint" }
subnet_ids = module.vpc.private_subnets
security_group_ids = [aws_security_group.stepfunctions_sg.id]
}
}
}
@ -105,3 +114,17 @@ resource "aws_security_group" "sns_sg" {
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "stepfunctions_sg" {
name_prefix = "vpc-g3-bsmsapp-sfsg"
description = "Allow outbound traffic"
vpc_id = module.vpc.vpc_id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
import json
import boto3
def main(event, context):
print(event)
message = "Error en la actualización de stock."
subject = "BSMSapp"
client = boto3.client("sns")
# El dueño del tópico podría salir de la BD, habría que guardar la relación item y dueño.
# Ahora está hardcodeado a un dueño solo (no me parece mal de todos modos para la entrega esta)
# Pero podríamos hacer un get del dynamo y obtener el dueño de ahí sino.
topic_arn = "arn:aws:sns:us-east-1:025685231147:slococo"
client.publish(TopicArn=topic_arn, Message=message, Subject=subject)

Binary file not shown.

View File

@ -0,0 +1,13 @@
import json
import boto3
import requests
def main(event, context):
print("hago el get y comparo el resultado con el post que tengo en {event}")
print(event)
response = requests.get("http://181.46.186.8:2555/events/10")
print(response.json())
return event

View File

@ -3,6 +3,7 @@ import boto3
def main(event, context):
print(event)
message = "Probando SNS desde lambda..."
subject = "BSMSapp"
client = boto3.client("sns")

View File

@ -2,25 +2,25 @@ import json
import boto3
def start_state_machine(state_machine_arn: str, sqs_message: str):
client = boto3.client('stepfunctions')
response = client.start_execution(
stateMachineArn=state_machine_arn,
input=sqs_message)
print(response)
return response
def main(event, context):
payload = event
payload = payload["Records"][0]
body = payload["body"]
record = event['Records'][0]
print(record)
sqs_message = json.dumps(event)
print(sqs_message)
body = record["body"]
body = body.replace('\n', '')
body = json.loads(body)
query = body["body-json"]
print(query)
client = boto3.resource('dynamodb', region_name="us-east-1")
table = client.Table("AWSDynamoDB-g3")
table.put_item(Item=query)
resp = {
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*",
},
"body": "El elemento fue agregado."
}
return resp
start_state_machine(
f"arn:aws:states:us-east-1:025685231147:stateMachine:AWSStepFunctions-g3", sqs_message)

Binary file not shown.

View File

@ -0,0 +1,27 @@
import json
import boto3
def main(event, context):
payload = event
payload = payload["Records"][0]
body = payload["body"]
body = body.replace('\n', '')
body = json.loads(body)
query = body["body-json"]
client = boto3.resource('dynamodb', region_name="us-east-1")
table = client.Table("AWSDynamoDB-g3")
table.put_item(Item=query)
# resp = {
# "statusCode": 200,
# "headers": {
# "Access-Control-Allow-Origin": "*",
# },
# "body": "El elemento fue agregado."
# }
# return resp
return event