From 232e1a7643dbdec15e25e6d456d33e093c7fa164 Mon Sep 17 00:00:00 2001 From: Ashwin A Nayar Date: Sat, 16 Nov 2024 15:22:49 +0530 Subject: [PATCH] feat: Natively support runner job started/completed hooks (#4260) Pre and post job hooks were added to github actions to help administrators run custom scripts at the beginning and end of every job. As of today the module doesn't support these options out of the box. Add variables to accept these optional scripts and register the hook in user-data. Related to: https://github.com/philips-labs/terraform-aws-github-runner/issues/3854 --- .terraform.lock.hcl | 5 ++++- main.tf | 2 ++ modules/multi-runner/runners.tf | 16 +++++++++------- modules/multi-runner/variables.tf | 2 ++ modules/runners/main.tf | 4 +++- modules/runners/templates/user-data.sh | 16 ++++++++++++++++ modules/runners/variables.tf | 12 ++++++++++++ variables.tf | 12 ++++++++++++ 8 files changed, 60 insertions(+), 9 deletions(-) diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl index 61e1824697..733b247e90 100644 --- a/.terraform.lock.hcl +++ b/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/aws" { version = "5.31.0" constraints = "~> 5.0, ~> 5.27" hashes = [ + "h1:WwgMbMOhZblxZTdjHeJf9XB2/hcSHHmpuywLxuTWYw0=", "h1:ltxyuBWIy9cq0kIKDJH1jeWJy/y7XJLjS4QrsQK4plA=", "zh:0cdb9c2083bf0902442384f7309367791e4640581652dda456f2d6d7abf0de8d", "zh:2fe4884cb9642f48a5889f8dff8f5f511418a18537a9dfa77ada3bcdad391e4e", @@ -26,8 +27,9 @@ provider "registry.terraform.io/hashicorp/aws" { provider "registry.terraform.io/hashicorp/null" { version = "3.2.3" - constraints = "~> 3.2" + constraints = "~> 3.0, ~> 3.2" hashes = [ + "h1:+AnORRgFbRO6qqcfaQyeX80W0eX3VmjadjnUFUJTiXo=", "h1:I0Um8UkrMUb81Fxq/dxbr3HLP2cecTH2WMJiwKSrwQY=", "zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2", "zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d", @@ -49,6 +51,7 @@ provider "registry.terraform.io/hashicorp/random" { constraints = "~> 3.0" hashes = [ "h1:I8MBeauYA8J8yheLJ8oSMWqB0kovn16dF/wKZ1QTdkk=", + "h1:R5Ucn26riKIEijcsiOMBR3uOAjuOMfI1x7XvH4P6B1w=", "zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d", "zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211", "zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829", diff --git a/main.tf b/main.tf index 3523e9ff3a..0a28cdf6e8 100644 --- a/main.tf +++ b/main.tf @@ -247,6 +247,8 @@ module "runners" { userdata_content = var.userdata_content userdata_pre_install = var.userdata_pre_install userdata_post_install = var.userdata_post_install + runner_hook_job_started = var.runner_hook_job_started + runner_hook_job_completed = var.runner_hook_job_completed key_name = var.key_name runner_ec2_tags = var.runner_ec2_tags diff --git a/modules/multi-runner/runners.tf b/modules/multi-runner/runners.tf index abea1cf3ee..1136896279 100644 --- a/modules/multi-runner/runners.tf +++ b/modules/multi-runner/runners.tf @@ -85,13 +85,15 @@ module "runners" { role_path = var.role_path role_permissions_boundary = var.role_permissions_boundary - enable_userdata = each.value.runner_config.enable_userdata - userdata_template = each.value.runner_config.userdata_template - userdata_content = each.value.runner_config.userdata_content - userdata_pre_install = each.value.runner_config.userdata_pre_install - userdata_post_install = each.value.runner_config.userdata_post_install - key_name = var.key_name - runner_ec2_tags = each.value.runner_config.runner_ec2_tags + enable_userdata = each.value.runner_config.enable_userdata + userdata_template = each.value.runner_config.userdata_template + userdata_content = each.value.runner_config.userdata_content + userdata_pre_install = each.value.runner_config.userdata_pre_install + userdata_post_install = each.value.runner_config.userdata_post_install + runner_hook_job_started = each.value.runner_config.runner_hook_job_started + runner_hook_job_completed = each.value.runner_config.runner_hook_job_completed + key_name = var.key_name + runner_ec2_tags = each.value.runner_config.runner_ec2_tags create_service_linked_role_spot = each.value.runner_config.create_service_linked_role_spot diff --git a/modules/multi-runner/variables.tf b/modules/multi-runner/variables.tf index ef104ef50c..cee668f39f 100644 --- a/modules/multi-runner/variables.tf +++ b/modules/multi-runner/variables.tf @@ -77,6 +77,8 @@ variable "multi_runner_config" { cloudwatch_config = optional(string, null) userdata_pre_install = optional(string, "") userdata_post_install = optional(string, "") + runner_hook_job_started = optional(string, "") + runner_hook_job_completed = optional(string, "") runner_ec2_tags = optional(map(string), {}) runner_iam_role_managed_policy_arns = optional(list(string), []) vpc_id = optional(string, null) diff --git a/modules/runners/main.tf b/modules/runners/main.tf index 625ebd4ed0..051d6713cd 100644 --- a/modules/runners/main.tf +++ b/modules/runners/main.tf @@ -54,7 +54,9 @@ locals { S3_LOCATION_RUNNER_DISTRIBUTION = local.s3_location_runner_distribution RUNNER_ARCHITECTURE = var.runner_architecture }) - post_install = var.userdata_post_install + post_install = var.userdata_post_install + hook_job_started = var.runner_hook_job_started + hook_job_completed = var.runner_hook_job_completed start_runner = templatefile(local.userdata_start_runner[var.runner_os], { metadata_tags = var.metadata_options != null ? var.metadata_options.instance_metadata_tags : "enabled" }) diff --git a/modules/runners/templates/user-data.sh b/modules/runners/templates/user-data.sh index 68edb79b0a..321cbc4e02 100644 --- a/modules/runners/templates/user-data.sh +++ b/modules/runners/templates/user-data.sh @@ -62,4 +62,20 @@ ${install_runner} ${post_install} +# Register runner job hooks +# Ref: https://github.com/actions/runner/blob/main/docs/adrs/1751-runner-job-hooks.md +%{ if hook_job_started != "" } +cat > /opt/actions-runner/hook_job_started.sh << EOF +${hook_job_started} +EOF +echo ACTIONS_RUNNER_HOOK_JOB_STARTED=/opt/actions-runner/hook_job_started.sh | tee -a /opt/actions-runner/.env +%{ endif } + +%{ if hook_job_completed != "" } +cat > /opt/actions-runner/hook_job_completed.sh << EOF +${hook_job_completed} +EOF +echo ACTIONS_RUNNER_HOOK_JOB_COMPLETED=/opt/actions-runner/hook_job_completed.sh | tee -a /opt/actions-runner/.env +%{ endif } + ${start_runner} diff --git a/modules/runners/variables.tf b/modules/runners/variables.tf index 1c84bf9c02..24908ff6b3 100644 --- a/modules/runners/variables.tf +++ b/modules/runners/variables.tf @@ -172,6 +172,18 @@ variable "userdata_post_install" { default = "" } +variable "runner_hook_job_started" { + description = "Script to be ran in the runner environment at the beginning of every job" + type = string + default = "" +} + +variable "runner_hook_job_completed" { + description = "Script to be ran in the runner environment at the end of every job" + type = string + default = "" +} + variable "sqs_build_queue" { description = "SQS queue to consume accepted build events." type = object({ diff --git a/variables.tf b/variables.tf index f0b011873b..1a109f01fb 100644 --- a/variables.tf +++ b/variables.tf @@ -269,6 +269,18 @@ variable "userdata_post_install" { description = "Script to be ran after the GitHub Actions runner is installed on the EC2 instances" } +variable "runner_hook_job_started" { + type = string + default = "" + description = "Script to be ran in the runner environment at the beginning of every job" +} + +variable "runner_hook_job_completed" { + type = string + default = "" + description = "Script to be ran in the runner environment at the end of every job" +} + variable "idle_config" { description = "List of time periods, defined as a 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." type = list(object({