From 8650bc17acb276e74f44725f6c61757d8eca8019 Mon Sep 17 00:00:00 2001 From: Quoc Truong Date: Fri, 26 Sep 2025 11:00:57 -0700 Subject: [PATCH 1/2] Add the ability to add services for GitHub runner --- packages/k8s/src/hooks/prepare-job.ts | 28 ++++++++++++---------- packages/k8s/src/k8s/utils.ts | 23 +++++++++++++++++- packages/k8s/tests/k8s-utils-test.ts | 34 ++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/packages/k8s/src/hooks/prepare-job.ts b/packages/k8s/src/hooks/prepare-job.ts index c9cb870c..841a4cd6 100644 --- a/packages/k8s/src/hooks/prepare-job.ts +++ b/packages/k8s/src/hooks/prepare-job.ts @@ -34,7 +34,8 @@ import { SCRIPT_EXECUTOR_ENTRY_POINT, SCRIPT_EXECUTOR_ENTRY_POINT_ARGS, getNumberOfHost, - sleep + sleep, + generateServicesName } from '../k8s/utils' import { CONTAINER_EXTENSION_PREFIX, @@ -68,6 +69,7 @@ export async function prepareJob( let services: k8s.V1Container[] = [] if (args.services?.length) { + generateServicesName(args.services) services = args.services.map(service => { core.debug(`Adding service '${service.image}' to pod definition`) return createContainerSpec( @@ -288,19 +290,19 @@ export function createContainerSpec( if (!container.entryPoint && jobContainer) { container.entryPoint = DEFAULT_CONTAINER_ENTRY_POINT container.entryPointArgs = DEFAULT_CONTAINER_ENTRY_POINT_ARGS - } - if (useScriptExecutor()) { - core.debug('starting script executor server') - // Starting the server. - container.entryPoint = - process.env['ACTIONS_RUNNER_SCRIPT_EXECUTOR_ENTRY_POINT'] || - SCRIPT_EXECUTOR_ENTRY_POINT - container.entryPointArgs = process.env[ - 'ACTIONS_RUNNER_SCRIPT_EXECUTOR_ARGS' - ] - ? process.env['ACTIONS_RUNNER_SCRIPT_EXECUTOR_ARGS'].split(' ') - : SCRIPT_EXECUTOR_ENTRY_POINT_ARGS + if (useScriptExecutor()) { + core.debug('starting script executor server') + // Starting the server. + container.entryPoint = + process.env['ACTIONS_RUNNER_SCRIPT_EXECUTOR_ENTRY_POINT'] || + SCRIPT_EXECUTOR_ENTRY_POINT + container.entryPointArgs = process.env[ + 'ACTIONS_RUNNER_SCRIPT_EXECUTOR_ARGS' + ] + ? process.env['ACTIONS_RUNNER_SCRIPT_EXECUTOR_ARGS'].split(' ') + : SCRIPT_EXECUTOR_ENTRY_POINT_ARGS + } } const podContainer = { diff --git a/packages/k8s/src/k8s/utils.ts b/packages/k8s/src/k8s/utils.ts index d8e67fb0..daaaad9f 100644 --- a/packages/k8s/src/k8s/utils.ts +++ b/packages/k8s/src/k8s/utils.ts @@ -197,7 +197,7 @@ export function writeEntryPointScript( } export function generateContainerName(image: string): string { - const nameWithTag = image.split('/').pop() + const nameWithTag = image.replace('_', '-').split('/').pop() const name = nameWithTag?.split(':').at(0) if (!name) { @@ -263,6 +263,27 @@ export function mergePodSpecWithOptions( } } +// If there are multiple service containers with the same image name, append a number +// to uniquely identify them. Otherwise we won't be able to create it. +export function generateServicesName( + services: { [key: string]: string }[] +): void { + const servicesSeen: { [key: string]: number } = {} + for (const service of services) { + if (servicesSeen[service.image] === undefined) { + servicesSeen[service.image] = 0 + service.name = generateContainerName(service.image) + continue + } + servicesSeen[service.image] += 1 + service.name = `${generateContainerName(service.image)}-${ + servicesSeen[service.image] + }` + } + + core.debug(`services are ${JSON.stringify(services)}`) +} + export function mergeObjectMeta( base: { metadata?: k8s.V1ObjectMeta }, from: k8s.V1ObjectMeta diff --git a/packages/k8s/tests/k8s-utils-test.ts b/packages/k8s/tests/k8s-utils-test.ts index c533570e..0d4e30ff 100644 --- a/packages/k8s/tests/k8s-utils-test.ts +++ b/packages/k8s/tests/k8s-utils-test.ts @@ -11,7 +11,8 @@ import { ENV_HOOK_TEMPLATE_PATH, createScriptExecutorContainer, getNumberOfHost, - ENV_NUMBER_OF_HOSTS + ENV_NUMBER_OF_HOSTS, + generateServicesName } from '../src/k8s/utils' import * as k8s from '@kubernetes/client-node' import { TestHelper } from './test-setup' @@ -344,6 +345,12 @@ describe('k8s utils', () => { ) }) + it('should replace - with _', () => { + expect( + generateContainerName('public.ecr.aws/localstack/local_stack') + ).toEqual('local-stack') + }) + it('should throw on invalid image string', () => { expect(() => generateContainerName('localstack/localstack/:latest') @@ -352,6 +359,31 @@ describe('k8s utils', () => { }) }) + describe('generateServicesName', () => { + it('should generate services name for multiple identical image', () => { + const services = [ + { + image: 'foo' + }, + { + image: 'foo' + } + ] + generateServicesName(services) + expect.arrayContaining([ + expect.objectContaining({ + name: 'commonName', + value: CertCommonName.ROOT + }) + ]) + + expect(services).toEqual([ + { image: 'foo', name: 'foo' }, + { image: 'foo', name: 'foo-1' } + ]) + }) + }) + describe('create script executor container', () => { it('should install script executor at the volume mount location', () => { const executorVolumeMount = new k8s.V1VolumeMount() From 47963a131b13d38019bcc511505ab800b5c48fa3 Mon Sep 17 00:00:00 2001 From: Quoc Truong Date: Fri, 26 Sep 2025 13:41:09 -0700 Subject: [PATCH 2/2] Fix description --- packages/k8s/tests/k8s-utils-test.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/k8s/tests/k8s-utils-test.ts b/packages/k8s/tests/k8s-utils-test.ts index 0d4e30ff..7ed57949 100644 --- a/packages/k8s/tests/k8s-utils-test.ts +++ b/packages/k8s/tests/k8s-utils-test.ts @@ -370,12 +370,6 @@ describe('k8s utils', () => { } ] generateServicesName(services) - expect.arrayContaining([ - expect.objectContaining({ - name: 'commonName', - value: CertCommonName.ROOT - }) - ]) expect(services).toEqual([ { image: 'foo', name: 'foo' },