Skip to content

Commit 8f7089c

Browse files
Merge branch 'main' into feat-ec2-dynamic-config
2 parents 41d5466 + efbaa6f commit 8f7089c

File tree

8 files changed

+94
-8
lines changed

8 files changed

+94
-8
lines changed

lambdas/functions/control-plane/src/aws/runners.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Placement,
77
FleetBlockDeviceMappingRequest,
88
} from '@aws-sdk/client-ec2';
9+
import { LambdaRunnerSource } from '../scale-runners/scale-up';
910

1011
export type RunnerType = 'Org' | 'Repo';
1112

@@ -64,6 +65,7 @@ export interface RunnerInputParameters {
6465
};
6566
ec2OverrideConfig?: Ec2OverrideConfig;
6667
numberOfRunners: number;
68+
source: LambdaRunnerSource;
6769
amiIdSsmParameterName?: string;
6870
tracingEnabled?: boolean;
6971
onDemandFailoverOnError?: string[];

lambdas/functions/control-plane/src/aws/runners.test.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
2121
import ScaleError from './../scale-runners/ScaleError';
2222
import { createRunner, listEC2Runners, tag, terminateRunner, untag } from './runners';
2323
import type { RunnerInfo, RunnerInputParameters, RunnerType } from './runners.d';
24+
import { LambdaRunnerSource } from '../scale-runners/scale-up';
2425

2526
process.env.AWS_REGION = 'eu-east-1';
2627
const mockEC2Client = mockClient(EC2Client);
@@ -319,13 +320,15 @@ describe('create runner', () => {
319320
capacityType: 'spot',
320321
type: 'Org',
321322
scaleErrors: ['UnfulfillableCapacity', 'MaxSpotInstanceCountExceeded'],
323+
source: 'scale-up-lambda',
322324
};
323325

324326
const defaultExpectedFleetRequestValues: ExpectedFleetRequestValues = {
325327
type: 'Org',
326328
capacityType: 'spot',
327329
allocationStrategy: SpotAllocationStrategy.CAPACITY_OPTIMIZED,
328330
totalTargetCapacity: 1,
331+
source: 'scale-up-lambda',
329332
};
330333

331334
beforeEach(() => {
@@ -366,6 +369,25 @@ describe('create runner', () => {
366369
});
367370
});
368371

372+
it('calls create fleet of multiple instances with pool-lambda source when specified', async () => {
373+
const instances = [{ InstanceIds: ['i-1234', 'i-5678', 'i-9012'] }];
374+
375+
mockEC2Client.on(CreateFleetCommand).resolves({ Instances: instances });
376+
377+
await createRunner({
378+
...createRunnerConfig({ ...defaultRunnerConfig, source: 'pool-lambda' }),
379+
numberOfRunners: 3,
380+
});
381+
382+
expect(mockEC2Client).toHaveReceivedCommandWith(CreateFleetCommand, {
383+
...expectedCreateFleetRequest({
384+
...defaultExpectedFleetRequestValues,
385+
totalTargetCapacity: 3,
386+
source: 'pool-lambda',
387+
}),
388+
});
389+
});
390+
369391
it('calls create fleet of 1 instance with the on-demand capacity', async () => {
370392
await createRunner(createRunnerConfig({ ...defaultRunnerConfig, capacityType: 'on-demand' }));
371393
expect(mockEC2Client).toHaveReceivedCommandWith(CreateFleetCommand, {
@@ -414,6 +436,7 @@ describe('create runner', () => {
414436
Name: 'my-ami-id-param',
415437
});
416438
});
439+
417440
it('calls create fleet of 1 instance with runner tracing enabled', async () => {
418441
tracer.getRootXrayTraceId = vi.fn().mockReturnValue('123');
419442

@@ -427,6 +450,28 @@ describe('create runner', () => {
427450
});
428451
});
429452

453+
it('calls create fleet with source set to scale-up-lambda when source is specified', async () => {
454+
await createRunner(createRunnerConfig({ ...defaultRunnerConfig, source: 'scale-up-lambda' }));
455+
456+
expect(mockEC2Client).toHaveReceivedCommandWith(CreateFleetCommand, {
457+
...expectedCreateFleetRequest({
458+
...defaultExpectedFleetRequestValues,
459+
source: 'scale-up-lambda',
460+
}),
461+
});
462+
});
463+
464+
it('calls create fleet with source set to pool-lambda when source is specified', async () => {
465+
await createRunner(createRunnerConfig({ ...defaultRunnerConfig, source: 'pool-lambda' }));
466+
467+
expect(mockEC2Client).toHaveReceivedCommandWith(CreateFleetCommand, {
468+
...expectedCreateFleetRequest({
469+
...defaultExpectedFleetRequestValues,
470+
source: 'pool-lambda',
471+
}),
472+
});
473+
});
474+
430475
it('overrides SubnetId when specified in ec2OverrideConfig', async () => {
431476
await createRunner({
432477
...createRunnerConfig(defaultRunnerConfig),
@@ -643,12 +688,14 @@ describe('create runner with errors', () => {
643688
capacityType: 'spot',
644689
type: 'Repo',
645690
scaleErrors: ['UnfulfillableCapacity', 'MaxSpotInstanceCountExceeded'],
691+
source: 'scale-up-lambda',
646692
};
647693
const defaultExpectedFleetRequestValues: ExpectedFleetRequestValues = {
648694
type: 'Repo',
649695
capacityType: 'spot',
650696
allocationStrategy: SpotAllocationStrategy.CAPACITY_OPTIMIZED,
651697
totalTargetCapacity: 1,
698+
source: 'scale-up-lambda',
652699
};
653700
beforeEach(() => {
654701
vi.clearAllMocks();
@@ -757,12 +804,14 @@ describe('create runner with errors fail over to OnDemand', () => {
757804
type: 'Repo',
758805
onDemandFailoverOnError: ['InsufficientInstanceCapacity'],
759806
scaleErrors: ['UnfulfillableCapacity', 'MaxSpotInstanceCountExceeded'],
807+
source: 'scale-up-lambda',
760808
};
761809
const defaultExpectedFleetRequestValues: ExpectedFleetRequestValues = {
762810
type: 'Repo',
763811
capacityType: 'spot',
764812
allocationStrategy: SpotAllocationStrategy.CAPACITY_OPTIMIZED,
765813
totalTargetCapacity: 1,
814+
source: 'scale-up-lambda',
766815
};
767816
beforeEach(() => {
768817
vi.clearAllMocks();
@@ -915,6 +964,7 @@ interface RunnerConfig {
915964
tracingEnabled?: boolean;
916965
onDemandFailoverOnError?: string[];
917966
scaleErrors: string[];
967+
source: LambdaRunnerSource;
918968
}
919969

920970
function createRunnerConfig(runnerConfig: RunnerConfig): RunnerInputParameters {
@@ -935,6 +985,7 @@ function createRunnerConfig(runnerConfig: RunnerConfig): RunnerInputParameters {
935985
tracingEnabled: runnerConfig.tracingEnabled,
936986
onDemandFailoverOnError: runnerConfig.onDemandFailoverOnError,
937987
scaleErrors: runnerConfig.scaleErrors,
988+
source: runnerConfig.source,
938989
};
939990
}
940991

@@ -946,14 +997,15 @@ interface ExpectedFleetRequestValues {
946997
totalTargetCapacity: number;
947998
imageId?: string;
948999
tracingEnabled?: boolean;
1000+
source: LambdaRunnerSource;
9491001
}
9501002

9511003
function expectedCreateFleetRequest(expectedValues: ExpectedFleetRequestValues): CreateFleetCommandInput {
9521004
const tags = [
9531005
{ Key: 'ghr:Application', Value: 'github-action-runner' },
9541006
{
9551007
Key: 'ghr:created_by',
956-
Value: expectedValues.totalTargetCapacity > 1 ? 'pool-lambda' : 'scale-up-lambda',
1008+
Value: expectedValues.source,
9571009
},
9581010
{ Key: 'ghr:Type', Value: expectedValues.type },
9591011
{ Key: 'ghr:Owner', Value: REPO_NAME },

lambdas/functions/control-plane/src/aws/runners.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ async function createInstances(
249249
) {
250250
const tags = [
251251
{ Key: 'ghr:Application', Value: 'github-action-runner' },
252-
{ Key: 'ghr:created_by', Value: runnerParameters.numberOfRunners === 1 ? 'scale-up-lambda' : 'pool-lambda' },
252+
{ Key: 'ghr:created_by', Value: runnerParameters.source },
253253
{ Key: 'ghr:Type', Value: runnerParameters.runnerType },
254254
{ Key: 'ghr:Owner', Value: runnerParameters.runnerOwner },
255255
];

lambdas/functions/control-plane/src/pool/pool.test.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,13 @@ describe('Test simple pool.', () => {
192192
it('Top up pool with pool size 2 registered.', async () => {
193193
await adjust({ poolSize: 3 });
194194
expect(createRunners).toHaveBeenCalledTimes(1);
195-
expect(createRunners).toHaveBeenCalledWith(expect.anything(), expect.anything(), 1, expect.anything());
195+
expect(createRunners).toHaveBeenCalledWith(
196+
expect.anything(),
197+
expect.anything(),
198+
1,
199+
expect.anything(),
200+
'pool-lambda',
201+
);
196202
});
197203

198204
it('Should not top up if pool size is reached.', async () => {
@@ -268,7 +274,13 @@ describe('Test simple pool.', () => {
268274
it('Top up if the pool size is set to 5', async () => {
269275
await adjust({ poolSize: 5 });
270276
// 2 idle, top up with 3 to match a pool of 5
271-
expect(createRunners).toHaveBeenCalledWith(expect.anything(), expect.anything(), 3, expect.anything());
277+
expect(createRunners).toHaveBeenCalledWith(
278+
expect.anything(),
279+
expect.anything(),
280+
3,
281+
expect.anything(),
282+
'pool-lambda',
283+
);
272284
});
273285
});
274286

@@ -283,7 +295,13 @@ describe('Test simple pool.', () => {
283295
it('Top up if the pool size is set to 5', async () => {
284296
await adjust({ poolSize: 5 });
285297
// 2 idle, top up with 3 to match a pool of 5
286-
expect(createRunners).toHaveBeenCalledWith(expect.anything(), expect.anything(), 3, expect.anything());
298+
expect(createRunners).toHaveBeenCalledWith(
299+
expect.anything(),
300+
expect.anything(),
301+
3,
302+
expect.anything(),
303+
'pool-lambda',
304+
);
287305
});
288306
});
289307

@@ -333,7 +351,13 @@ describe('Test simple pool.', () => {
333351

334352
await adjust({ poolSize: 5 });
335353
// 2 idle, 2 prefixed idle top up with 1 to match a pool of 5
336-
expect(createRunners).toHaveBeenCalledWith(expect.anything(), expect.anything(), 1, expect.anything());
354+
expect(createRunners).toHaveBeenCalledWith(
355+
expect.anything(),
356+
expect.anything(),
357+
1,
358+
expect.anything(),
359+
'pool-lambda',
360+
);
337361
});
338362
});
339363
});

lambdas/functions/control-plane/src/pool/pool.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export async function adjust(event: PoolEvent): Promise<void> {
106106
},
107107
topUp,
108108
githubInstallationClient,
109+
'pool-lambda',
109110
);
110111
} else {
111112
logger.info(`Pool will not be topped up. Found ${numberOfRunnersInPool} managed idle runners.`);

lambdas/functions/control-plane/src/scale-runners/scale-up.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ const EXPECTED_RUNNER_PARAMS: RunnerInputParameters = {
113113
tracingEnabled: false,
114114
onDemandFailoverOnError: [],
115115
scaleErrors: ['UnfulfillableCapacity', 'MaxSpotInstanceCountExceeded', 'TargetCapacityLimitExceededException'],
116+
source: 'scale-up-lambda',
116117
};
117118
let expectedRunnerParams: RunnerInputParameters;
118119

lambdas/functions/control-plane/src/scale-runners/scale-up.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import {
4141

4242
const logger = createChildLogger('scale-up');
4343

44+
export type LambdaRunnerSource = 'scale-up-lambda' | 'pool-lambda';
45+
4446
export interface RunnerGroup {
4547
name: string;
4648
id: number;
@@ -280,11 +282,13 @@ export async function createRunners(
280282
ec2RunnerConfig: CreateEC2RunnerConfig,
281283
numberOfRunners: number,
282284
ghClient: Octokit,
285+
source: LambdaRunnerSource = 'scale-up-lambda',
283286
): Promise<string[]> {
284287
const instances = await createRunner({
285288
runnerType: githubRunnerConfig.runnerType,
286289
runnerOwner: githubRunnerConfig.runnerOwner,
287290
numberOfRunners,
291+
source,
288292
...ec2RunnerConfig,
289293
});
290294
if (instances.length !== 0) {
@@ -582,6 +586,7 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
582586
},
583587
newRunners,
584588
githubInstallationClient,
589+
'scale-up-lambda',
585590
);
586591

587592
// Not all runners we wanted were created, let's reject enough items so that

modules/runners/logging.tf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,20 @@ locals {
3333
}
3434
]
3535
)
36+
# CloudWatch agent collect_list schema expects log_group_class, not log_class
3637
logfiles = var.enable_cloudwatch_agent ? [for l in local.runner_log_files : {
3738
"log_group_name" : l.prefix_log_group ? "/github-self-hosted-runners/${var.prefix}/${l.log_group_name}" : "/${l.log_group_name}"
3839
"log_stream_name" : l.log_stream_name
3940
"file_path" : l.file_path
40-
"log_class" : l.log_class
41+
"log_group_class" : l.log_class
4142
}] : []
4243

4344
loggroups_names = distinct([for l in local.logfiles : l.log_group_name])
4445
# Create a list of unique log classes corresponding to each log group name
4546
# This maintains the same order as loggroups_names for use with count
4647
loggroups_classes = [
4748
for name in local.loggroups_names : [
48-
for l in local.logfiles : l.log_class
49+
for l in local.logfiles : l.log_group_class
4950
if l.log_group_name == name
5051
][0]
5152
]

0 commit comments

Comments
 (0)