Skip to content
This repository was archived by the owner on Jan 16, 2025. It is now read-only.

Commit c996f73

Browse files
mcaulifnnpalm
authored andcommitted
feat: support multiple instance types (#898)
* fix(scale): Refactor Runner Type and Owner * `environment` should not be optional * feat(runners): Support Multiple Instance Types * Correcting failed launch logic * Updating tests * Test for all launch templates failing * Marking `instance_type` as deprecated
1 parent 83dd263 commit c996f73

File tree

10 files changed

+242
-159
lines changed

10 files changed

+242
-159
lines changed

main.tf

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ module "runners" {
6868
s3_location_runner_binaries = local.s3_action_runner_url
6969

7070
instance_type = var.instance_type
71+
instance_types = var.instance_types
7172
market_options = var.market_options
7273
block_device_mappings = var.block_device_mappings
7374

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

+11-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ jest.mock('aws-sdk', () => ({
77
SSM: jest.fn().mockImplementation(() => mockSSM),
88
}));
99

10+
const LAUNCH_TEMPLATE = 'lt-1';
1011
const ORG_NAME = 'SomeAwesomeCoder';
1112
const REPO_NAME = `${ORG_NAME}/some-amazing-library`;
1213
const ENVIRONMENT = 'unit-test-environment';
@@ -115,22 +116,20 @@ describe('create runner', () => {
115116
],
116117
});
117118
mockSSM.putParameter.mockImplementation(() => mockPutParameter);
118-
process.env.LAUNCH_TEMPLATE_NAME = 'launch-template-name';
119-
process.env.LAUNCH_TEMPLATE_VERSION = '1';
120119
process.env.SUBNET_IDS = 'sub-1234';
121120
});
122121

123122
it('calls run instances with the correct config for repo', async () => {
124123
await createRunner({
125-
runnerConfig: 'bla',
124+
runnerServiceConfig: 'bla',
126125
environment: ENVIRONMENT,
127126
runnerType: 'Repo',
128127
runnerOwner: REPO_NAME
129-
});
128+
}, LAUNCH_TEMPLATE);
130129
expect(mockEC2.runInstances).toBeCalledWith({
131130
MaxCount: 1,
132131
MinCount: 1,
133-
LaunchTemplate: { LaunchTemplateName: 'launch-template-name', Version: '1' },
132+
LaunchTemplate: { LaunchTemplateName: LAUNCH_TEMPLATE, Version: '$Default' },
134133
SubnetId: 'sub-1234',
135134
TagSpecifications: [
136135
{
@@ -146,15 +145,15 @@ describe('create runner', () => {
146145

147146
it('calls run instances with the correct config for org', async () => {
148147
await createRunner({
149-
runnerConfig: 'bla',
148+
runnerServiceConfig: 'bla',
150149
environment: ENVIRONMENT,
151150
runnerType: 'Org',
152151
runnerOwner: ORG_NAME,
153-
});
152+
}, LAUNCH_TEMPLATE);
154153
expect(mockEC2.runInstances).toBeCalledWith({
155154
MaxCount: 1,
156155
MinCount: 1,
157-
LaunchTemplate: { LaunchTemplateName: 'launch-template-name', Version: '1' },
156+
LaunchTemplate: { LaunchTemplateName: LAUNCH_TEMPLATE, Version: '$Default' },
158157
SubnetId: 'sub-1234',
159158
TagSpecifications: [
160159
{
@@ -170,11 +169,11 @@ describe('create runner', () => {
170169

171170
it('creates ssm parameters for each created instance', async () => {
172171
await createRunner({
173-
runnerConfig: 'bla',
172+
runnerServiceConfig: 'bla',
174173
environment: ENVIRONMENT,
175174
runnerType: 'Org',
176175
runnerOwner: ORG_NAME,
177-
});
176+
}, LAUNCH_TEMPLATE);
178177
expect(mockSSM.putParameter).toBeCalledWith({
179178
Name: `${ENVIRONMENT}-i-1234`,
180179
Value: 'bla',
@@ -187,11 +186,11 @@ describe('create runner', () => {
187186
Instances: [],
188187
});
189188
await createRunner({
190-
runnerConfig: 'bla',
189+
runnerServiceConfig: 'bla',
191190
environment: ENVIRONMENT,
192191
runnerType: 'Org',
193192
runnerOwner: ORG_NAME,
194-
});
193+
}, LAUNCH_TEMPLATE);
195194
expect(mockSSM.putParameter).not.toBeCalled();
196195
});
197196
});

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

+42-36
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ export interface ListRunnerFilters {
1313
environment: string | undefined;
1414
}
1515

16+
export interface RunnerInputParameters {
17+
runnerServiceConfig: string;
18+
environment: string;
19+
runnerType: 'Org' | 'Repo';
20+
runnerOwner: string;
21+
}
22+
1623
export async function listRunners(filters: ListRunnerFilters | undefined = undefined): Promise<RunnerInfo[]> {
1724
const ec2 = new EC2();
1825
const ec2Filters = [
@@ -46,13 +53,6 @@ export async function listRunners(filters: ListRunnerFilters | undefined = undef
4653
return runners;
4754
}
4855

49-
export interface RunnerInputParameters {
50-
runnerConfig: string;
51-
environment: string;
52-
runnerType: 'Org' | 'Repo';
53-
runnerOwner: string;
54-
}
55-
5656
export async function terminateRunner(runner: RunnerInfo): Promise<void> {
5757
const ec2 = new EC2();
5858
await ec2
@@ -63,47 +63,53 @@ export async function terminateRunner(runner: RunnerInfo): Promise<void> {
6363
console.debug('Runner terminated.' + runner.instanceId);
6464
}
6565

66-
export async function createRunner(runnerParameters: RunnerInputParameters): Promise<void> {
67-
const launchTemplateName = process.env.LAUNCH_TEMPLATE_NAME as string;
68-
const launchTemplateVersion = process.env.LAUNCH_TEMPLATE_VERSION as string;
69-
70-
const subnets = (process.env.SUBNET_IDS as string).split(',');
71-
const randomSubnet = subnets[Math.floor(Math.random() * subnets.length)];
66+
export async function createRunner(runnerParameters: RunnerInputParameters, launchTemplateName: string): Promise<void> {
7267
console.debug('Runner configuration: ' + JSON.stringify(runnerParameters));
7368
const ec2 = new EC2();
7469
const runInstancesResponse = await ec2
75-
.runInstances({
76-
MaxCount: 1,
77-
MinCount: 1,
78-
LaunchTemplate: {
79-
LaunchTemplateName: launchTemplateName,
80-
Version: launchTemplateVersion,
81-
},
82-
SubnetId: randomSubnet,
83-
TagSpecifications: [
84-
{
85-
ResourceType: 'instance',
86-
Tags: [
87-
{ Key: 'Application', Value: 'github-action-runner' },
88-
{
89-
Key: runnerParameters.runnerType,
90-
Value: runnerParameters.runnerOwner
91-
},
92-
],
93-
},
94-
],
95-
})
70+
.runInstances(getInstanceParams(launchTemplateName, runnerParameters))
9671
.promise();
9772
console.info('Created instance(s): ', runInstancesResponse.Instances?.map((i) => i.InstanceId).join(','));
98-
9973
const ssm = new SSM();
10074
runInstancesResponse.Instances?.forEach(async (i: EC2.Instance) => {
10175
await ssm
10276
.putParameter({
10377
Name: runnerParameters.environment + '-' + (i.InstanceId as string),
104-
Value: runnerParameters.runnerConfig,
78+
Value: runnerParameters.runnerServiceConfig,
10579
Type: 'SecureString',
10680
})
10781
.promise();
10882
});
10983
}
84+
85+
function getInstanceParams(
86+
launchTemplateName: string,
87+
runnerParameters: RunnerInputParameters
88+
): EC2.RunInstancesRequest {
89+
return {
90+
MaxCount: 1,
91+
MinCount: 1,
92+
LaunchTemplate: {
93+
LaunchTemplateName: launchTemplateName,
94+
Version: '$Default',
95+
},
96+
SubnetId: getSubnet(),
97+
TagSpecifications: [
98+
{
99+
ResourceType: 'instance',
100+
Tags: [
101+
{ Key: 'Application', Value: 'github-action-runner' },
102+
{
103+
Key: runnerParameters.runnerType,
104+
Value: runnerParameters.runnerOwner
105+
},
106+
],
107+
},
108+
],
109+
};
110+
}
111+
112+
function getSubnet(): string {
113+
const subnets = (process.env.SUBNET_IDS as string).split(',');
114+
return subnets[Math.floor(Math.random() * subnets.length)];
115+
}

0 commit comments

Comments
 (0)