Skip to content

Commit ba0997f

Browse files
Merge branch 'main' into feat-macos-support
2 parents ad532dc + efbaa6f commit ba0997f

8 files changed

Lines changed: 95 additions & 8 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { DefaultTargetCapacityType, SpotAllocationStrategy } from '@aws-sdk/client-ec2';
2+
import { LambdaRunnerSource } from '../scale-runners/scale-up';
23

34
export type RunnerType = 'Org' | 'Repo';
45

@@ -42,6 +43,7 @@ export interface RunnerInputParameters {
4243
instanceAllocationStrategy: SpotAllocationStrategy;
4344
};
4445
numberOfRunners: number;
46+
source: LambdaRunnerSource;
4547
amiIdSsmParameterName?: string;
4648
tracingEnabled?: boolean;
4749
onDemandFailoverOnError?: string[];

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

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

2627
process.env.AWS_REGION = 'eu-east-1';
2728
const mockEC2Client = mockClient(EC2Client);
@@ -319,13 +320,16 @@ describe('create runner', () => {
319320
allocationStrategy: SpotAllocationStrategy.CAPACITY_OPTIMIZED,
320321
capacityType: 'spot',
321322
type: 'Org',
323+
scaleErrors: [],
324+
source: 'scale-up-lambda',
322325
};
323326

324327
const defaultExpectedFleetRequestValues: ExpectedFleetRequestValues = {
325328
type: 'Org',
326329
capacityType: 'spot',
327330
allocationStrategy: SpotAllocationStrategy.CAPACITY_OPTIMIZED,
328331
totalTargetCapacity: 1,
332+
source: 'scale-up-lambda',
329333
};
330334

331335
beforeEach(() => {
@@ -366,6 +370,25 @@ describe('create runner', () => {
366370
});
367371
});
368372

373+
it('calls create fleet of multiple instances with pool-lambda source when specified', async () => {
374+
const instances = [{ InstanceIds: ['i-1234', 'i-5678', 'i-9012'] }];
375+
376+
mockEC2Client.on(CreateFleetCommand).resolves({ Instances: instances });
377+
378+
await createRunner({
379+
...createRunnerConfig({ ...defaultRunnerConfig, source: 'pool-lambda' }),
380+
numberOfRunners: 3,
381+
});
382+
383+
expect(mockEC2Client).toHaveReceivedCommandWith(CreateFleetCommand, {
384+
...expectedCreateFleetRequest({
385+
...defaultExpectedFleetRequestValues,
386+
totalTargetCapacity: 3,
387+
source: 'pool-lambda',
388+
}),
389+
});
390+
});
391+
369392
it('calls create fleet of 1 instance with the on-demand capacity', async () => {
370393
await createRunner(createRunnerConfig({ ...defaultRunnerConfig, capacityType: 'on-demand' }));
371394
expect(mockEC2Client).toHaveReceivedCommandWith(CreateFleetCommand, {
@@ -426,6 +449,28 @@ describe('create runner', () => {
426449
}),
427450
});
428451
});
452+
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+
});
429474
});
430475

431476
describe('create runner with errors', () => {
@@ -434,12 +479,14 @@ describe('create runner with errors', () => {
434479
capacityType: 'spot',
435480
type: 'Repo',
436481
scaleErrors: ['UnfulfillableCapacity', 'MaxSpotInstanceCountExceeded'],
482+
source: 'scale-up-lambda',
437483
};
438484
const defaultExpectedFleetRequestValues: ExpectedFleetRequestValues = {
439485
type: 'Repo',
440486
capacityType: 'spot',
441487
allocationStrategy: SpotAllocationStrategy.CAPACITY_OPTIMIZED,
442488
totalTargetCapacity: 1,
489+
source: 'scale-up-lambda',
443490
};
444491
beforeEach(() => {
445492
vi.clearAllMocks();
@@ -547,12 +594,15 @@ describe('create runner with errors fail over to OnDemand', () => {
547594
capacityType: 'spot',
548595
type: 'Repo',
549596
onDemandFailoverOnError: ['InsufficientInstanceCapacity'],
597+
scaleErrors: [],
598+
source: 'scale-up-lambda',
550599
};
551600
const defaultExpectedFleetRequestValues: ExpectedFleetRequestValues = {
552601
type: 'Repo',
553602
capacityType: 'spot',
554603
allocationStrategy: SpotAllocationStrategy.CAPACITY_OPTIMIZED,
555604
totalTargetCapacity: 1,
605+
source: 'scale-up-lambda',
556606
};
557607
beforeEach(() => {
558608
vi.clearAllMocks();
@@ -706,6 +756,7 @@ interface RunnerConfig {
706756
onDemandFailoverOnError?: string[];
707757
scaleErrors: string[];
708758
useDedicatedHost?: boolean;
759+
source: LambdaRunnerSource;
709760
}
710761

711762
function createRunnerConfig(runnerConfig: RunnerConfig): RunnerInputParameters {
@@ -727,6 +778,7 @@ function createRunnerConfig(runnerConfig: RunnerConfig): RunnerInputParameters {
727778
onDemandFailoverOnError: runnerConfig.onDemandFailoverOnError,
728779
scaleErrors: runnerConfig.scaleErrors,
729780
useDedicatedHost: runnerConfig.useDedicatedHost,
781+
source: runnerConfig.source,
730782
};
731783
}
732784

@@ -738,14 +790,15 @@ interface ExpectedFleetRequestValues {
738790
totalTargetCapacity: number;
739791
imageId?: string;
740792
tracingEnabled?: boolean;
793+
source: LambdaRunnerSource;
741794
}
742795

743796
function expectedCreateFleetRequest(expectedValues: ExpectedFleetRequestValues): CreateFleetCommandInput {
744797
const tags = [
745798
{ Key: 'ghr:Application', Value: 'github-action-runner' },
746799
{
747800
Key: 'ghr:created_by',
748-
Value: expectedValues.totalTargetCapacity > 1 ? 'pool-lambda' : 'scale-up-lambda',
801+
Value: expectedValues.source,
749802
},
750803
{ Key: 'ghr:Type', Value: expectedValues.type },
751804
{ 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
@@ -251,7 +251,7 @@ async function createInstances(
251251
) {
252252
const tags = [
253253
{ Key: 'ghr:Application', Value: 'github-action-runner' },
254-
{ Key: 'ghr:created_by', Value: runnerParameters.numberOfRunners === 1 ? 'scale-up-lambda' : 'pool-lambda' },
254+
{ Key: 'ghr:created_by', Value: runnerParameters.source },
255255
{ Key: 'ghr:Type', Value: runnerParameters.runnerType },
256256
{ Key: 'ghr:Owner', Value: runnerParameters.runnerOwner },
257257
];

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
@@ -114,6 +114,7 @@ const EXPECTED_RUNNER_PARAMS: RunnerInputParameters = {
114114
onDemandFailoverOnError: [],
115115
scaleErrors: ['UnfulfillableCapacity', 'MaxSpotInstanceCountExceeded', 'TargetCapacityLimitExceededException'],
116116
useDedicatedHost: false,
117+
source: 'scale-up-lambda',
117118
};
118119
let expectedRunnerParams: RunnerInputParameters;
119120

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { publishRetryMessage } from './job-retry';
1111

1212
const logger = createChildLogger('scale-up');
1313

14+
export type LambdaRunnerSource = 'scale-up-lambda' | 'pool-lambda';
15+
1416
export interface RunnerGroup {
1517
name: string;
1618
id: number;
@@ -249,11 +251,13 @@ export async function createRunners(
249251
ec2RunnerConfig: CreateEC2RunnerConfig,
250252
numberOfRunners: number,
251253
ghClient: Octokit,
254+
source: LambdaRunnerSource = 'scale-up-lambda',
252255
): Promise<string[]> {
253256
const instances = await createRunner({
254257
runnerType: githubRunnerConfig.runnerType,
255258
runnerOwner: githubRunnerConfig.runnerOwner,
256259
numberOfRunners,
260+
source,
257261
...ec2RunnerConfig,
258262
});
259263
if (instances.length !== 0) {
@@ -510,6 +514,7 @@ export async function scaleUp(payloads: ActionRequestMessageSQS[]): Promise<stri
510514
},
511515
newRunners,
512516
githubInstallationClient,
517+
'scale-up-lambda',
513518
);
514519

515520
// 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)