Skip to content
Merged
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
2 changes: 1 addition & 1 deletion examples/multi-runner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ terraform output -raw webhook_secret

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.4.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 6.33 |
| <a name="requirement_local"></a> [local](#requirement\_local) | ~> 2.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | ~> 3.0 |
Expand Down
2 changes: 1 addition & 1 deletion examples/multi-runner/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ terraform {
version = "~> 3.0"
}
}
required_version = ">= 1.3.0"
required_version = ">= 1.4.0"
}
71 changes: 71 additions & 0 deletions modules/multi-runner/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 12 additions & 45 deletions modules/multi-runner/README.md

Large diffs are not rendered by default.

15 changes: 12 additions & 3 deletions modules/multi-runner/runners.experimental.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,18 @@ module "runner_configs" {
runner = each.value.runner
github = merge(each.value.github, {
app_parameters = {
key_base64 = [local.github_app_parameters.key_base64]
id = [local.github_app_parameters.id]
installation_id = [null]
id = concat(
[local.primary_app_id],
[for app in module.ssm.additional_app_parameters : app.id],
)
key_base64 = concat(
[local.primary_app_key_base64],
[for app in module.ssm.additional_app_parameters : app.key_base64],
)
installation_id = concat(
[null],
[for app in module.ssm.additional_app_parameters : app.installation_id],
)
}
})
lambda = each.value.lambda
Expand Down
35 changes: 35 additions & 0 deletions modules/multi-runner/tests/config-effective.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,32 @@ run "v2_effective_config_contains_derived_values" {
id = "experimental-app-id"
webhook_secret = "experimental-webhook-secret"
}
additional_apps = [
{
key_base64_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/additional-0/key"
name = "/tests/github-app/additional-0/key"
}
id_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/additional-0/id"
name = "/tests/github-app/additional-0/id"
}
installation_id_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/additional-0/installation-id"
name = "/tests/github-app/additional-0/installation-id"
}
},
{
key_base64_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/additional-1/key"
name = "/tests/github-app/additional-1/key"
}
id_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/additional-1/id"
name = "/tests/github-app/additional-1/id"
}
},
]
}

global_config_lambda = {
Expand Down Expand Up @@ -249,4 +275,13 @@ run "v2_effective_config_contains_derived_values" {
)
error_message = "The effective v2 configuration must contain global values, derived labels, and the resolved runner-binary target map."
}

assert {
condition = (
module.runner_configs["lane"].scale_up.lambda.environment[0].variables["PARAMETER_GITHUB_APP_ID_NAME"] == "/github-action-runners/github-actions/app/github_app_id:/tests/github-app/additional-0/id:/tests/github-app/additional-1/id"
&& module.runner_configs["lane"].scale_up.lambda.environment[0].variables["PARAMETER_GITHUB_APP_KEY_BASE64_NAME"] == "/github-action-runners/github-actions/app/github_app_key_base64:/tests/github-app/additional-0/key:/tests/github-app/additional-1/key"
&& module.runner_configs["lane"].scale_up.lambda.environment[0].variables["PARAMETER_GITHUB_APP_INSTALLATION_ID_NAME"] == ":/tests/github-app/additional-0/installation-id:"
)
error_message = "The v2 runner-config adapter must preserve primary and additional GitHub App parameter ordering."
}
}
102 changes: 78 additions & 24 deletions modules/multi-runner/tests/config-resolution.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -59,30 +59,9 @@ mock_provider "random" {}
mock_provider "null" {}

variables {
aws_region = "eu-west-1"
vpc_id = "vpc-stable"
subnet_ids = ["subnet-stable"]

github_app = {
key_base64_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/key"
name = "/tests/github-app/key"
}
id_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/id"
name = "/tests/github-app/id"
}
webhook_secret_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/webhook-secret"
name = "/tests/github-app/webhook-secret"
}
}

lambda_s3_bucket = "test-lambda-artifacts"
runners_lambda_zip = "README.md"
runners_lambda_s3_key = "runners.zip"
webhook_lambda_s3_key = "webhook.zip"
syncer_lambda_s3_key = "runner-binaries-syncer.zip"
aws_region = "eu-west-1"
prefix = "test"
aws_partition = "aws"

global_config_github = {
app = {
Expand Down Expand Up @@ -152,6 +131,30 @@ run "v1_stable_inputs_translate_into_effective_base" {
command = plan

variables {
vpc_id = "vpc-stable"
subnet_ids = ["subnet-stable"]

github_app = {
key_base64_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/key"
name = "/tests/github-app/key"
}
id_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/id"
name = "/tests/github-app/id"
}
webhook_secret_ssm = {
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/tests/github-app/webhook-secret"
name = "/tests/github-app/webhook-secret"
}
}

lambda_s3_bucket = "test-lambda-artifacts"
runners_lambda_zip = "README.md"
runners_lambda_s3_key = "runners.zip"
webhook_lambda_s3_key = "webhook.zip"
syncer_lambda_s3_key = "runner-binaries-syncer.zip"

tags = {
source = "v1"
}
Expand Down Expand Up @@ -393,3 +396,54 @@ run "v2_inputs_resolve_lane_over_global" {
error_message = "Experimental v2 configurations must route through module.runner_configs and skip the legacy runners module."
}
}

run "v2_inputs_do_not_require_legacy_arguments" {
command = plan

variables {
experimental_features = ["multi-runner-v2"]

global_config_compute_provider = {
aws = {
ec2 = {
vpc_id = "vpc-v2"
subnet_ids = ["subnet-v2"]
runner_binaries = {
enabled = false
}
}
}
}
multi_runner_config = {
lane = {
orchestration_provider = {
webhook = {
matcherConfig = {
labelMatchers = [["self-hosted", "linux", "x64"]]
}
}
}
compute_provider = {
aws = {
ec2 = {
instance_types = ["m5.large"]
binaries_syncer = {
enabled = false
}
}
}
}
}
}
}

assert {
condition = (
local.use_v2_config
&& keys(module.runner_configs) == ["lane"]
&& length(module.runners) == 0
&& local.resolved_config.multi_runner_config["lane"].compute_provider.aws.ec2.vpc_id == "vpc-v2"
)
error_message = "The v2 interface must work without the stable v1 GitHub App, VPC, subnet, or runner configuration inputs."
}
}
81 changes: 81 additions & 0 deletions modules/multi-runner/validations.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
locals {
common_validation_errors = concat(
alltrue([
for app in var.additional_github_apps :
(app.key_base64 != null || app.key_base64_ssm != null) &&
(app.id != null || app.id_ssm != null)
]) ? [] : ["Each additional GitHub app must provide either key_base64 or key_base64_ssm, and either id or id_ssm."],
contains(["STANDARD", "INFREQUENT_ACCESS"], var.log_class) ? [] : ["`log_class` must be either `STANDARD` or `INFREQUENT_ACCESS`."],
contains(["first", "random", "all"], var.queue_selection_strategy) ? [] : ["`queue_selection_strategy` value not valid. Valid values are 'first', 'random', 'all'."],
contains(["silly", "trace", "debug", "info", "warn", "error", "fatal"], var.log_level) ? [] : ["`log_level` value not valid. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'."],
contains(["arm64", "x86_64"], var.lambda_architecture) ? [] : ["`lambda_architecture` value is not valid, valid values are: `arm64` and `x86_64`."],
contains(["ENABLED", "DISABLED", "ENABLED_WITH_ALL_CLOUDTRAIL_MANAGEMENT_EVENTS"], var.state_event_rule_binaries_syncer) ? [] : ["`state_event_rule_binaries_syncer` value is not valid, valid values are: `ENABLED`, `DISABLED`, `ENABLED_WITH_ALL_CLOUDTRAIL_MANAGEMENT_EVENTS`."],
var.queue_encryption == null || var.queue_encryption.sqs_managed_sse_enabled != null && var.queue_encryption.kms_master_key_id == null && var.queue_encryption.kms_data_key_reuse_period_seconds == null || var.queue_encryption.sqs_managed_sse_enabled == null && var.queue_encryption.kms_master_key_id != null ? [] : ["Invalid configuration for `queue_encryption`. Valid configurations are encryption disabled, enabled via SSE. Or encryption via KMS."],
contains(["Standard", "Advanced"], var.matcher_config_parameter_store_tier) ? [] : ["`matcher_config_parameter_store_tier` value is not valid, valid values are: `Standard`, and `Advanced`."],
!var.iam_overrides.override_instance_profile || var.iam_overrides.instance_profile_name != null ? [] : ["instance_profile_name must be provided when override_instance_profile is true."],
!var.iam_overrides.override_runner_role || var.iam_overrides.runner_role_arn != null ? [] : ["runner_role_arn must be provided when override_runner_role is true."]
)
}

resource "terraform_data" "validate_v1" {
count = local.use_v2_config ? 0 : 1

lifecycle {
precondition {
condition = length(local.common_validation_errors) == 0
error_message = join("\n", local.common_validation_errors)
}

precondition {
condition = (
(var.github_app.key_base64 != null || var.github_app.key_base64_ssm != null) &&
(var.github_app.id != null || var.github_app.id_ssm != null) &&
(var.github_app.webhook_secret != null || var.github_app.webhook_secret_ssm != null) &&
var.vpc_id != null &&
var.subnet_ids != null &&
length(var.multi_runner_config) > 0
)
error_message = "Stable v1 configuration requires github_app, vpc_id, subnet_ids, and multi_runner_config."
}
}
}

resource "terraform_data" "validate_v2" {
count = local.use_v2_config ? 1 : 0

lifecycle {
precondition {
condition = length(local.common_validation_errors) == 0
error_message = join("\n", local.common_validation_errors)
}

precondition {
condition = (
(
try(var.global_config_github.app.key_base64, null) != null ||
try(var.global_config_github.app.key_base64_ssm, null) != null
) && (
try(var.global_config_github.app.id, null) != null ||
try(var.global_config_github.app.id_ssm, null) != null
) && (
try(var.global_config_github.app.webhook_secret, null) != null ||
try(var.global_config_github.app.webhook_secret_ssm, null) != null
)
)
error_message = "Experimental v2 configuration requires a complete GitHub App under global_config_github.app."
}

precondition {
condition = alltrue([
for config in local.resolved_config.multi_runner_config : (
try(config.orchestration_provider.webhook != null, false) &&
try(config.compute_provider.aws.ec2 != null, false) &&
try(length(config.compute_provider.aws.ec2.instance_types) > 0, false) &&
try(config.compute_provider.aws.ec2.vpc_id != null, false) &&
try(length(config.compute_provider.aws.ec2.subnet_ids) > 0, false)
)
])
error_message = "Each experimental v2 runner lane requires a webhook provider, EC2 instance_types, vpc_id, and at least one subnet."
}
}
}
Loading
Loading