Repository navigation
Expand file tree
/
Copy pathlambda.tf
More file actions
109 lines (91 loc) · 3.73 KB
/
Copy pathlambda.tf
File metadata and controls
109 lines (91 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# The functions need only boto3, which the Lambda runtime provides.
data "archive_file" "package" {
type = "zip"
output_path = "${path.module}/.build/${var.name}.zip"
dynamic "source" {
for_each = toset(["app.py", "aws.py", "control.py", "engine.py", "messages.py", "model.py", "rules.py"])
content {
filename = source.value
content = file("${path.module}/lambda/devboxes/${source.value}")
}
}
}
resource "aws_cloudwatch_log_group" "evaluator" {
name = "/aws/lambda/${var.name}-evaluator"
retention_in_days = var.log_retention_days
tags = var.tags
}
resource "aws_cloudwatch_log_group" "control" {
name = "/aws/lambda/${var.name}-control"
retention_in_days = var.log_retention_days
tags = var.tags
}
# --- evaluator: every 5 minutes --------------------------------------------------------------
resource "aws_lambda_function" "evaluator" {
function_name = "${var.name}-evaluator"
description = "Warns, stops and starts managed dev boxes by idleness and schedule"
role = aws_iam_role.evaluator.arn
filename = data.archive_file.package.output_path
source_code_hash = data.archive_file.package.output_base64sha256
handler = "app.evaluator"
runtime = "python3.14"
architectures = ["arm64"]
memory_size = 256
# The probe waits up to 60 s for SSM; the rest is a few API calls per box.
timeout = 180
# One tick at a time: the state's conditional writes guard against Slack, not against a
# second tick deciding the same boxes.
reserved_concurrent_executions = 1
environment {
variables = { TABLE_NAME = aws_dynamodb_table.this.name }
}
tags = var.tags
depends_on = [aws_cloudwatch_log_group.evaluator, aws_iam_role_policy.evaluator]
}
resource "aws_lambda_function_event_invoke_config" "evaluator" {
function_name = aws_lambda_function.evaluator.function_name
maximum_retry_attempts = 0
}
resource "aws_cloudwatch_event_rule" "evaluator" {
name = "${var.name}-evaluator"
description = "Evaluate managed dev boxes"
schedule_expression = "rate(5 minutes)"
tags = var.tags
}
resource "aws_cloudwatch_event_target" "evaluator" {
rule = aws_cloudwatch_event_rule.evaluator.name
arn = aws_lambda_function.evaluator.arn
}
resource "aws_lambda_permission" "evaluator_schedule" {
statement_id = "AllowSchedule"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.evaluator.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.evaluator.arn
}
# --- control: Slack commands -------------------------------------------------------------------
resource "aws_lambda_function" "control" {
function_name = "${var.name}-control"
description = "Slack commands for dev boxes: list, status, start, stop, extend"
role = aws_iam_role.control.arn
filename = data.archive_file.package.output_path
source_code_hash = data.archive_file.package.output_base64sha256
handler = "app.control"
runtime = "python3.14"
architectures = ["arm64"]
memory_size = 256
# Amazon Q gives a command 15 seconds; the function never waits for an instance.
timeout = 15
environment {
variables = { TABLE_NAME = aws_dynamodb_table.this.name }
}
tags = var.tags
depends_on = [aws_cloudwatch_log_group.control, aws_iam_role_policy.control]
}
resource "aws_lambda_permission" "control_chat" {
count = var.slack != null ? 1 : 0
statement_id = "AllowAmazonQChannel"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.control.function_name
principal = aws_iam_role.chat[0].arn
}