Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 42 additions & 10 deletions modules/platform/ec2_deployment/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ locals {
}

module "ec2_update_runner_ssm_ami" {
count = length(local.ec2_runner_configs) > 0 ? 1 : 0
source = "./ec2_update_runner_ssm_ami"

providers = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module "ec2_update_runner_tags" {
count = length(local.ec2_runner_configs) > 0 ? 1 : 0
source = "./ec2_update_runner_tags"

providers = {
Expand Down
36 changes: 23 additions & 13 deletions modules/platform/ec2_deployment/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ locals {
terraform_aws_github_runner_tags = merge(
var.tenant_configs.tags,
{
terraform-aws-github-runner-ref = "v7.11.0"
terraform-aws-github-runner-ref = "fix-multi-runner-v2-routing"
}
)
webhook_api_gateway_access_log_format = jsonencode({
Expand Down Expand Up @@ -67,7 +67,13 @@ data "aws_subnet" "runner_subnet" {
}

data "external" "download_lambdas" {
program = ["bash", "${path.module}/scripts/download_lambdas.sh", "/tmp/${var.runner_configs.prefix}/", "v7.11.0", "github-aws-runners/terraform-aws-github-runner"]
count = (
length(local.ec2_runner_configs) > 0
|| try(var.runner_configs.lambda_artifacts.control_plane_zip, null) == null
|| try(var.runner_configs.lambda_artifacts.webhook_zip, null) == null
) ? 1 : 0

program = ["bash", "${path.module}/scripts/download_lambdas.sh", "/tmp/${var.runner_configs.prefix}/v7.10.1/", "v7.10.1", "github-aws-runners/terraform-aws-github-runner"]
}

# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -105,6 +111,8 @@ resource "aws_ssm_parameter" "hook_job_completed" {
}

data "aws_iam_policy_document" "runner_hooks_ssm_read" {
count = length(local.ec2_runner_configs) > 0 ? 1 : 0

statement {
sid = "ReadRunnerHookParameters"
effect = "Allow"
Expand All @@ -117,9 +125,11 @@ data "aws_iam_policy_document" "runner_hooks_ssm_read" {
}

resource "aws_iam_policy" "runner_hooks_ssm_read" {
count = length(local.ec2_runner_configs) > 0 ? 1 : 0
name = "${var.runner_configs.prefix}-runner-hooks-ssm-read"
path = "/"
description = "Allow runners to read their gzip'd job-hook scripts from SSM."
policy = data.aws_iam_policy_document.runner_hooks_ssm_read.json
policy = data.aws_iam_policy_document.runner_hooks_ssm_read[0].json
tags = var.tenant_configs.tags
}

Expand All @@ -136,18 +146,18 @@ module "runners" {

github_app = var.runner_configs.github_app

multi_runner_config = {}
experimental_features = ["multi-runner-v2"]

experimental_global_config = {
tags = local.experimental_config.tags
global_config = {
tags = local.global_config.tags
}
experimental_global_config_github = local.experimental_config.github
experimental_global_config_lambda = local.experimental_config.lambda
experimental_global_config_orchestration_provider = local.experimental_config.orchestration_provider
experimental_global_config_ssm = local.experimental_config.ssm
experimental_global_config_observability = local.experimental_config.observability
experimental_global_config_compute_provider = local.experimental_config.compute_provider
experimental_multi_runner_config = local.multi_runner_config
global_config_github = local.global_config.github
global_config_lambda = local.global_config.lambda
global_config_orchestration_provider = local.global_config.orchestration_provider
global_config_ssm = local.global_config.ssm
global_config_observability = local.global_config.observability
global_config_compute_provider = local.global_config.compute_provider
multi_runner_config = local.multi_runner_config

depends_on = [
data.external.download_lambdas,
Expand Down
19 changes: 19 additions & 0 deletions modules/platform/ec2_deployment/moved.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
moved {
from = aws_iam_policy.ec2_tags
to = aws_iam_policy.ec2_tags[0]
}

moved {
from = aws_iam_policy.runner_hooks_ssm_read
to = aws_iam_policy.runner_hooks_ssm_read[0]
}

moved {
from = module.ec2_update_runner_ssm_ami
to = module.ec2_update_runner_ssm_ami[0]
}

moved {
from = module.ec2_update_runner_tags
to = module.ec2_update_runner_tags[0]
}
44 changes: 42 additions & 2 deletions modules/platform/ec2_deployment/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@ output "webhook_endpoint" {

output "ec2_runners_arn_map" {
value = {
for runner_key, runner in module.runners.runners_map_v2 : runner_key => coalesce(
try(runner.runner.role.arn, null),
for runner_key in keys(local.ec2_runner_configs) : runner_key => coalesce(
try(module.runners.runners_map_v2[runner_key].runner.role.arn, null),
try(local.ec2_runner_configs[runner_key].runner.iam.role.arn, null),
)
}
description = "Map of EC2 runner keys to their IAM role ARNs."
}

output "runners_arn_map" {
value = {
for runner_key, runner in module.runners.runners_map_v2 : runner_key => coalesce(
try(runner.runner.role.arn, null),
try(runner.provider.aws.microvm.execution_role_arn, null),
try(local.runner_configs[runner_key].runner.iam.role.arn, null),
)
}
description = "Map of runner keys to their resolved EC2 or Lambda MicroVM execution-role ARNs."
}

output "ec2_runners_ami_name_map" {
value = {
for runner_key in keys(local.ec2_runner_configs) : runner_key => data.aws_ami.runner_ami[runner_key].name
Expand All @@ -27,6 +38,35 @@ output "ec2_runners_labels_map" {
description = "Map of EC2 runner keys to their base and extra GitHub labels."
}

output "runners_labels_map" {
value = local.runner_labels
description = "Map of runner keys to their base and extra GitHub labels."
}

output "microvm_runners_arn_map" {
value = {
for runner_key in keys(local.microvm_runner_configs) :
runner_key => module.runners.runners_map_v2[runner_key].provider.aws.microvm.execution_role_arn
}
description = "Map of Lambda MicroVM runner keys to their execution-role ARNs."
}

output "microvm_runners_labels_map" {
value = {
for runner_key in keys(local.microvm_runner_configs) :
runner_key => local.runner_labels[runner_key]
}
description = "Map of Lambda MicroVM runner keys to their base and extra GitHub labels."
}

output "microvm_runners_map" {
value = {
for runner_key in keys(local.microvm_runner_configs) :
runner_key => module.runners.runners_map_v2[runner_key].provider.aws.microvm
}
description = "Map of Lambda MicroVM runner keys to their provider-owned image, execution-role, and runtime log-group outputs."
}

output "subnet_cidr_blocks" {
value = { for id, subnet in data.aws_subnet.runner_subnet : id => subnet.cidr_block }
description = "Map of EC2 runner subnet IDs to their CIDR blocks."
Expand Down
2 changes: 2 additions & 0 deletions modules/platform/ec2_deployment/roles.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ data "aws_iam_policy_document" "ec2_tags" {

# Define the actual IAM policy for EC2 tags
resource "aws_iam_policy" "ec2_tags" {
count = length(local.ec2_runner_configs) > 0 ? 1 : 0
name = "${var.runner_configs.prefix}-policy-for-ec2-tags"
path = "/"
description = "Policy that allows EC2 instances to create tags on themselves."
policy = data.aws_iam_policy_document.ec2_tags.json

Expand Down
98 changes: 69 additions & 29 deletions modules/platform/ec2_deployment/runner_configs_v2.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
locals {
ec2_runner_configs = var.runner_configs.runner_specs
runner_configs = var.runner_configs.runner_specs
runner_binaries_default_enabled = true
runner_iam_policy_arn_prefix = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:policy"
runner_binaries_targets = {
for target in distinct([
for runner_config in values(var.runner_configs.runner_specs) : {
os = runner_config.runner.os
architecture = runner_config.runner.architecture
}
if(
length(try(runner_config.compute_provider.aws.ec2[*], [])) == 1
&& coalesce(
try(runner_config.compute_provider.aws.ec2.binaries_syncer.enabled, null),
local.runner_binaries_default_enabled,
)
)
]) : "${target.os}_${target.architecture}" => target
}
compute_provider_selections = {
for runner_key, runner_config in var.runner_configs.runner_specs : runner_key => {
namespace = "aws"
type = (
length(try(runner_config.compute_provider.aws.ec2[*], [])) == 1 ? "ec2" :
length(try(runner_config.compute_provider.aws.microvm[*], [])) == 1 ? "microvm" : null
)
}
}
ec2_runner_configs = {
for key, runner_config in local.runner_configs : key => runner_config
if length(try(runner_config.compute_provider.aws.ec2[*], [])) == 1
}
microvm_runner_configs = {
for key, runner_config in local.runner_configs : key => runner_config
if length(try(runner_config.compute_provider.aws.microvm[*], [])) == 1
}

effective_runner_users = {
for key, runner_config in local.ec2_runner_configs :
Expand Down Expand Up @@ -89,7 +123,7 @@ locals {
}

legacy_runner_labels = {
for key, runner_config in local.ec2_runner_configs :
for key, runner_config in local.runner_configs :
key => concat(
try(runner_config.orchestration_provider.webhook.matcherConfig.labelMatchers[0], []),
coalesce(runner_config.runner.extra_labels, []),
Expand All @@ -100,7 +134,7 @@ locals {
# only new labels introduced by additional v2 matchers. The upstream v1 module
# separately sorts the corresponding set before registering runners.
runner_labels = {
for key, runner_config in local.ec2_runner_configs :
for key, runner_config in local.runner_configs :
key => concat(
local.legacy_runner_labels[key],
distinct([
Expand Down Expand Up @@ -181,15 +215,15 @@ locals {
}
)
log_files = coalesce(runner_config.compute_provider.aws.ec2.log_files, local.forge_ec2_log_files[key])
tags = merge(var.tenant_configs.tags, runner_config.compute_provider.aws.ec2.tags)
tags = runner_config.compute_provider.aws.ec2.tags
}
)
}

# Preserve Forge-managed runner hooks, policies, bootstrap content, logging,
# and tags while passing the public nested contract directly to upstream v2.
# Preserve the provider-neutral lane contract while applying Forge's EC2
# bootstrap, lifecycle-hook, and policy overlays only to EC2 lanes.
multi_runner_config = {
for key, runner_config in local.ec2_runner_configs :
for key, runner_config in local.runner_configs :
key => merge(runner_config, {
observability = merge(runner_config.observability, {
metrics = merge(runner_config.observability.metrics, {
Expand All @@ -214,10 +248,10 @@ locals {
})
})
runner = merge(runner_config.runner, {
hooks = {
hooks = contains(keys(local.ec2_runner_configs), key) ? {
job_started = local.runner_hook_job_started[key]
job_completed = local.runner_hook_job_completed[key]
}
} : runner_config.runner.hooks
iam = merge(runner_config.runner.iam, {
managed_policy_arns = merge(
coalesce(runner_config.runner.iam.managed_policy_arns, {}),
Expand All @@ -226,10 +260,10 @@ locals {
for policy_index, policy_arn in var.runner_configs.runner_iam_role_managed_policy_arns :
"forge-config-${policy_index}" => policy_arn
},
{
forge_ec2_tags = aws_iam_policy.ec2_tags.arn
forge_runner_hooks_ssm_read = aws_iam_policy.runner_hooks_ssm_read.arn
},
contains(keys(local.ec2_runner_configs), key) ? {
forge_ec2_tags = "${local.runner_iam_policy_arn_prefix}${aws_iam_policy.ec2_tags[0].path}${aws_iam_policy.ec2_tags[0].name}"
forge_runner_hooks_ssm_read = "${local.runner_iam_policy_arn_prefix}${aws_iam_policy.runner_hooks_ssm_read[0].path}${aws_iam_policy.runner_hooks_ssm_read[0].name}"
} : {},
) : {},
)
})
Expand All @@ -245,21 +279,24 @@ locals {
})
})
}
compute_provider = {
aws = {
ec2 = merge(local.ec2_compute_provider[key], {
on_demand_failover_for_errors = coalesce(
try(runner_config.compute_provider.aws.ec2.on_demand_failover_for_errors, null),
try(runner_config.compute_provider.aws.ec2.enable_on_demand_failover_for_errors, null),
[],
)
})
}
}
compute_provider = merge(runner_config.compute_provider, {
aws = merge(runner_config.compute_provider.aws, {
ec2 = try(local.ec2_compute_provider[key], null)
})
})
})
}

experimental_config = {
control_plane_lambda_zip = try(coalesce(
try(var.runner_configs.lambda_artifacts.control_plane_zip, null),
try("${data.external.download_lambdas[0].result.path}/runners.zip", null),
), null)
webhook_lambda_zip = try(coalesce(
try(var.runner_configs.lambda_artifacts.webhook_zip, null),
try("${data.external.download_lambdas[0].result.path}/webhook.zip", null),
), null)

global_config = {
tags = local.terraform_aws_github_runner_tags

github = {
Expand All @@ -282,11 +319,11 @@ locals {
}
lambda = {
artifact = {
zip = "${data.external.download_lambdas.result.path}/runners.zip"
zip = local.control_plane_lambda_zip
}
webhook = {
artifact = {
zip = "${data.external.download_lambdas.result.path}/webhook.zip"
zip = local.webhook_lambda_zip
}
api_gateway_access_log_settings = {
destination_arn = aws_cloudwatch_log_group.webhook_api_gateway_access.arn
Expand All @@ -305,7 +342,7 @@ locals {
housekeeper = {
lambda = {
artifact = {
zip = "${data.external.download_lambdas.result.path}/runners.zip"
zip = local.control_plane_lambda_zip
}
}
}
Expand All @@ -319,14 +356,17 @@ locals {
}

compute_provider = {
selections = local.compute_provider_selections
aws = {
ec2 = {
vpc_id = var.network_configs.vpc_id
subnet_ids = var.network_configs.subnet_ids
runner_binaries = {
enabled = local.runner_binaries_default_enabled
targets = local.runner_binaries_targets
syncer = {
artifact = {
zip = "${data.external.download_lambdas.result.path}/runner-binaries-syncer.zip"
zip = try("${data.external.download_lambdas[0].result.path}/runner-binaries-syncer.zip", null)
}
}
}
Expand Down
Loading