mirror of
https://github.com/actions/runner-container-hooks.git
synced 2025-12-17 02:06:43 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c92bb5544e | ||
|
|
26f4a32c30 | ||
|
|
10c6c0aa70 | ||
|
|
d735152125 | ||
|
|
ae31f04223 | ||
|
|
7754cb80eb | ||
|
|
ae432db512 | ||
|
|
4448b61e00 | ||
|
|
bf39b9bf16 | ||
|
|
5b597b0fe2 | ||
|
|
0e1ba7bdc8 | ||
|
|
73914b840c | ||
|
|
b537fd4c92 |
@@ -73,6 +73,8 @@
|
|||||||
"contextName": "redis",
|
"contextName": "redis",
|
||||||
"image": "redis",
|
"image": "redis",
|
||||||
"createOptions": "--cpus 1",
|
"createOptions": "--cpus 1",
|
||||||
|
"entrypoint": null,
|
||||||
|
"entryPointArgs": [],
|
||||||
"environmentVariables": {},
|
"environmentVariables": {},
|
||||||
"userMountVolumes": [
|
"userMountVolumes": [
|
||||||
{
|
{
|
||||||
|
|||||||
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "hooks",
|
"name": "hooks",
|
||||||
"version": "0.1.3",
|
"version": "0.3.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "hooks",
|
"name": "hooks",
|
||||||
"version": "0.1.3",
|
"version": "0.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^27.5.1",
|
"@types/jest": "^27.5.1",
|
||||||
@@ -1800,9 +1800,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
@@ -3926,9 +3926,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hooks",
|
"name": "hooks",
|
||||||
"version": "0.2.0",
|
"version": "0.3.0",
|
||||||
"description": "Three projects are included - k8s: a kubernetes hook implementation that spins up pods dynamically to run a job - docker: A hook implementation of the runner's docker implementation - A hook lib, which contains shared typescript definitions and utilities that the other packages consume",
|
"description": "Three projects are included - k8s: a kubernetes hook implementation that spins up pods dynamically to run a job - docker: A hook implementation of the runner's docker implementation - A hook lib, which contains shared typescript definitions and utilities that the other packages consume",
|
||||||
"main": "",
|
"main": "",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
|||||||
24
packages/docker/package-lock.json
generated
24
packages/docker/package-lock.json
generated
@@ -3779,9 +3779,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"json5": "lib/cli.js"
|
"json5": "lib/cli.js"
|
||||||
@@ -4903,9 +4903,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tsconfig-paths/node_modules/json5": {
|
"node_modules/tsconfig-paths/node_modules/json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
@@ -8176,9 +8176,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"kleur": {
|
"kleur": {
|
||||||
@@ -8985,9 +8985,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
|
|||||||
@@ -16,15 +16,14 @@ import {
|
|||||||
import { checkEnvironment } from './utils'
|
import { checkEnvironment } from './utils'
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
|
try {
|
||||||
|
checkEnvironment()
|
||||||
const input = await getInputFromStdin()
|
const input = await getInputFromStdin()
|
||||||
|
|
||||||
const args = input['args']
|
const args = input['args']
|
||||||
const command = input['command']
|
const command = input['command']
|
||||||
const responseFile = input['responseFile']
|
const responseFile = input['responseFile']
|
||||||
const state = input['state']
|
const state = input['state']
|
||||||
|
|
||||||
try {
|
|
||||||
checkEnvironment()
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case Command.PrepareJob:
|
case Command.PrepareJob:
|
||||||
await prepareJob(args as PrepareJobArgs, responseFile)
|
await prepareJob(args as PrepareJobArgs, responseFile)
|
||||||
|
|||||||
12
packages/hooklib/package-lock.json
generated
12
packages/hooklib/package-lock.json
generated
@@ -1742,9 +1742,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
@@ -3789,9 +3789,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
|
|||||||
985
packages/k8s/package-lock.json
generated
985
packages/k8s/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
|||||||
"@actions/core": "^1.9.1",
|
"@actions/core": "^1.9.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/io": "^1.1.2",
|
"@actions/io": "^1.1.2",
|
||||||
"@kubernetes/client-node": "^0.16.3",
|
"@kubernetes/client-node": "^0.18.1",
|
||||||
"hooklib": "file:../hooklib"
|
"hooklib": "file:../hooklib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
containerVolumes,
|
containerVolumes,
|
||||||
DEFAULT_CONTAINER_ENTRY_POINT,
|
DEFAULT_CONTAINER_ENTRY_POINT,
|
||||||
DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
|
DEFAULT_CONTAINER_ENTRY_POINT_ARGS,
|
||||||
|
generateContainerName,
|
||||||
PodPhase
|
PodPhase
|
||||||
} from '../k8s/utils'
|
} from '../k8s/utils'
|
||||||
import { JOB_CONTAINER_NAME } from './constants'
|
import { JOB_CONTAINER_NAME } from './constants'
|
||||||
@@ -31,14 +32,14 @@ export async function prepareJob(
|
|||||||
let container: k8s.V1Container | undefined = undefined
|
let container: k8s.V1Container | undefined = undefined
|
||||||
if (args.container?.image) {
|
if (args.container?.image) {
|
||||||
core.debug(`Using image '${args.container.image}' for job image`)
|
core.debug(`Using image '${args.container.image}' for job image`)
|
||||||
container = createPodSpec(args.container, JOB_CONTAINER_NAME, true)
|
container = createContainerSpec(args.container, JOB_CONTAINER_NAME, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
let services: k8s.V1Container[] = []
|
let services: k8s.V1Container[] = []
|
||||||
if (args.services?.length) {
|
if (args.services?.length) {
|
||||||
services = args.services.map(service => {
|
services = args.services.map(service => {
|
||||||
core.debug(`Adding service '${service.image}' to pod definition`)
|
core.debug(`Adding service '${service.image}' to pod definition`)
|
||||||
return createPodSpec(service, service.image.split(':')[0])
|
return createContainerSpec(service, generateContainerName(service.image))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (!container && !services?.length) {
|
if (!container && !services?.length) {
|
||||||
@@ -124,10 +125,9 @@ function generateResponseFile(
|
|||||||
)
|
)
|
||||||
if (serviceContainers?.length) {
|
if (serviceContainers?.length) {
|
||||||
response.context['services'] = serviceContainers.map(c => {
|
response.context['services'] = serviceContainers.map(c => {
|
||||||
if (!c.ports) {
|
if (!c.ports?.length) {
|
||||||
return
|
return { image: c.image }
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctxPorts: ContextPorts = {}
|
const ctxPorts: ContextPorts = {}
|
||||||
for (const port of c.ports) {
|
for (const port of c.ports) {
|
||||||
ctxPorts[port.containerPort] = port.hostPort
|
ctxPorts[port.containerPort] = port.hostPort
|
||||||
@@ -153,7 +153,7 @@ async function copyExternalsToRoot(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPodSpec(
|
export function createContainerSpec(
|
||||||
container,
|
container,
|
||||||
name: string,
|
name: string,
|
||||||
jobContainer = false
|
jobContainer = false
|
||||||
@@ -166,14 +166,20 @@ function createPodSpec(
|
|||||||
const podContainer = {
|
const podContainer = {
|
||||||
name,
|
name,
|
||||||
image: container.image,
|
image: container.image,
|
||||||
command: [container.entryPoint],
|
|
||||||
args: container.entryPointArgs,
|
|
||||||
ports: containerPorts(container)
|
ports: containerPorts(container)
|
||||||
} as k8s.V1Container
|
} as k8s.V1Container
|
||||||
if (container.workingDirectory) {
|
if (container.workingDirectory) {
|
||||||
podContainer.workingDir = container.workingDirectory
|
podContainer.workingDir = container.workingDirectory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (container.entryPoint) {
|
||||||
|
podContainer.command = [container.entryPoint]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container.entryPointArgs?.length > 0) {
|
||||||
|
podContainer.args = container.entryPointArgs
|
||||||
|
}
|
||||||
|
|
||||||
podContainer.env = []
|
podContainer.env = []
|
||||||
for (const [key, value] of Object.entries(
|
for (const [key, value] of Object.entries(
|
||||||
container['environmentVariables']
|
container['environmentVariables']
|
||||||
|
|||||||
@@ -9,15 +9,13 @@ import {
|
|||||||
import { isAuthPermissionsOK, namespace, requiredPermissions } from './k8s'
|
import { isAuthPermissionsOK, namespace, requiredPermissions } from './k8s'
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
|
try {
|
||||||
const input = await getInputFromStdin()
|
const input = await getInputFromStdin()
|
||||||
|
|
||||||
const args = input['args']
|
const args = input['args']
|
||||||
const command = input['command']
|
const command = input['command']
|
||||||
const responseFile = input['responseFile']
|
const responseFile = input['responseFile']
|
||||||
const state = input['state']
|
const state = input['state']
|
||||||
|
|
||||||
let exitCode = 0
|
|
||||||
try {
|
|
||||||
if (!(await isAuthPermissionsOK())) {
|
if (!(await isAuthPermissionsOK())) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The Service account needs the following permissions ${JSON.stringify(
|
`The Service account needs the following permissions ${JSON.stringify(
|
||||||
@@ -25,28 +23,28 @@ async function run(): Promise<void> {
|
|||||||
)} on the pod resource in the '${namespace()}' namespace. Please contact your self hosted runner administrator.`
|
)} on the pod resource in the '${namespace()}' namespace. Please contact your self hosted runner administrator.`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let exitCode = 0
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case Command.PrepareJob:
|
case Command.PrepareJob:
|
||||||
await prepareJob(args as prepareJobArgs, responseFile)
|
await prepareJob(args as prepareJobArgs, responseFile)
|
||||||
break
|
return process.exit(0)
|
||||||
case Command.CleanupJob:
|
case Command.CleanupJob:
|
||||||
await cleanupJob()
|
await cleanupJob()
|
||||||
break
|
return process.exit(0)
|
||||||
case Command.RunScriptStep:
|
case Command.RunScriptStep:
|
||||||
await runScriptStep(args, state, null)
|
await runScriptStep(args, state, null)
|
||||||
break
|
return process.exit(0)
|
||||||
case Command.RunContainerStep:
|
case Command.RunContainerStep:
|
||||||
exitCode = await runContainerStep(args)
|
exitCode = await runContainerStep(args)
|
||||||
break
|
return process.exit(exitCode)
|
||||||
case Command.runContainerStep:
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Command not recognized: ${command}`)
|
throw new Error(`Command not recognized: ${command}`)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.error(error as Error)
|
core.error(error as Error)
|
||||||
exitCode = 1
|
process.exit(1)
|
||||||
}
|
}
|
||||||
process.exitCode = exitCode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
|
|||||||
@@ -517,6 +517,9 @@ export function containerPorts(
|
|||||||
container: ContainerInfo
|
container: ContainerInfo
|
||||||
): k8s.V1ContainerPort[] {
|
): k8s.V1ContainerPort[] {
|
||||||
const ports: k8s.V1ContainerPort[] = []
|
const ports: k8s.V1ContainerPort[] = []
|
||||||
|
if (!container.portMappings?.length) {
|
||||||
|
return ports
|
||||||
|
}
|
||||||
for (const portDefinition of container.portMappings) {
|
for (const portDefinition of container.portMappings) {
|
||||||
const portProtoSplit = portDefinition.split('/')
|
const portProtoSplit = portDefinition.split('/')
|
||||||
if (portProtoSplit.length > 2) {
|
if (portProtoSplit.length > 2) {
|
||||||
|
|||||||
@@ -111,11 +111,13 @@ export function writeEntryPointScript(
|
|||||||
if (environmentVariables && Object.entries(environmentVariables).length) {
|
if (environmentVariables && Object.entries(environmentVariables).length) {
|
||||||
const envBuffer: string[] = []
|
const envBuffer: string[] = []
|
||||||
for (const [key, value] of Object.entries(environmentVariables)) {
|
for (const [key, value] of Object.entries(environmentVariables)) {
|
||||||
|
if (key.includes(`=`) || key.includes(`'`) || key.includes(`"`)) {
|
||||||
|
throw new Error(
|
||||||
|
`environment key ${key} is invalid - the key must not contain =, ' or "`
|
||||||
|
)
|
||||||
|
}
|
||||||
envBuffer.push(
|
envBuffer.push(
|
||||||
`"${key}=${value
|
`"${key}=${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`
|
||||||
.replace(/\\/g, '\\\\')
|
|
||||||
.replace(/"/g, '\\"')
|
|
||||||
.replace(/=/g, '\\=')}"`
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
environmentPrefix = `env ${envBuffer.join(' ')} `
|
environmentPrefix = `env ${envBuffer.join(' ')} `
|
||||||
@@ -137,6 +139,17 @@ exec ${environmentPrefix} ${entryPoint} ${
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateContainerName(image: string): string {
|
||||||
|
const nameWithTag = image.split('/').pop()
|
||||||
|
const name = nameWithTag?.split(':').at(0)
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
throw new Error(`Image definition '${image}' is invalid`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
export enum PodPhase {
|
export enum PodPhase {
|
||||||
PENDING = 'Pending',
|
PENDING = 'Pending',
|
||||||
RUNNING = 'Running',
|
RUNNING = 'Running',
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import { containerPorts, POD_VOLUME_NAME } from '../src/k8s'
|
import { containerPorts, POD_VOLUME_NAME } from '../src/k8s'
|
||||||
import { containerVolumes, writeEntryPointScript } from '../src/k8s/utils'
|
import {
|
||||||
|
containerVolumes,
|
||||||
|
generateContainerName,
|
||||||
|
writeEntryPointScript
|
||||||
|
} from '../src/k8s/utils'
|
||||||
import { TestHelper } from './test-setup'
|
import { TestHelper } from './test-setup'
|
||||||
|
|
||||||
let testHelper: TestHelper
|
let testHelper: TestHelper
|
||||||
@@ -221,4 +225,32 @@ describe('k8s utils', () => {
|
|||||||
expect(() => containerPorts({ portMappings: ['1/tcp/udp'] })).toThrow()
|
expect(() => containerPorts({ portMappings: ['1/tcp/udp'] })).toThrow()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('generate container name', () => {
|
||||||
|
it('should return the container name from image string', () => {
|
||||||
|
expect(
|
||||||
|
generateContainerName('public.ecr.aws/localstack/localstack')
|
||||||
|
).toEqual('localstack')
|
||||||
|
expect(
|
||||||
|
generateContainerName(
|
||||||
|
'public.ecr.aws/url/with/multiple/slashes/postgres:latest'
|
||||||
|
)
|
||||||
|
).toEqual('postgres')
|
||||||
|
expect(generateContainerName('postgres')).toEqual('postgres')
|
||||||
|
expect(generateContainerName('postgres:latest')).toEqual('postgres')
|
||||||
|
expect(generateContainerName('localstack/localstack')).toEqual(
|
||||||
|
'localstack'
|
||||||
|
)
|
||||||
|
expect(generateContainerName('localstack/localstack:latest')).toEqual(
|
||||||
|
'localstack'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw on invalid image string', () => {
|
||||||
|
expect(() =>
|
||||||
|
generateContainerName('localstack/localstack/:latest')
|
||||||
|
).toThrow()
|
||||||
|
expect(() => generateContainerName(':latest')).toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { cleanupJob } from '../src/hooks'
|
import { cleanupJob } from '../src/hooks'
|
||||||
import { prepareJob } from '../src/hooks/prepare-job'
|
import { createContainerSpec, prepareJob } from '../src/hooks/prepare-job'
|
||||||
import { TestHelper } from './test-setup'
|
import { TestHelper } from './test-setup'
|
||||||
|
import { generateContainerName } from '../src/k8s/utils'
|
||||||
|
import { V1Container } from '@kubernetes/client-node'
|
||||||
|
|
||||||
jest.useRealTimers()
|
jest.useRealTimers()
|
||||||
|
|
||||||
@@ -71,4 +73,27 @@ describe('Prepare job', () => {
|
|||||||
prepareJob(prepareJobData.args, prepareJobOutputFilePath)
|
prepareJob(prepareJobData.args, prepareJobOutputFilePath)
|
||||||
).rejects.toThrow()
|
).rejects.toThrow()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not set command + args for service container if not passed in args', async () => {
|
||||||
|
const services = prepareJobData.args.services.map(service => {
|
||||||
|
return createContainerSpec(service, generateContainerName(service.image))
|
||||||
|
}) as [V1Container]
|
||||||
|
|
||||||
|
expect(services[0].command).toBe(undefined)
|
||||||
|
expect(services[0].args).toBe(undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
test.each([undefined, null, []])(
|
||||||
|
'should not throw exception when portMapping=%p',
|
||||||
|
async pm => {
|
||||||
|
prepareJobData.args.services.forEach(s => {
|
||||||
|
s.portMappings = pm
|
||||||
|
})
|
||||||
|
await prepareJob(prepareJobData.args, prepareJobOutputFilePath)
|
||||||
|
const content = JSON.parse(
|
||||||
|
fs.readFileSync(prepareJobOutputFilePath).toString()
|
||||||
|
)
|
||||||
|
expect(() => content.context.services[0].image).not.toThrow()
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
## Features
|
## Features
|
||||||
- Always use the Docker related ENVs from the host machine instead of ENVs from the runner job [#40]
|
- Use service container entrypoint if no entrypoint is specified [#53]
|
||||||
- Use user defined entrypoints for service containers (instead of `tail -f /dev/null`)
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Fixed substring issue with /github/workspace and /github/file_commands [#35]
|
- Fixed issue caused by promise rejection in kubernetes hook [#65]
|
||||||
- Fixed issue related to setting hostPort and containerPort when formatting is not recognized by k8s default [#38]
|
- Fixed service container name issue when service image contains one or more `/`
|
||||||
|
in the name [#53]
|
||||||
|
- Fixed issue related to service container failures when no ports are specified
|
||||||
|
[#60]
|
||||||
|
- Allow equal signs in environment variable values [#62]
|
||||||
|
|
||||||
<!-- ## Misc
|
<!-- ## Misc
|
||||||
|
|||||||
Reference in New Issue
Block a user