Model/infrastructure/terraform/lambda/fast-api/main.tf
2026-03-11 18:05:23 +00:00

225 lines
No EOL
7.2 KiB
HCL

############################################
# Load Terraform State
############################################
data "terraform_remote_state" "shared" {
backend = "s3"
config = {
bucket = "assessment-model-terraform-state"
key = "env:/${var.stage}/terraform.tfstate"
region = "eu-west-2"
}
}
data "terraform_remote_state" "engine" {
backend = "s3"
config = {
bucket = "ara-engine-terraform-state",
key = "env:/${var.stage}/terraform.tfstate"
region = "eu-west-2"
}
}
data "terraform_remote_state" "categorisation" {
backend = "s3"
config = {
bucket = "categorisation-terraform-state",
key = "env:/${var.stage}/terraform.tfstate"
region = "eu-west-2"
}
}
############################################
# Load Credentials
############################################
data "aws_secretsmanager_secret_version" "db_credentials" {
secret_id = "${var.stage}/assessment_model/db_credentials"
}
locals {
db_credentials = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)
}
# data "aws_ssm_parameter" "certificate_arn" {
# name = "/ssl_certificate_arn"
# }
# data "aws_route53_zone" "this" {
# name = var.domain_name
# }
############################################
# Install Python requirements
############################################
resource "null_resource" "pip_install" {
triggers = {
requirements_hash = filemd5("${path.root}/../../../../backend/app/requirements/requirements.txt")
}
provisioner "local-exec" {
command = <<EOT
pip install \
-r ${path.root}/../../../../backend/app/requirements/requirements.txt \
-t ${path.root}/../../../../backend/app/packages \
--platform manylinux2014_x86_64 \
--implementation cp \
--python-version 3.11 \
--only-binary=:all: \
EOT
}
}
############################################
# IAM role
############################################
module "role" {
source = "../../modules/lambda_execution_role"
name = "fastapi-lambda-${var.stage}"
}
############################################
# Create deployment zip
############################################
data "archive_file" "fastapi_zip" {
type = "zip"
source_dir = "${path.root}/../../../../"
output_path = "${path.module}/fastapi_lambda_${var.stage}.zip"
excludes = [
"**/__pycache__/**",
"**/*.pyc",
"**/.pytest_cache/**",
"**/tests/**",
"**/.git/**",
"**/.terraform/**",
"**/node_modules/**",
"**/.env*",
"**/*.xlsx",
"**/*.pdf"
]
depends_on = [null_resource.pip_install]
}
############################################
# Upload zip to S3
############################################
resource "aws_s3_object" "fastapi_zip" {
bucket = "ara-fast-api-terraform-state"
key = "fastapi-lambda/${var.stage}/fastapi_lambda_${var.stage}_${data.archive_file.fastapi_zip.output_base64sha256}.zip"
source = data.archive_file.fastapi_zip.output_path
etag = filemd5(data.archive_file.fastapi_zip.output_path)
}
############################################
# FastAPI Lambda (S3-backed)
############################################
module "lambda" {
source = "../../modules/lambda_service_zip"
name = "fastapi-${var.stage}"
role_arn = module.role.role_arn
s3_bucket = aws_s3_object.fastapi_zip.bucket
s3_key = aws_s3_object.fastapi_zip.key
source_code_hash = data.archive_file.fastapi_zip.output_base64sha256
handler = "backend.app.main.handler"
runtime = "python3.11"
timeout = 600
memory_size = 512
environment = {
ENVIRONMENT = var.stage
API_KEY = var.api_key
SECRET_KEY = var.secret_key
EPC_AUTH_TOKEN = var.epc_auth_token
GOOGLE_SOLAR_API_KEY = var.google_solar_api_key
DB_HOST = var.db_host
DB_NAME = var.db_name
DB_PORT = var.db_port
DB_USERNAME = local.db_credentials.db_assessment_model_username
DB_PASSWORD = local.db_credentials.db_assessment_model_password
PLAN_TRIGGER_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_plan_trigger_bucket_name
DATA_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_sap_data_bucket_name
SAP_PREDICTIONS_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_sap_predictions_bucket_name
CARBON_PREDICTIONS_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_carbon_predictions_bucket_name
HEAT_PREDICTIONS_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_heat_predictions_bucket_name
HEATING_KWH_PREDICTIONS_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_heating_kwh_predictions_bucket_name
HOTWATER_KWH_PREDICTIONS_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_hotwater_kwh_predictions_bucket_name
ENERGY_ASSESSMENTS_BUCKET = data.terraform_remote_state.shared.outputs.retrofit_energy_assessments_bucket_name
ENGINE_SQS_URL = data.terraform_remote_state.engine.outputs.ara_engine_queue_url
CATEGORISATION_SQS_URL = data.terraform_remote_state.categorisation.outputs.categorisation_queue_url
}
depends_on = [aws_s3_object.fastapi_zip]
}
############################################
# API Gateway
############################################
resource "aws_apigatewayv2_api" "this" {
name = "fastapi-api-${var.stage}"
protocol_type = "HTTP"
}
resource "aws_apigatewayv2_stage" "this" {
api_id = aws_apigatewayv2_api.this.id
name = "$default"
auto_deploy = true
}
resource "aws_apigatewayv2_integration" "this" {
api_id = aws_apigatewayv2_api.this.id
integration_type = "AWS_PROXY"
integration_uri = module.lambda.lambda_arn
payload_format_version = "2.0"
}
resource "aws_apigatewayv2_route" "catch_all" {
api_id = aws_apigatewayv2_api.this.id
route_key = "$default"
target = "integrations/${aws_apigatewayv2_integration.this.id}"
}
resource "aws_lambda_permission" "apigw_invoke" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = module.lambda.lambda_arn
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.this.execution_arn}/*/*"
}
############################################
# IAM policy attachments
############################################
module "fastapi_sqs_policy" {
source = "../../modules/general_iam_policy"
policy_name = "fastapi-sqs-send-${var.stage}"
policy_description = "Allow FastAPI to send messages to engine & categorisation queues"
actions = [
"sqs:SendMessage"
]
resources = [
data.terraform_remote_state.engine.outputs.ara_engine_queue_arn,
data.terraform_remote_state.categorisation.outputs.categorisation_queue_arn
]
conditions = null
tags = {
Service = "fastapi"
Stage = var.stage
}
}
resource "aws_iam_role_policy_attachment" "fastapi_s3_read_and_write" {
role = module.role.role_name
policy_arn = data.terraform_remote_state.shared.outputs.fast_api_s3_read_and_write_arn
}
resource "aws_iam_role_policy_attachment" "fastapi_sqs_policy" {
role = module.role.role_name
policy_arn = module.fastapi_sqs_policy.policy_arn
}