Skip to content

Commit d5343e5

Browse files
committed
Add support for setting the time zone for pool schedules
Fixes github-aws-runners#4056 Replaces the `aws_cloudwatch_event_rule` in the `pool` module (which only support UTC) with `aws_scheduler_schedule`, which supports arbitrary time zones via the `schedule_expression_timezone` attribute. The AWS EventBridge Scheduler is a drop in replacement for scheduler based AWS EventBridge Rules ([see AWS blog post](https://aws.amazon.com/blogs/compute/introducing-amazon-eventbridge-scheduler/)), including the expression syntax and pricing. The timezone can be set via the `schedule_expression_timezone` property via the main module or `multi-runners` module.
1 parent cf26704 commit d5343e5

File tree

7 files changed

+87
-45
lines changed

7 files changed

+87
-45
lines changed

docs/configuration.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ The pool is introduced in combination with the ephemeral runners and is primaril
6565
```hcl
6666
pool_runner_owner = "my-org" # Org to which the runners are added
6767
pool_config = [{
68-
size = 20 # size of the pool
69-
schedule_expression = "cron(* * * * ? *)" # cron expression to trigger the adjustment of the pool
68+
size = 20 # size of the pool
69+
schedule_expression = "cron(* * * * ? *)" # cron expression to trigger the adjustment of the pool
70+
schedule_expression_timezone = "Australia/Sydney" # optional time zone (defaults to UTC)
7071
}]
7172
```
7273

examples/ephemeral/main.tf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ module "runners" {
6262
# # Example of simple pool usages
6363
# pool_runner_owner = "philips-test-runners"
6464
# pool_config = [{
65-
# size = 3
66-
# schedule_expression = "cron(* * * * ? *)"
65+
# size = 3
66+
# schedule_expression = "cron(* * * * ? *)"
67+
# schedule_expression_timezone = "Australia/Sydney"
6768
# }]
6869
#
6970
#

modules/multi-runner/variables.tf

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ variable "multi_runner_config" {
107107
volume_size = 30
108108
}])
109109
pool_config = optional(list(object({
110-
schedule_expression = string
111-
size = number
110+
schedule_expression = string
111+
schedule_expression_timezone = optional(string)
112+
size = number
112113
})), [])
113114
})
114115

@@ -177,7 +178,7 @@ variable "multi_runner_config" {
177178
idle_config: "List of time period that can be defined as cron expression to keep a minimum amount of runners active instead of scaling down to 0. By defining this list you can ensure that in time periods that match the cron expression within 5 seconds a runner is kept idle."
178179
runner_log_files: "(optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details."
179180
block_device_mappings: "The EC2 instance block device configuration. Takes the following keys: `device_name`, `delete_on_termination`, `volume_type`, `volume_size`, `encrypted`, `iops`, `throughput`, `kms_key_id`, `snapshot_id`."
180-
pool_config: "The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for week days to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1."
181+
pool_config: "The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for week days to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1. Use `schedule_expression_timezone` to override the schedule time zone (defaults to UTC)."
181182
}
182183
matcherConfig: {
183184
labelMatchers: "The list of list of labels supported by the runner configuration. `[[self-hosted, linux, x64, example]]`"

modules/runners/pool/main.tf

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -118,36 +118,6 @@ data "aws_iam_policy_document" "lambda_assume_role_policy" {
118118
}
119119
}
120120

121-
# per config object one trigger is created to trigger the lambda.
122-
resource "aws_cloudwatch_event_rule" "pool" {
123-
count = length(var.config.pool)
124-
125-
name = "${var.config.prefix}-pool-${count.index}-rule"
126-
schedule_expression = var.config.pool[count.index].schedule_expression
127-
tags = var.config.tags
128-
}
129-
130-
resource "aws_cloudwatch_event_target" "pool" {
131-
count = length(var.config.pool)
132-
133-
input = jsonencode({
134-
poolSize = var.config.pool[count.index].size
135-
})
136-
137-
rule = aws_cloudwatch_event_rule.pool[count.index].name
138-
arn = aws_lambda_function.pool.arn
139-
}
140-
141-
resource "aws_lambda_permission" "pool" {
142-
count = length(var.config.pool)
143-
144-
statement_id = "AllowExecutionFromCloudWatch-${count.index}"
145-
action = "lambda:InvokeFunction"
146-
function_name = aws_lambda_function.pool.function_name
147-
principal = "events.amazonaws.com"
148-
source_arn = aws_cloudwatch_event_rule.pool[count.index].arn
149-
}
150-
151121
resource "aws_iam_role_policy_attachment" "ami_id_ssm_parameter_read" {
152122
count = var.config.ami_id_ssm_parameter_name != null ? 1 : 0
153123
role = aws_iam_role.pool.name
@@ -177,3 +147,69 @@ resource "aws_iam_role_policy" "pool_xray" {
177147
policy = data.aws_iam_policy_document.lambda_xray[0].json
178148
role = aws_iam_role.pool.name
179149
}
150+
151+
resource "aws_scheduler_schedule_group" "pool" {
152+
name_prefix = "${var.config.prefix}-pool"
153+
154+
tags = var.config.tags
155+
}
156+
157+
data "aws_iam_policy_document" "scheduler_assume" {
158+
statement {
159+
sid = "ScheduleGroupAssumeRole"
160+
actions = ["sts:AssumeRole"]
161+
principals {
162+
type = "Service"
163+
identifiers = ["scheduler.amazonaws.com"]
164+
}
165+
166+
condition {
167+
test = "StringEquals"
168+
variable = "aws:SourceArn"
169+
values = [aws_scheduler_schedule_group.pool.arn]
170+
}
171+
}
172+
}
173+
174+
data "aws_iam_policy_document" "scheduler" {
175+
statement {
176+
sid = "InvokePoolLambda"
177+
actions = ["lambda:InvokeFunction"]
178+
resources = [aws_lambda_function.pool.arn]
179+
}
180+
}
181+
182+
resource "aws_iam_role" "scheduler" {
183+
name_prefix = "${var.config.prefix}-pool"
184+
185+
assume_role_policy = data.aws_iam_policy_document.scheduler_assume.json
186+
187+
inline_policy {
188+
name = "terraform"
189+
policy = data.aws_iam_policy_document.scheduler.json
190+
}
191+
192+
tags = var.config.tags
193+
}
194+
195+
resource "aws_scheduler_schedule" "pool" {
196+
for_each = { for i, v in var.config.pool : i => v }
197+
198+
name_prefix = "${var.config.prefix}-pool-${each.key}-rule"
199+
group_name = aws_scheduler_schedule_group.pool.name
200+
201+
flexible_time_window {
202+
mode = "OFF"
203+
}
204+
205+
schedule_expression = each.value.schedule_expression
206+
schedule_expression_timezone = each.value.schedule_expression_timezone
207+
208+
target {
209+
arn = aws_lambda_function.pool.arn
210+
role_arn = aws_iam_role.scheduler.arn
211+
input = jsonencode({
212+
poolSize = each.value.size
213+
})
214+
}
215+
}

modules/runners/pool/variables.tf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ variable "config" {
5050
instance_max_spot_price = string
5151
prefix = string
5252
pool = list(object({
53-
schedule_expression = string
54-
size = number
53+
schedule_expression = string
54+
schedule_expression_timezone = string
55+
size = number
5556
}))
5657
role_permissions_boundary = string
5758
kms_key_arn = string

modules/runners/variables.tf

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,10 +538,11 @@ variable "pool_lambda_reserved_concurrent_executions" {
538538
}
539539

540540
variable "pool_config" {
541-
description = "The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for week days to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1."
541+
description = "The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for week days to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1. Use `schedule_expression_timezone ` to override the schedule time zone (defaults to UTC)."
542542
type = list(object({
543-
schedule_expression = string
544-
size = number
543+
schedule_expression = string
544+
schedule_expression_timezone = optional(string)
545+
size = number
545546
}))
546547
default = []
547548
}

variables.tf

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -686,10 +686,11 @@ variable "pool_lambda_reserved_concurrent_executions" {
686686
}
687687

688688
variable "pool_config" {
689-
description = "The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for weekdays to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1."
689+
description = "The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for weekdays to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1. Use `schedule_expression_timezone` to override the schedule time zone (defaults to UTC)."
690690
type = list(object({
691-
schedule_expression = string
692-
size = number
691+
schedule_expression = string
692+
schedule_expression_timezone = optional(string)
693+
size = number
693694
}))
694695
default = []
695696
}

0 commit comments

Comments
 (0)