Skip to content

Commit c8c232b

Browse files
authored
feat: Support runner groups (#496)
* Support runner groups * Add runner group only for org runners * Add runner group only for org runners * Add runner group only for org runners * review comments
1 parent b7ccaf1 commit c8c232b

File tree

8 files changed

+72
-9
lines changed

8 files changed

+72
-9
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ To apply the terraform module, the compiled lambdas (.zip files) need to be avai
113113

114114
To read the files from S3, set the `lambda_s3_bucket` variable and the specific object key for each lambda.
115115

116-
The lambdas can be downloaded maually from the [release page](https://github.com/philips-labs/terraform-aws-github-runner/releases) or using the [download-lambda](./modules/download-lambda) terraform module (requires `curl` to be installed on your machine). In the `download-lambda` directory, run `terraform init && terraform apply`. The lambdas will be saved to the same directory.
116+
The lambdas can be downloaded manually from the [release page](https://github.com/philips-labs/terraform-aws-github-runner/releases) or using the [download-lambda](./modules/download-lambda) terraform module (requires `curl` to be installed on your machine). In the `download-lambda` directory, run `terraform init && terraform apply`. The lambdas will be saved to the same directory.
117117

118118
For local development you can build all the lambdas at once using `.ci/build.sh` or individually using `yarn dist`.
119119

@@ -136,7 +136,7 @@ Note that `github_app.key_base64` needs to be the base64-encoded `.pem` file, i.
136136
```terraform
137137
module "github-runner" {
138138
source = "philips-labs/github-runner/aws"
139-
version = "0.8.0"
139+
version = "0.9.1"
140140
141141
aws_region = "eu-west-1"
142142
vpc_id = "vpc-123"
@@ -336,6 +336,7 @@ No requirements.
336336
| runner\_binaries\_syncer\_lambda\_timeout | Time out of the binaries sync lambda in seconds. | `number` | `300` | no |
337337
| runner\_binaries\_syncer\_lambda\_zip | File location of the binaries sync lambda zip file. | `string` | `null` | no |
338338
| runner\_extra\_labels | Extra labels for the runners (GitHub). Separate each label by a comma | `string` | `""` | no |
339+
| runner\_group\_name | Name of the runner group. | `string` | `"Default"` | no |
339340
| runner\_iam\_role\_managed\_policy\_arns | Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role | `list(string)` | `[]` | no |
340341
| 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> | <pre>[<br> {<br> "file_path": "/var/log/messages",<br> "log_group_name": "messages",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> },<br> {<br> "file_path": "/var/log/user-data.log",<br> "log_group_name": "user_data",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> },<br> {<br> "file_path": "/home/ec2-user/actions-runner/_diag/Runner_**.log",<br> "log_group_name": "runner",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> }<br>]</pre> | no |
341342
| runners\_lambda\_s3\_key | S3 key for runners lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no |

modules/runners/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ No requirements.
9595
| runner\_architecture | The platform architecture of the runner instance\_type. | `string` | `"x64"` | no |
9696
| runner\_as\_root | Run the action runner under the root user. | `bool` | `false` | no |
9797
| runner\_extra\_labels | Extra labels for the runners (GitHub). Separate each label by a comma | `string` | `""` | no |
98+
| runner\_group\_name | Name of the runner group. | `string` | `"Default"` | no |
9899
| runner\_iam\_role\_managed\_policy\_arns | Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role | `list(string)` | `[]` | no |
99-
| runner\_log\_files | (optional) List of logfiles to send to cloudwatch, will onlybe usded if `enable_cloudwatch_agent` is set to true. Object description: `log_group_name`: Name of the log group, `prefix_log_group`: module will prefix the log group with `/github-self-hosted-runners/<var.environment>`, `file_path`: path to the log file, `log_stream_name`: name of the log stream. | <pre>list(object({<br> log_group_name = string<br> prefix_log_group = bool<br> file_path = string<br> log_stream_name = string<br> }))</pre> | <pre>[<br> {<br> "file_path": "/var/log/messages",<br> "log_group_name": "messages",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> },<br> {<br> "file_path": "/var/log/user-data.log",<br> "log_group_name": "user_data",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> },<br> {<br> "file_path": "/home/ec2-user/actions-runner/_diag/Runner_**.log",<br> "log_group_name": "runner",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> }<br>]</pre> | no |
100+
| runner\_log\_files | (optional) List of logfiles to send to cloudwatch, will only be used if `enable_cloudwatch_agent` is set to true. Object description: `log_group_name`: Name of the log group, `prefix_log_group`: If true, the log group name will be prefixed with `/github-self-hosted-runners/<var.environment>`, `file_path`: path to the log file, `log_stream_name`: name of the log stream. | <pre>list(object({<br> log_group_name = string<br> prefix_log_group = bool<br> file_path = string<br> log_stream_name = string<br> }))</pre> | <pre>[<br> {<br> "file_path": "/var/log/messages",<br> "log_group_name": "messages",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> },<br> {<br> "file_path": "/var/log/user-data.log",<br> "log_group_name": "user_data",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> },<br> {<br> "file_path": "/home/ec2-user/actions-runner/_diag/Runner_**.log",<br> "log_group_name": "runner",<br> "log_stream_name": "{instance_id}",<br> "prefix_log_group": true<br> }<br>]</pre> | no |
100101
| runners\_lambda\_s3\_key | S3 key for runners lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no |
101102
| runners\_lambda\_s3\_object\_version | S3 object version for runners lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no |
102103
| runners\_maximum\_count | The maximum number of runners that will be created. | `number` | `3` | no |

modules/runners/lambdas/runners/src/lambda.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { scaleUp } from './scale-runners/scale-up';
22
import { scaleDown } from './scale-runners/scale-down';
3-
import { SQSEvent } from 'aws-lambda';
3+
import { SQSEvent, ScheduledEvent } from 'aws-lambda';
44

55
module.exports.scaleUp = async (event: SQSEvent, context: any, callback: any) => {
66
console.dir(event, { depth: 5 });
@@ -15,7 +15,7 @@ module.exports.scaleUp = async (event: SQSEvent, context: any, callback: any) =>
1515
}
1616
};
1717

18-
module.exports.scaleDown = async (event: any, context: any, callback: any) => {
18+
module.exports.scaleDown = async (event: ScheduledEvent, context: any, callback: any) => {
1919
try {
2020
scaleDown();
2121
return callback(null);

modules/runners/lambdas/runners/src/scale-runners/scale-up.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ describe('scaleUp with GHES', () => {
127127
repoName: undefined,
128128
});
129129
});
130+
131+
it('creates a runner with labels in s specific group', async () => {
132+
process.env.RUNNER_EXTRA_LABELS = 'label1,label2';
133+
process.env.RUNNER_GROUP_NAME = 'TEST_GROUP';
134+
await scaleUp('aws:sqs', TEST_DATA);
135+
expect(createRunner).toBeCalledWith({
136+
environment: 'unit-test-environment',
137+
runnerConfig: `--url https://github.enterprise.something/${TEST_DATA.repositoryOwner} --token 1234abcd --labels label1,label2 --runnergroup TEST_GROUP`,
138+
orgName: TEST_DATA.repositoryOwner,
139+
repoName: undefined,
140+
});
141+
});
130142
});
131143

132144
describe('on repo level', () => {
@@ -166,6 +178,18 @@ describe('scaleUp with GHES', () => {
166178
repoName: `${TEST_DATA.repositoryOwner}/${TEST_DATA.repositoryName}`,
167179
});
168180
});
181+
182+
it('creates a runner and ensure the group argument is ignored', async () => {
183+
process.env.RUNNER_EXTRA_LABELS = 'label1,label2';
184+
process.env.RUNNER_GROUP_NAME = 'TEST_GROUP_IGNORED';
185+
await scaleUp('aws:sqs', TEST_DATA);
186+
expect(createRunner).toBeCalledWith({
187+
environment: 'unit-test-environment',
188+
runnerConfig: `--url https://github.enterprise.something/${TEST_DATA.repositoryOwner}/${TEST_DATA.repositoryName} --token 1234abcd --labels label1,label2`,
189+
orgName: undefined,
190+
repoName: `${TEST_DATA.repositoryOwner}/${TEST_DATA.repositoryName}`,
191+
});
192+
});
169193
});
170194
});
171195

@@ -228,6 +252,18 @@ describe('scaleUp with public GH', () => {
228252
repoName: undefined,
229253
});
230254
});
255+
256+
it('creates a runner with labels in s specific group', async () => {
257+
process.env.RUNNER_EXTRA_LABELS = 'label1,label2';
258+
process.env.RUNNER_GROUP_NAME = 'TEST_GROUP';
259+
await scaleUp('aws:sqs', TEST_DATA);
260+
expect(createRunner).toBeCalledWith({
261+
environment: 'unit-test-environment',
262+
runnerConfig: `--url https://github.com/${TEST_DATA.repositoryOwner} --token 1234abcd --labels label1,label2 --runnergroup TEST_GROUP`,
263+
orgName: TEST_DATA.repositoryOwner,
264+
repoName: undefined,
265+
});
266+
});
231267
});
232268

233269
describe('on repo level', () => {
@@ -267,5 +303,17 @@ describe('scaleUp with public GH', () => {
267303
repoName: `${TEST_DATA.repositoryOwner}/${TEST_DATA.repositoryName}`,
268304
});
269305
});
306+
307+
it('creates a runner and ensure the group argument is ignored', async () => {
308+
process.env.RUNNER_EXTRA_LABELS = 'label1,label2';
309+
process.env.RUNNER_GROUP_NAME = 'TEST_GROUP_IGNORED';
310+
await scaleUp('aws:sqs', TEST_DATA);
311+
expect(createRunner).toBeCalledWith({
312+
environment: 'unit-test-environment',
313+
runnerConfig: `--url https://github.com/${TEST_DATA.repositoryOwner}/${TEST_DATA.repositoryName} --token 1234abcd --labels label1,label2`,
314+
orgName: undefined,
315+
repoName: `${TEST_DATA.repositoryOwner}/${TEST_DATA.repositoryName}`,
316+
});
317+
});
270318
});
271319
});

modules/runners/lambdas/runners/src/scale-runners/scale-up.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const scaleUp = async (eventSource: string, payload: ActionRequestMessage
1515
const enableOrgLevel = yn(process.env.ENABLE_ORGANIZATION_RUNNERS, { default: true });
1616
const maximumRunners = parseInt(process.env.RUNNERS_MAXIMUM_COUNT || '3');
1717
const runnerExtraLabels = process.env.RUNNER_EXTRA_LABELS;
18+
const runnerGroup = process.env.RUNNER_GROUP_NAME;
1819
const environment = process.env.ENVIRONMENT as string;
1920
const ghesBaseUrl = process.env.GHES_URL as string;
2021

@@ -58,11 +59,12 @@ export const scaleUp = async (eventSource: string, payload: ActionRequestMessage
5859
const token = registrationToken.data.token;
5960

6061
const labelsArgument = runnerExtraLabels !== undefined ? `--labels ${runnerExtraLabels}` : '';
62+
const runnerGroupArgument = runnerGroup !== undefined ? ` --runnergroup ${runnerGroup}` : '';
6163
const configBaseUrl = ghesBaseUrl ? ghesBaseUrl : 'https://github.com';
6264
await createRunner({
6365
environment: environment,
6466
runnerConfig: enableOrgLevel
65-
? `--url ${configBaseUrl}/${payload.repositoryOwner} --token ${token} ${labelsArgument}`
67+
? `--url ${configBaseUrl}/${payload.repositoryOwner} --token ${token} ${labelsArgument}${runnerGroupArgument}`
6668
: `--url ${configBaseUrl}/${payload.repositoryOwner}/${payload.repositoryName} --token ${token} ${labelsArgument}`,
6769
orgName: orgName,
6870
repoName: repoName,

modules/runners/scale-up.tf

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,14 @@ resource "aws_lambda_function" "scale_up" {
3737
GITHUB_APP_KEY_BASE64 = local.github_app_key_base64
3838
KMS_KEY_ID = var.encryption.kms_key_id
3939
RUNNER_EXTRA_LABELS = var.runner_extra_labels
40+
RUNNER_GROUP_NAME = var.runner_group_name
4041
RUNNERS_MAXIMUM_COUNT = var.runners_maximum_count
4142
LAUNCH_TEMPLATE_NAME = aws_launch_template.runner.name
4243
LAUNCH_TEMPLATE_VERSION = aws_launch_template.runner.latest_version
4344
SUBNET_IDS = join(",", var.subnet_ids)
4445
}
4546
}
4647

47-
48-
4948
dynamic "vpc_config" {
5049
for_each = var.lambda_subnet_ids != null && var.lambda_security_group_ids != null ? [true] : []
5150
content {
@@ -111,4 +110,4 @@ resource "aws_iam_role_policy_attachment" "scale_up_vpc_execution_role" {
111110
count = length(var.lambda_subnet_ids) > 0 ? 1 : 0
112111
role = aws_iam_role.scale_up.name
113112
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
114-
}
113+
}

modules/runners/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ variable "runner_extra_labels" {
135135
default = ""
136136
}
137137

138+
variable "runner_group_name" {
139+
description = "Name of the runner group."
140+
type = string
141+
default = "Default"
142+
}
143+
138144
variable "lambda_zip" {
139145
description = "File location of the lambda zip file."
140146
type = string

variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ variable "runner_extra_labels" {
5757
default = ""
5858
}
5959

60+
variable "runner_group_name" {
61+
description = "Name of the runner group."
62+
type = string
63+
default = "Default"
64+
}
65+
6066
variable "webhook_lambda_zip" {
6167
description = "File location of the webhook lambda zip file."
6268
type = string

0 commit comments

Comments
 (0)