Merge branch 'main' of https://github.com/actions/runner-container-hooks into fhammerl+nikola-jokic/kaniko

This commit is contained in:
Ferenc Hammerl
2023-01-04 11:27:54 +01:00
17 changed files with 300 additions and 91 deletions

View File

@@ -13,7 +13,7 @@ You'll need a runner compatible with hooks, a repository with container workflow
- You'll need a runner compatible with hooks, a repository with container workflows to which you can register the runner and the hooks from this repository. - You'll need a runner compatible with hooks, a repository with container workflows to which you can register the runner and the hooks from this repository.
- See [the runner contributing.md](../../github/CONTRIBUTING.MD) for how to get started with runner development. - See [the runner contributing.md](../../github/CONTRIBUTING.MD) for how to get started with runner development.
- Build your hook using `npm run build` - Build your hook using `npm run build`
- Enable the hooks by setting `ACTIONS_RUNNER_CONTAINER_HOOK=./packages/{libraryname}/dist/index.js` file generated by [ncc](https://github.com/vercel/ncc) - Enable the hooks by setting `ACTIONS_RUNNER_CONTAINER_HOOKS=./packages/{libraryname}/dist/index.js` file generated by [ncc](https://github.com/vercel/ncc)
- Configure your self hosted runner against the a repository you have admin access - Configure your self hosted runner against the a repository you have admin access
- Run a workflow with a container job, for example - Run a workflow with a container job, for example
``` ```

View File

@@ -1,6 +1,6 @@
{ {
"name": "hooks", "name": "hooks",
"version": "0.1.3", "version": "0.2.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": {

View File

@@ -9,7 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0", "@actions/core": "^1.9.1",
"@actions/exec": "^1.1.1", "@actions/exec": "^1.1.1",
"hooklib": "file:../hooklib", "hooklib": "file:../hooklib",
"uuid": "^8.3.2" "uuid": "^8.3.2"
@@ -30,7 +30,7 @@
"version": "0.1.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0" "@actions/core": "^1.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^17.0.23", "@types/node": "^17.0.23",
@@ -43,11 +43,12 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.6.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
} }
}, },
"node_modules/@actions/exec": { "node_modules/@actions/exec": {
@@ -59,11 +60,11 @@
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": { "dependencies": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"node_modules/@actions/io": { "node_modules/@actions/io": {
@@ -5279,11 +5280,12 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.6.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"requires": { "requires": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
} }
}, },
"@actions/exec": { "@actions/exec": {
@@ -5295,11 +5297,11 @@
} }
}, },
"@actions/http-client": { "@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"@actions/io": { "@actions/io": {
@@ -7376,7 +7378,7 @@
"hooklib": { "hooklib": {
"version": "file:../hooklib", "version": "file:../hooklib",
"requires": { "requires": {
"@actions/core": "^1.6.0", "@actions/core": "^1.9.1",
"@types/node": "^17.0.23", "@types/node": "^17.0.23",
"@typescript-eslint/parser": "^5.18.0", "@typescript-eslint/parser": "^5.18.0",
"@zeit/ncc": "^0.22.3", "@zeit/ncc": "^0.22.3",

View File

@@ -10,7 +10,7 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0", "@actions/core": "^1.9.1",
"@actions/exec": "^1.1.1", "@actions/exec": "^1.1.1",
"hooklib": "file:../hooklib", "hooklib": "file:../hooklib",
"uuid": "^8.3.2" "uuid": "^8.3.2"

View File

@@ -427,6 +427,9 @@ export async function containerRun(
dockerArgs.push(args.image) dockerArgs.push(args.image)
if (args.entryPointArgs) { if (args.entryPointArgs) {
for (const entryPointArg of args.entryPointArgs) { for (const entryPointArg of args.entryPointArgs) {
if (!entryPointArg) {
continue
}
dockerArgs.push(entryPointArg) dockerArgs.push(entryPointArg)
} }
} }

View File

@@ -16,6 +16,7 @@ export async function runDockerCommand(
args: string[], args: string[],
options?: RunDockerCommandOptions options?: RunDockerCommandOptions
): Promise<string> { ): Promise<string> {
options = optionsWithDockerEnvs(options)
const pipes = await exec.getExecOutput('docker', args, options) const pipes = await exec.getExecOutput('docker', args, options)
if (pipes.exitCode !== 0) { if (pipes.exitCode !== 0) {
core.error(`Docker failed with exit code ${pipes.exitCode}`) core.error(`Docker failed with exit code ${pipes.exitCode}`)
@@ -24,6 +25,45 @@ export async function runDockerCommand(
return Promise.resolve(pipes.stdout) return Promise.resolve(pipes.stdout)
} }
export function optionsWithDockerEnvs(
options?: RunDockerCommandOptions
): RunDockerCommandOptions | undefined {
// From https://docs.docker.com/engine/reference/commandline/cli/#environment-variables
const dockerCliEnvs = new Set([
'DOCKER_API_VERSION',
'DOCKER_CERT_PATH',
'DOCKER_CONFIG',
'DOCKER_CONTENT_TRUST_SERVER',
'DOCKER_CONTENT_TRUST',
'DOCKER_CONTEXT',
'DOCKER_DEFAULT_PLATFORM',
'DOCKER_HIDE_LEGACY_COMMANDS',
'DOCKER_HOST',
'DOCKER_STACK_ORCHESTRATOR',
'DOCKER_TLS_VERIFY',
'BUILDKIT_PROGRESS'
])
const dockerEnvs = {}
for (const key in process.env) {
if (dockerCliEnvs.has(key)) {
dockerEnvs[key] = process.env[key]
}
}
const newOptions = {
workingDir: options?.workingDir,
input: options?.input,
env: options?.env || {}
}
// Set docker envs or overwrite provided ones
for (const [key, value] of Object.entries(dockerEnvs)) {
newOptions.env[key] = value as string
}
return newOptions
}
export function sanitize(val: string): string { export function sanitize(val: string): string {
if (!val || typeof val !== 'string') { if (!val || typeof val !== 'string') {
return '' return ''

View File

@@ -1,4 +1,4 @@
import { sanitize } from '../src/utils' import { optionsWithDockerEnvs, sanitize } from '../src/utils'
describe('Utilities', () => { describe('Utilities', () => {
it('should return sanitized image name', () => { it('should return sanitized image name', () => {
@@ -9,4 +9,41 @@ describe('Utilities', () => {
const validStr = 'teststr8_one' const validStr = 'teststr8_one'
expect(sanitize(validStr)).toBe(validStr) expect(sanitize(validStr)).toBe(validStr)
}) })
describe('with docker options', () => {
it('should augment options with docker environment variables', () => {
process.env.DOCKER_HOST = 'unix:///run/user/1001/docker.sock'
process.env.DOCKER_NOTEXIST = 'notexist'
const optionDefinitions: any = [
undefined,
{},
{ env: {} },
{ env: { DOCKER_HOST: 'unix://var/run/docker.sock' } }
]
for (const opt of optionDefinitions) {
let options = optionsWithDockerEnvs(opt)
expect(options).toBeDefined()
expect(options?.env).toBeDefined()
expect(options?.env?.DOCKER_HOST).toBe(process.env.DOCKER_HOST)
expect(options?.env?.DOCKER_NOTEXIST).toBeUndefined()
}
})
it('should not overwrite other options', () => {
process.env.DOCKER_HOST = 'unix:///run/user/1001/docker.sock'
const opt = {
workingDir: 'test',
input: Buffer.from('test')
}
const options = optionsWithDockerEnvs(opt)
expect(options).toBeDefined()
expect(options?.workingDir).toBe(opt.workingDir)
expect(options?.input).toBe(opt.input)
expect(options?.env).toStrictEqual({
DOCKER_HOST: process.env.DOCKER_HOST
})
})
})
}) })

View File

@@ -9,7 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0" "@actions/core": "^1.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^17.0.23", "@types/node": "^17.0.23",
@@ -22,19 +22,20 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.6.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": { "dependencies": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
@@ -2485,6 +2486,14 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache": { "node_modules/v8-compile-cache": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
@@ -2546,19 +2555,20 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.6.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"requires": { "requires": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
} }
}, },
"@actions/http-client": { "@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"@eslint/eslintrc": { "@eslint/eslintrc": {
@@ -4300,6 +4310,11 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"v8-compile-cache": { "v8-compile-cache": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",

View File

@@ -23,6 +23,6 @@
"typescript": "^4.6.3" "typescript": "^4.6.3"
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0" "@actions/core": "^1.9.1"
} }
} }

View File

@@ -9,7 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0", "@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.16.3",
@@ -28,7 +28,7 @@
"version": "0.1.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0" "@actions/core": "^1.9.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^17.0.23", "@types/node": "^17.0.23",
@@ -41,11 +41,20 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.8.2", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/core/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
} }
}, },
"node_modules/@actions/exec": { "node_modules/@actions/exec": {
@@ -3428,9 +3437,9 @@
} }
}, },
"node_modules/jose": { "node_modules/jose": {
"version": "2.0.5", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz",
"integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==",
"dependencies": { "dependencies": {
"@panva/asn1.js": "^1.0.0" "@panva/asn1.js": "^1.0.0"
}, },
@@ -5145,11 +5154,19 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.8.2", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"requires": { "requires": {
"@actions/http-client": "^2.0.1" "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
},
"dependencies": {
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
}
} }
}, },
"@actions/exec": { "@actions/exec": {
@@ -7074,7 +7091,7 @@
"hooklib": { "hooklib": {
"version": "file:../hooklib", "version": "file:../hooklib",
"requires": { "requires": {
"@actions/core": "^1.6.0", "@actions/core": "^1.9.1",
"@types/node": "^17.0.23", "@types/node": "^17.0.23",
"@typescript-eslint/parser": "^5.18.0", "@typescript-eslint/parser": "^5.18.0",
"@zeit/ncc": "^0.22.3", "@zeit/ncc": "^0.22.3",
@@ -7804,9 +7821,9 @@
} }
}, },
"jose": { "jose": {
"version": "2.0.5", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz",
"integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==",
"requires": { "requires": {
"@panva/asn1.js": "^1.0.0" "@panva/asn1.js": "^1.0.0"
} }

View File

@@ -13,7 +13,7 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.6.0", "@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.16.3",

View File

@@ -158,7 +158,7 @@ function createPodSpec(
name: string, name: string,
jobContainer = false jobContainer = false
): k8s.V1Container { ): k8s.V1Container {
if (!container.entryPoint) { if (!container.entryPoint && jobContainer) {
container.entryPoint = DEFAULT_CONTAINER_ENTRY_POINT container.entryPoint = DEFAULT_CONTAINER_ENTRY_POINT
container.entryPointArgs = DEFAULT_CONTAINER_ENTRY_POINT_ARGS container.entryPointArgs = DEFAULT_CONTAINER_ENTRY_POINT_ARGS
} }

View File

@@ -556,27 +556,37 @@ class BackOffManager {
export function containerPorts( export function containerPorts(
container: ContainerInfo container: ContainerInfo
): k8s.V1ContainerPort[] { ): k8s.V1ContainerPort[] {
// 8080:8080/tcp
const portFormat = /(\d{1,5})(:(\d{1,5}))?(\/(tcp|udp))?/
const ports: k8s.V1ContainerPort[] = [] const ports: k8s.V1ContainerPort[] = []
for (const portDefinition of container.portMappings) { for (const portDefinition of container.portMappings) {
const submatches = portFormat.exec(portDefinition) const portProtoSplit = portDefinition.split('/')
if (!submatches) { if (portProtoSplit.length > 2) {
throw new Error( throw new Error(`Unexpected port format: ${portDefinition}`)
`Port definition "${portDefinition}" is in incorrect format`
)
} }
const port = new k8s.V1ContainerPort() const port = new k8s.V1ContainerPort()
port.hostPort = Number(submatches[1]) port.protocol =
if (submatches[3]) { portProtoSplit.length === 2 ? portProtoSplit[1].toUpperCase() : 'TCP'
port.containerPort = Number(submatches[3])
const portSplit = portProtoSplit[0].split(':')
if (portSplit.length > 2) {
throw new Error('ports should have at most one ":" separator')
} }
if (submatches[5]) {
port.protocol = submatches[5].toUpperCase() const parsePort = (p: string): number => {
const num = Number(p)
if (!Number.isInteger(num) || num < 1 || num > 65535) {
throw new Error(`invalid container port: ${p}`)
}
return num
}
if (portSplit.length === 1) {
port.containerPort = parsePort(portSplit[0])
} else { } else {
port.protocol = 'TCP' port.hostPort = parsePort(portSplit[0])
port.containerPort = parsePort(portSplit[1])
} }
ports.push(port) ports.push(port)
} }
return ports return ports

View File

@@ -22,16 +22,18 @@ export function containerVolumes(
const workspacePath = process.env.GITHUB_WORKSPACE as string const workspacePath = process.env.GITHUB_WORKSPACE as string
if (containerAction) { if (containerAction) {
const i = workspacePath.lastIndexOf('_work/')
const workspaceRelativePath = workspacePath.slice(i + '_work/'.length)
mounts.push( mounts.push(
{ {
name: POD_VOLUME_NAME, name: POD_VOLUME_NAME,
mountPath: '/github/workspace', mountPath: '/github/workspace',
subPath: workspacePath.substring(workspacePath.indexOf('work/') + 1) subPath: workspaceRelativePath
}, },
{ {
name: POD_VOLUME_NAME, name: POD_VOLUME_NAME,
mountPath: '/github/file_commands', mountPath: '/github/file_commands',
subPath: workspacePath.substring(workspacePath.indexOf('work/') + 1) subPath: '_temp/_runner_file_commands'
} }
) )
return mounts return mounts

View File

@@ -4,6 +4,7 @@ import {
getSecretName, getSecretName,
getStepPodName, getStepPodName,
getVolumeClaimName, getVolumeClaimName,
JOB_CONTAINER_NAME,
MAX_POD_NAME_LENGTH, MAX_POD_NAME_LENGTH,
RunnerInstanceLabel, RunnerInstanceLabel,
STEP_POD_NAME_SUFFIX_LENGTH STEP_POD_NAME_SUFFIX_LENGTH
@@ -170,4 +171,12 @@ describe('constants', () => {
} }
}) })
}) })
describe('const values', () => {
it('should have constants set', () => {
expect(JOB_CONTAINER_NAME).toBeTruthy()
expect(MAX_POD_NAME_LENGTH).toBeGreaterThan(0)
expect(STEP_POD_NAME_SUFFIX_LENGTH).toBeGreaterThan(0)
})
})
}) })

View File

@@ -1,5 +1,5 @@
import * as fs from 'fs' import * as fs from 'fs'
import { POD_VOLUME_NAME } from '../src/k8s' import { containerPorts, POD_VOLUME_NAME } from '../src/k8s'
import { containerVolumes, writeEntryPointScript } from '../src/k8s/utils' import { containerVolumes, writeEntryPointScript } from '../src/k8s/utils'
import { TestHelper } from './test-setup' import { TestHelper } from './test-setup'
@@ -103,19 +103,22 @@ describe('k8s utils', () => {
it('should have container action volumes', () => { it('should have container action volumes', () => {
let volumes = containerVolumes([], true, true) let volumes = containerVolumes([], true, true)
expect( let workspace = volumes.find(e => e.mountPath === '/github/workspace')
volumes.find(e => e.mountPath === '/github/workspace') let fileCommands = volumes.find(
).toBeTruthy() e => e.mountPath === '/github/file_commands'
expect( )
volumes.find(e => e.mountPath === '/github/file_commands') expect(workspace).toBeTruthy()
).toBeTruthy() expect(workspace?.subPath).toBe('repo/repo')
expect(fileCommands).toBeTruthy()
expect(fileCommands?.subPath).toBe('_temp/_runner_file_commands')
volumes = containerVolumes([], false, true) volumes = containerVolumes([], false, true)
expect( workspace = volumes.find(e => e.mountPath === '/github/workspace')
volumes.find(e => e.mountPath === '/github/workspace') fileCommands = volumes.find(e => e.mountPath === '/github/file_commands')
).toBeTruthy() expect(workspace).toBeTruthy()
expect( expect(workspace?.subPath).toBe('repo/repo')
volumes.find(e => e.mountPath === '/github/file_commands') expect(fileCommands).toBeTruthy()
).toBeTruthy() expect(fileCommands?.subPath).toBe('_temp/_runner_file_commands')
}) })
it('should have externals, github home and github workflow mounts if job container', () => { it('should have externals, github home and github workflow mounts if job container', () => {
@@ -149,5 +152,73 @@ describe('k8s utils', () => {
volumes = containerVolumes([], false, false) volumes = containerVolumes([], false, false)
expect(volumes.every(e => e.name === POD_VOLUME_NAME)).toBeTruthy() expect(volumes.every(e => e.name === POD_VOLUME_NAME)).toBeTruthy()
}) })
it('should parse container ports', () => {
const tt = [
{
spec: '8080:80',
want: {
containerPort: 80,
hostPort: 8080,
protocol: 'TCP'
}
},
{
spec: '8080:80/udp',
want: {
containerPort: 80,
hostPort: 8080,
protocol: 'UDP'
}
},
{
spec: '8080/udp',
want: {
containerPort: 8080,
hostPort: undefined,
protocol: 'UDP'
}
},
{
spec: '8080',
want: {
containerPort: 8080,
hostPort: undefined,
protocol: 'TCP'
}
}
]
for (const tc of tt) {
const got = containerPorts({ portMappings: [tc.spec] })
for (const [key, value] of Object.entries(tc.want)) {
expect(got[0][key]).toBe(value)
}
}
})
it('should throw when ports are out of range (0, 65536)', () => {
expect(() => containerPorts({ portMappings: ['65536'] })).toThrow()
expect(() => containerPorts({ portMappings: ['0'] })).toThrow()
expect(() => containerPorts({ portMappings: ['65536/udp'] })).toThrow()
expect(() => containerPorts({ portMappings: ['0/udp'] })).toThrow()
expect(() => containerPorts({ portMappings: ['1:65536'] })).toThrow()
expect(() => containerPorts({ portMappings: ['65536:1'] })).toThrow()
expect(() => containerPorts({ portMappings: ['1:65536/tcp'] })).toThrow()
expect(() => containerPorts({ portMappings: ['65536:1/tcp'] })).toThrow()
expect(() => containerPorts({ portMappings: ['1:'] })).toThrow()
expect(() => containerPorts({ portMappings: [':1'] })).toThrow()
expect(() => containerPorts({ portMappings: ['1:/tcp'] })).toThrow()
expect(() => containerPorts({ portMappings: [':1/tcp'] })).toThrow()
})
it('should throw on multi ":" splits', () => {
expect(() => containerPorts({ portMappings: ['1:1:1'] })).toThrow()
})
it('should throw on multi "/" splits', () => {
expect(() => containerPorts({ portMappings: ['1:1/tcp/udp'] })).toThrow()
expect(() => containerPorts({ portMappings: ['1/tcp/udp'] })).toThrow()
})
}) })
}) })

View File

@@ -1,6 +1,9 @@
## Features ## Features
- Always use the Docker related ENVs from the host machine instead of ENVs from the runner job [#40]
- Use user defined entrypoints for service containers (instead of `tail -f /dev/null`)
## Bugs ## Bugs
- Fixed an issue where default private registry images did not pull correctly [#25] - Fixed substring issue with /github/workspace and /github/file_commands [#35]
- Fixed issue related to setting hostPort and containerPort when formatting is not recognized by k8s default [#38]
## Misc <!-- ## Misc