mirror of
https://github.com/actions/runner-container-hooks.git
synced 2025-12-14 16:46:43 +00:00
* added initial entrypoint script * change workingg directory working with addition to fix prepare-job state output * added prepend path * added run-script-step file generation, removed prepend path from container-step and prepare job * latest changes with testing run script step * fix the mounts real fast * cleanup * fix tests * add kind test * add kind yaml to ignore and run it during ci * fix kind option * remove gitignore * lowercase pwd * checkout first! * ignore test file in build.yaml * fixed wrong working directory and added test to run script step testing for the env * handle env's/escaping better * added single quote escape to env escapes * surounded env value with single quote * added spacing around run-container-step, changed examples to actually echo hello world * refactored tests * make sure to escape properly * set addition mounts for container steps * fixup container action mounts Co-authored-by: Thomas Boop <thboop@github.com> Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
198 lines
5.3 KiB
TypeScript
198 lines
5.3 KiB
TypeScript
import * as k8s from '@kubernetes/client-node'
|
|
import * as fs from 'fs'
|
|
import { HookData } from 'hooklib/lib'
|
|
import * as path from 'path'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
|
|
const kc = new k8s.KubeConfig()
|
|
|
|
kc.loadFromDefault()
|
|
|
|
const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
|
|
const k8sStorageApi = kc.makeApiClient(k8s.StorageV1Api)
|
|
|
|
export class TestHelper {
|
|
private tempDirPath: string
|
|
private podName: string
|
|
constructor() {
|
|
this.tempDirPath = `${__dirname}/_temp/runner`
|
|
this.podName = uuidv4().replace(/-/g, '')
|
|
}
|
|
|
|
public async initialize(): Promise<void> {
|
|
process.env['ACTIONS_RUNNER_POD_NAME'] = `${this.podName}`
|
|
process.env['ACTIONS_RUNNER_CLAIM_NAME'] = `${this.podName}-work`
|
|
process.env['RUNNER_WORKSPACE'] = `${this.tempDirPath}/_work/repo`
|
|
process.env['RUNNER_TEMP'] = `${this.tempDirPath}/_work/_temp`
|
|
process.env['GITHUB_WORKSPACE'] = `${this.tempDirPath}/_work/repo/repo`
|
|
process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'default'
|
|
|
|
fs.mkdirSync(`${this.tempDirPath}/_work/repo/repo`, { recursive: true })
|
|
fs.mkdirSync(`${this.tempDirPath}/externals`, { recursive: true })
|
|
fs.mkdirSync(process.env.RUNNER_TEMP, { recursive: true })
|
|
|
|
fs.copyFileSync(
|
|
path.resolve(`${__dirname}/../../../examples/example-script.sh`),
|
|
`${process.env.RUNNER_TEMP}/example-script.sh`
|
|
)
|
|
|
|
await this.cleanupK8sResources()
|
|
try {
|
|
await this.createTestVolume()
|
|
await this.createTestJobPod()
|
|
} catch (e) {
|
|
console.log(JSON.stringify(e))
|
|
}
|
|
}
|
|
|
|
public async cleanup(): Promise<void> {
|
|
try {
|
|
await this.cleanupK8sResources()
|
|
fs.rmSync(this.tempDirPath, { recursive: true })
|
|
} catch {}
|
|
}
|
|
public async cleanupK8sResources() {
|
|
await k8sApi
|
|
.deleteNamespacedPersistentVolumeClaim(
|
|
`${this.podName}-work`,
|
|
'default',
|
|
undefined,
|
|
undefined,
|
|
0
|
|
)
|
|
.catch(e => {})
|
|
await k8sApi.deletePersistentVolume(`${this.podName}-pv`).catch(e => {})
|
|
await k8sStorageApi.deleteStorageClass('local-storage').catch(e => {})
|
|
await k8sApi
|
|
.deleteNamespacedPod(this.podName, 'default', undefined, undefined, 0)
|
|
.catch(e => {})
|
|
await k8sApi
|
|
.deleteNamespacedPod(
|
|
`${this.podName}-workflow`,
|
|
'default',
|
|
undefined,
|
|
undefined,
|
|
0
|
|
)
|
|
.catch(e => {})
|
|
}
|
|
public createFile(fileName?: string): string {
|
|
const filePath = `${this.tempDirPath}/${fileName || uuidv4()}`
|
|
fs.writeFileSync(filePath, '')
|
|
return filePath
|
|
}
|
|
|
|
public removeFile(fileName: string): void {
|
|
const filePath = `${this.tempDirPath}/${fileName}`
|
|
fs.rmSync(filePath)
|
|
}
|
|
|
|
public async createTestJobPod() {
|
|
const container = {
|
|
name: 'nginx',
|
|
image: 'nginx:latest',
|
|
imagePullPolicy: 'IfNotPresent'
|
|
} as k8s.V1Container
|
|
|
|
const pod: k8s.V1Pod = {
|
|
metadata: {
|
|
name: this.podName
|
|
},
|
|
spec: {
|
|
restartPolicy: 'Never',
|
|
containers: [container]
|
|
}
|
|
} as k8s.V1Pod
|
|
await k8sApi.createNamespacedPod('default', pod)
|
|
}
|
|
|
|
public async createTestVolume() {
|
|
var sc: k8s.V1StorageClass = {
|
|
metadata: {
|
|
name: 'local-storage'
|
|
},
|
|
provisioner: 'kubernetes.io/no-provisioner',
|
|
volumeBindingMode: 'Immediate'
|
|
}
|
|
await k8sStorageApi.createStorageClass(sc)
|
|
|
|
var volume: k8s.V1PersistentVolume = {
|
|
metadata: {
|
|
name: `${this.podName}-pv`
|
|
},
|
|
spec: {
|
|
storageClassName: 'local-storage',
|
|
capacity: {
|
|
storage: '2Gi'
|
|
},
|
|
volumeMode: 'Filesystem',
|
|
accessModes: ['ReadWriteOnce'],
|
|
hostPath: {
|
|
path: `${this.tempDirPath}/_work`
|
|
}
|
|
}
|
|
}
|
|
await k8sApi.createPersistentVolume(volume)
|
|
var volumeClaim: k8s.V1PersistentVolumeClaim = {
|
|
metadata: {
|
|
name: `${this.podName}-work`
|
|
},
|
|
spec: {
|
|
accessModes: ['ReadWriteOnce'],
|
|
volumeMode: 'Filesystem',
|
|
storageClassName: 'local-storage',
|
|
volumeName: `${this.podName}-pv`,
|
|
resources: {
|
|
requests: {
|
|
storage: '1Gi'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
await k8sApi.createNamespacedPersistentVolumeClaim('default', volumeClaim)
|
|
}
|
|
|
|
public getPrepareJobDefinition(): HookData {
|
|
const prepareJob = JSON.parse(
|
|
fs.readFileSync(
|
|
path.resolve(__dirname + '/../../../examples/prepare-job.json'),
|
|
'utf8'
|
|
)
|
|
)
|
|
|
|
prepareJob.args.container.userMountVolumes = undefined
|
|
prepareJob.args.container.registry = null
|
|
prepareJob.args.services.forEach(s => {
|
|
s.registry = null
|
|
})
|
|
|
|
return prepareJob
|
|
}
|
|
|
|
public getRunScriptStepDefinition(): HookData {
|
|
const runScriptStep = JSON.parse(
|
|
fs.readFileSync(
|
|
path.resolve(__dirname + '/../../../examples/run-script-step.json'),
|
|
'utf8'
|
|
)
|
|
)
|
|
|
|
runScriptStep.args.entryPointArgs[1] = `/__w/_temp/example-script.sh`
|
|
return runScriptStep
|
|
}
|
|
|
|
public getRunContainerStepDefinition(): HookData {
|
|
const runContainerStep = JSON.parse(
|
|
fs.readFileSync(
|
|
path.resolve(__dirname + '/../../../examples/run-container-step.json'),
|
|
'utf8'
|
|
)
|
|
)
|
|
|
|
runContainerStep.args.entryPointArgs[1] = `/__w/_temp/example-script.sh`
|
|
runContainerStep.args.userMountVolumes = undefined
|
|
runContainerStep.args.registry = null
|
|
return runContainerStep
|
|
}
|
|
}
|