Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f5fa6a0
feat: add support to use custom scale errors
edersonbrilhante Dec 4, 2025
9eb0383
chore: update variable description
edersonbrilhante Dec 4, 2025
c48513a
fix: fix typo
edersonbrilhante Dec 4, 2025
a1c2acb
style: fix ts formating
edersonbrilhante Dec 4, 2025
297dc0a
docs: auto update terraform docs
github-actions[bot] Dec 15, 2025
2542305
style: fix formatting issue
edersonbrilhante Dec 15, 2025
f744d32
test: fix test after rebase
edersonbrilhante Dec 15, 2025
b078c54
fix: missing property in NodeJS
edersonbrilhante Dec 16, 2025
02e0b36
refactor: remove custom friom variable and add default values
edersonbrilhante Dec 18, 2025
3a1c508
feat: add osx options
edersonbrilhante Dec 3, 2025
7ebd834
feat: create runner scripts for macos
edersonbrilhante Dec 3, 2025
7b3bdea
docs: auto update terraform docs
github-actions[bot] Dec 15, 2025
2a1c57e
fix: remove not needed variable
edersonbrilhante Dec 17, 2025
7ed8698
fix: fix ownership group
edersonbrilhante Dec 18, 2025
bfbb6cc
fix: fix wrong type for host_resource_group_arn
edersonbrilhante Dec 18, 2025
8fd2e66
feat: add license_specification
edersonbrilhante Dec 18, 2025
d6c0106
fix: use list of license_specification
edersonbrilhante Dec 18, 2025
571ee7c
fix: fix typo
edersonbrilhante Dec 18, 2025
aea7f65
docs: add example to create dedicate hosts and host group
edersonbrilhante Dec 22, 2025
dfa465b
fix: fix install runner for windows
edersonbrilhante Dec 23, 2025
4461627
fix: remove cd in start
edersonbrilhante Dec 23, 2025
e142885
fix: undo windows change
edersonbrilhante Jan 7, 2026
3beb03d
docs: fix typo
edersonbrilhante Jan 7, 2026
9509230
docs: auto update terraform docs
github-actions[bot] Jan 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
| <a name="input_instance_profile_path"></a> [instance\_profile\_path](#input\_instance\_profile\_path) | The path that will be added to the instance\_profile, if not set the environment name will be used. | `string` | `null` | no |
| <a name="input_instance_target_capacity_type"></a> [instance\_target\_capacity\_type](#input\_instance\_target\_capacity\_type) | Default lifecycle used for runner instances, can be either `spot` or `on-demand`. | `string` | `"spot"` | no |
| <a name="input_instance_termination_watcher"></a> [instance\_termination\_watcher](#input\_instance\_termination\_watcher) | Configuration for the instance termination watcher. This feature is Beta, changes will not trigger a major release as long in beta.<br/><br/>`enable`: Enable or disable the spot termination watcher.<br/>'features': Enable or disable features of the termination watcher.<br/>`memory_size`: Memory size limit in MB of the lambda.<br/>`s3_key`: S3 key for syncer lambda function. Required if using S3 bucket to specify lambdas.<br/>`s3_object_version`: S3 object version for syncer lambda function. Useful if S3 versioning is enabled on source bucket.<br/>`timeout`: Time out of the lambda in seconds.<br/>`zip`: File location of the lambda zip file. | <pre>object({<br/> enable = optional(bool, false)<br/> features = optional(object({<br/> enable_spot_termination_handler = optional(bool, true)<br/> enable_spot_termination_notification_watcher = optional(bool, true)<br/> }), {})<br/> memory_size = optional(number, null)<br/> s3_key = optional(string, null)<br/> s3_object_version = optional(string, null)<br/> timeout = optional(number, null)<br/> zip = optional(string, null)<br/> })</pre> | `{}` | no |
| <a name="input_instance_types"></a> [instance\_types](#input\_instance\_types) | List of instance types for the action runner. Defaults are based on runner\_os (al2023 for linux and Windows Server Core for win). | `list(string)` | <pre>[<br/> "m5.large",<br/> "c5.large"<br/>]</pre> | no |
| <a name="input_instance_types"></a> [instance\_types](#input\_instance\_types) | List of instance types for the action runner. Defaults are based on runner\_os (al2023 for linux, macOS Sequoia for osx, Windows Server Core for win). | `list(string)` | <pre>[<br/> "m5.large",<br/> "c5.large"<br/>]</pre> | no |
| <a name="input_job_queue_retention_in_seconds"></a> [job\_queue\_retention\_in\_seconds](#input\_job\_queue\_retention\_in\_seconds) | The number of seconds the job is held in the queue before it is purged. | `number` | `86400` | no |
| <a name="input_job_retry"></a> [job\_retry](#input\_job\_retry) | Experimental! Can be removed / changed without trigger a major release.Configure job retries. The configuration enables job retries (for ephemeral runners). After creating the instances a message will be published to a job retry queue. The job retry check lambda is checking after a delay if the job is queued. If not the message will be published again on the scale-up (build queue). Using this feature can impact the rate limit of the GitHub app.<br/><br/>`enable`: Enable or disable the job retry feature.<br/>`delay_in_seconds`: The delay in seconds before the job retry check lambda will check the job status.<br/>`delay_backoff`: The backoff factor for the delay.<br/>`lambda_memory_size`: Memory size limit in MB for the job retry check lambda.<br/>`lambda_timeout`: Time out of the job retry check lambda in seconds.<br/>`max_attempts`: The maximum number of attempts to retry the job. | <pre>object({<br/> enable = optional(bool, false)<br/> delay_in_seconds = optional(number, 300)<br/> delay_backoff = optional(number, 2)<br/> lambda_memory_size = optional(number, 256)<br/> lambda_timeout = optional(number, 30)<br/> max_attempts = optional(number, 1)<br/> })</pre> | `{}` | no |
| <a name="input_key_name"></a> [key\_name](#input\_key\_name) | Key pair name | `string` | `null` | no |
Expand Down Expand Up @@ -196,11 +196,12 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
| <a name="input_runner_hook_job_completed"></a> [runner\_hook\_job\_completed](#input\_runner\_hook\_job\_completed) | Script to be ran in the runner environment at the end of every job | `string` | `""` | no |
| <a name="input_runner_hook_job_started"></a> [runner\_hook\_job\_started](#input\_runner\_hook\_job\_started) | Script to be ran in the runner environment at the beginning of every job | `string` | `""` | no |
| <a name="input_runner_iam_role_managed_policy_arns"></a> [runner\_iam\_role\_managed\_policy\_arns](#input\_runner\_iam\_role\_managed\_policy\_arns) | Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role | `list(string)` | `[]` | no |
| <a name="input_runner_license_specifications"></a> [runner\_license\_specifications](#input\_runner\_license\_specifications) | The license specifications for the instance. See https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template#license_specification for details. | <pre>list(object({<br/> license_configuration_arn = string<br/> }))</pre> | `[]` | no |
| <a name="input_runner_log_files"></a> [runner\_log\_files](#input\_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. | <pre>list(object({<br/> log_group_name = string<br/> prefix_log_group = bool<br/> file_path = string<br/> log_stream_name = string<br/> }))</pre> | `null` | no |
| <a name="input_runner_metadata_options"></a> [runner\_metadata\_options](#input\_runner\_metadata\_options) | Metadata options for the ec2 runner instances. By default, the module uses metadata tags for bootstrapping the runner, only disable `instance_metadata_tags` when using custom scripts for starting the runner. | `map(any)` | <pre>{<br/> "http_endpoint": "enabled",<br/> "http_put_response_hop_limit": 1,<br/> "http_tokens": "required",<br/> "instance_metadata_tags": "enabled"<br/>}</pre> | no |
| <a name="input_runner_name_prefix"></a> [runner\_name\_prefix](#input\_runner\_name\_prefix) | The prefix used for the GitHub runner name. The prefix will be used in the default start script to prefix the instance name when register the runner in GitHub. The value is available via an EC2 tag 'ghr:runner\_name\_prefix'. | `string` | `""` | no |
| <a name="input_runner_os"></a> [runner\_os](#input\_runner\_os) | The EC2 Operating System type to use for action runner instances (linux,windows). | `string` | `"linux"` | no |
| <a name="input_runner_placement"></a> [runner\_placement](#input\_runner\_placement) | The placement options for the instance. See https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template#placement for details. | <pre>object({<br/> affinity = optional(string)<br/> availability_zone = optional(string)<br/> group_id = optional(string)<br/> group_name = optional(string)<br/> host_id = optional(string)<br/> host_resource_group_arn = optional(number)<br/> spread_domain = optional(string)<br/> tenancy = optional(string)<br/> partition_number = optional(number)<br/> })</pre> | `null` | no |
| <a name="input_runner_os"></a> [runner\_os](#input\_runner\_os) | The EC2 Operating System type to use for action runner instances (linux, osx, windows). | `string` | `"linux"` | no |
| <a name="input_runner_placement"></a> [runner\_placement](#input\_runner\_placement) | The placement options for the instance. See https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template#placement for details. | <pre>object({<br/> affinity = optional(string)<br/> availability_zone = optional(string)<br/> group_id = optional(string)<br/> group_name = optional(string)<br/> host_id = optional(string)<br/> host_resource_group_arn = optional(string)<br/> spread_domain = optional(string)<br/> tenancy = optional(string)<br/> partition_number = optional(number)<br/> })</pre> | `null` | no |
| <a name="input_runner_run_as"></a> [runner\_run\_as](#input\_runner\_run\_as) | Run the GitHub actions agent as user. | `string` | `"ec2-user"` | no |
| <a name="input_runners_ebs_optimized"></a> [runners\_ebs\_optimized](#input\_runners\_ebs\_optimized) | Enable EBS optimization for the runner instances. | `bool` | `false` | no |
| <a name="input_runners_lambda_s3_key"></a> [runners\_lambda\_s3\_key](#input\_runners\_lambda\_s3\_key) | S3 key for runners lambda function. Required if using S3 bucket to specify lambdas. | `string` | `null` | no |
Expand Down
42 changes: 42 additions & 0 deletions examples/dedicated-mac-hosts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 6.21 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 6.21 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [aws_ec2_host.mac_dedicated_host](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_host) | resource |
| [aws_licensemanager_license_configuration.mac_dedicated_host_license_configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/licensemanager_license_configuration) | resource |
| [aws_resourcegroups_group.mac_host_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/resourcegroups_group) | resource |
| [aws_resourcegroups_resource.mac_host_membership](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/resourcegroups_resource) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | AWS region. | `string` | n/a | yes |
| <a name="input_environment"></a> [environment](#input\_environment) | Environment name, used as prefix. | `string` | `null` | no |
| <a name="input_host_groups"></a> [host\_groups](#input\_host\_groups) | Map of host groups, each with a name, host instance type, and a list of hosts (name + AZ). | <pre>map(object({<br/> name = string<br/> host_instance_type = string<br/> hosts = list(object({<br/> name = string<br/> availability_zone = string<br/> }))<br/> }))</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_license_specification_arn"></a> [license\_specification\_arn](#output\_license\_specification\_arn) | ARN of the License Manager configuration used for Mac dedicated hosts. |
| <a name="output_resource_group_arns"></a> [resource\_group\_arns](#output\_resource\_group\_arns) | Map of resource group names to their ARNs. |
<!-- END_TF_DOCS -->
105 changes: 105 additions & 0 deletions examples/dedicated-mac-hosts/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
locals {

environment = var.environment != null ? var.environment : "default"
aws_region = var.aws_region

# Flatten host_groups into a map of individual host definitions keyed by
# "groupKey-hostName" so we can create one aws_ec2_host per host.
mac_dedicated_hosts = merge([
for group_key, group in var.host_groups : {
for host in group.hosts :
"${group_key}-${host.name}" => {
instance_type = group.host_instance_type
availability_zone = host.availability_zone
group_name = group.name
host_name = host.name
}
}
]...)
}

resource "aws_ec2_host" "mac_dedicated_host" {
for_each = local.mac_dedicated_hosts

instance_type = each.value.instance_type
availability_zone = each.value.availability_zone
auto_placement = "on"

tags = {
"Name" = each.value.host_name
"HostGroup" = each.value.group_name
}
}

resource "aws_resourcegroups_group" "mac_host_group" {
for_each = { for _, group in var.host_groups : group.name => group }

name = each.value.name

configuration {
type = "AWS::EC2::HostManagement"

parameters {
name = "any-host-based-license-configuration"
values = ["true"]
}

parameters {
name = "auto-allocate-host"
values = [
"false",
]
}
parameters {
name = "auto-host-recovery"
values = [
"false",
]
}
parameters {
name = "auto-release-host"
values = [
"false",
]
}
}

configuration {
type = "AWS::ResourceGroups::Generic"
parameters {
name = "allowed-resource-types"
values = [
"AWS::EC2::Host",
]
}

parameters {
name = "deletion-protection"
values = [
"UNLESS_EMPTY",
]
}
}

tags = {
"Name" = each.value.name
}
}

resource "aws_resourcegroups_resource" "mac_host_membership" {
for_each = local.mac_dedicated_hosts

group_arn = aws_resourcegroups_group.mac_host_group[each.value.group_name].arn
resource_arn = aws_ec2_host.mac_dedicated_host[each.key].arn
}


resource "aws_licensemanager_license_configuration" "mac_dedicated_host_license_configuration" {
name = "mac-dedicated-host-license-configuration"
description = "Mac dedicated host license configuration"
license_counting_type = "Socket"

tags = {
"Name" = each.value.name
}
}
12 changes: 12 additions & 0 deletions examples/dedicated-mac-hosts/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
output "resource_group_arns" {
description = "Map of resource group names to their ARNs."
value = {
for k, rg in aws_resourcegroups_group.mac_host_group :
rg.name => rg.arn
}
}

output "license_specification_arn" {
description = "ARN of the License Manager configuration used for Mac dedicated hosts."
value = aws_licensemanager_license_configuration.mac_dedicated_host_license_configuration.arn
}
9 changes: 9 additions & 0 deletions examples/dedicated-mac-hosts/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
provider "aws" {
region = local.aws_region

default_tags {
tags = {
Example = local.environment
}
}
}
23 changes: 23 additions & 0 deletions examples/dedicated-mac-hosts/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
variable "aws_region" {
description = "AWS region."
type = string
}

variable "environment" {
description = "Environment name, used as prefix."

type = string
default = null
}

variable "host_groups" {
description = "Map of host groups, each with a name, host instance type, and a list of hosts (name + AZ)."
type = map(object({
name = string
host_instance_type = string
hosts = list(object({
name = string
availability_zone = string
}))
}))
}
10 changes: 10 additions & 0 deletions examples/dedicated-mac-hosts/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 6.21"
}
}

required_version = ">= 1.3.0"
}
2 changes: 1 addition & 1 deletion examples/prebuilt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ terraform output webhook_secret
| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | AWS region. | `string` | `"eu-west-1"` | no |
| <a name="input_environment"></a> [environment](#input\_environment) | Environment name, used as prefix. | `string` | `null` | no |
| <a name="input_github_app"></a> [github\_app](#input\_github\_app) | GitHub for API usages. | <pre>object({<br/> id = string<br/> key_base64 = string<br/> })</pre> | n/a | yes |
| <a name="input_runner_os"></a> [runner\_os](#input\_runner\_os) | The EC2 Operating System type to use for action runner instances (linux,windows). | `string` | `"linux"` | no |
| <a name="input_runner_os"></a> [runner\_os](#input\_runner\_os) | The EC2 Operating System type to use for action runner instances (linux, osx, windows). | `string` | `"linux"` | no |

## Outputs

Expand Down
2 changes: 1 addition & 1 deletion examples/prebuilt/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ variable "aws_region" {
}

variable "runner_os" {
description = "The EC2 Operating System type to use for action runner instances (linux,windows)."
description = "The EC2 Operating System type to use for action runner instances (linux, osx, windows)."

type = string
default = "linux"
Expand Down
1 change: 1 addition & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ module "runners" {
credit_specification = var.runner_credit_specification
cpu_options = var.runner_cpu_options
placement = var.runner_placement
license_specifications = var.runner_license_specifications

enable_runner_binaries_syncer = var.enable_runner_binaries_syncer
lambda_s3_bucket = var.lambda_s3_bucket
Expand Down
2 changes: 1 addition & 1 deletion modules/multi-runner/README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions modules/multi-runner/runners.tf
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ module "runners" {
credit_specification = each.value.runner_config.credit_specification
cpu_options = each.value.runner_config.cpu_options
placement = each.value.runner_config.placement
license_specifications = each.value.runner_config.license_specifications

enable_runner_binaries_syncer = each.value.runner_config.enable_runner_binaries_syncer
lambda_s3_bucket = var.lambda_s3_bucket
Expand Down
9 changes: 6 additions & 3 deletions modules/multi-runner/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,14 @@ variable "multi_runner_config" {
group_id = optional(string)
group_name = optional(string)
host_id = optional(string)
host_resource_group_arn = optional(number)
host_resource_group_arn = optional(string)
spread_domain = optional(string)
tenancy = optional(string)
partition_number = optional(number)
}), null)
license_specifications = optional(list(object({
license_configuration_arn = string
})), [])
runner_log_files = optional(list(object({
log_group_name = string
prefix_log_group = bool
Expand Down Expand Up @@ -196,7 +199,7 @@ variable "multi_runner_config" {
description = <<EOT
multi_runner_config = {
runner_config: {
runner_os: "The EC2 Operating System type to use for action runner instances (linux,windows)."
runner_os: "The EC2 Operating System type to use for action runner instances (linux, osx, windows)."
runner_architecture: "The platform architecture of the runner instance_type."
runner_metadata_options: "(Optional) Metadata options for the ec2 runner instances."
ami: "(Optional) AMI configuration for the action runner instances. This object allows you to specify all AMI-related settings in one place."
Expand All @@ -216,7 +219,7 @@ variable "multi_runner_config" {
instance_allocation_strategy: "The allocation strategy for spot instances. AWS recommends to use `capacity-optimized` however the AWS default is `lowest-price`."
instance_max_spot_price: "Max price price for spot instances per hour. This variable will be passed to the create fleet as max spot price for the fleet."
instance_target_capacity_type: "Default lifecycle used for runner instances, can be either `spot` or `on-demand`."
instance_types: "List of instance types for the action runner. Defaults are based on runner_os (al2023 for linux and Windows Server Core for win)."
instance_types: "List of instance types for the action runner. Defaults are based on runner_os (al2023 for linux, macOS Sequoia for osx, Windows Server Core for win)."
job_queue_retention_in_seconds: "The number of seconds the job is held in the queue before it is purged"
minimum_running_time_in_minutes: "The time an ec2 action runner should be running at minimum before terminated if not busy."
pool_runner_owner: "The pool will deploy runners to the GitHub org ID, set this value to the org to which you want the runners deployed. Repo level is not supported."
Expand Down
Loading