mirror of
https://github.com/actions/runner-container-hooks.git
synced 2025-12-18 02:36:44 +00:00
refactored the api to accept remote registry, not complete yet
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as k8s from '@kubernetes/client-node'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { RunContainerStepArgs } from 'hooklib'
|
||||
import {
|
||||
createJob,
|
||||
@@ -25,8 +24,7 @@ export async function runContainerStep(
|
||||
stepContainer: RunContainerStepArgs
|
||||
): Promise<number> {
|
||||
if (stepContainer.dockerfile) {
|
||||
const imagePath = `${generateBuildHandle()}/${generateBuildTag()}`
|
||||
const imageUrl = await containerBuild(stepContainer, imagePath)
|
||||
const imageUrl = await containerBuild(stepContainer)
|
||||
stepContainer.image = imageUrl
|
||||
}
|
||||
|
||||
@@ -112,11 +110,3 @@ function createPodSpec(
|
||||
|
||||
return podContainer
|
||||
}
|
||||
|
||||
function generateBuildTag(): string {
|
||||
return `${uuidv4()}:${uuidv4()}`
|
||||
}
|
||||
|
||||
function generateBuildHandle(): string {
|
||||
return uuidv4()
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
RunnerInstanceLabel
|
||||
} from '../hooks/constants'
|
||||
import { kanikoPod } from './kaniko'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { PodPhase } from './utils'
|
||||
import {
|
||||
namespace,
|
||||
@@ -18,7 +19,11 @@ import {
|
||||
k8sApi,
|
||||
k8sBatchV1Api,
|
||||
k8sAuthorizationV1Api,
|
||||
registryNodePort
|
||||
localRegistryNodePort,
|
||||
localRegistryHost,
|
||||
localRegistryPort,
|
||||
remoteRegistryHost,
|
||||
remoteRegistryHandle
|
||||
} from './settings'
|
||||
|
||||
export * from './settings'
|
||||
@@ -475,11 +480,21 @@ export async function isPodContainerAlpine(
|
||||
}
|
||||
|
||||
export async function containerBuild(
|
||||
args: RunContainerStepArgs,
|
||||
imagePath: string
|
||||
args: RunContainerStepArgs
|
||||
): Promise<string> {
|
||||
const registryUri = `localhost:${registryNodePort()}/${imagePath}`
|
||||
const pod = kanikoPod(args.dockerfile, imagePath)
|
||||
let kanikoRegistry = ''
|
||||
let pullRegistry = ''
|
||||
if (localRegistryHost()) {
|
||||
const host = `${localRegistryHost()}.${namespace()}.svc.cluster.local`
|
||||
const port = localRegistryPort()
|
||||
const uri = `${generateBuildHandle()}/${generateBuildImage()}`
|
||||
kanikoRegistry = `${host}:${port}/${uri}`
|
||||
pullRegistry = `localhost:${localRegistryNodePort()}/${uri}`
|
||||
} else {
|
||||
kanikoRegistry = `${remoteRegistryHost()}/${remoteRegistryHandle()}/${generateBuildImage()}`
|
||||
pullRegistry = kanikoRegistry
|
||||
}
|
||||
const pod = kanikoPod(args.dockerfile, kanikoRegistry)
|
||||
if (!pod.metadata?.name) {
|
||||
throw new Error('kaniko pod name is not set')
|
||||
}
|
||||
@@ -489,7 +504,7 @@ export async function containerBuild(
|
||||
new Set([PodPhase.SUCCEEDED]),
|
||||
new Set([PodPhase.PENDING, PodPhase.UNKNOWN, PodPhase.RUNNING])
|
||||
)
|
||||
return registryUri
|
||||
return pullRegistry
|
||||
}
|
||||
|
||||
async function getCurrentNodeName(): Promise<string> {
|
||||
@@ -556,3 +571,11 @@ export function containerPorts(
|
||||
}
|
||||
return ports
|
||||
}
|
||||
|
||||
function generateBuildImage(): string {
|
||||
return `${uuidv4()}:${uuidv4()}`
|
||||
}
|
||||
|
||||
function generateBuildHandle(): string {
|
||||
return uuidv4()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as k8s from '@kubernetes/client-node'
|
||||
import * as path from 'path'
|
||||
import { namespace, registryHost, registryPort } from './settings'
|
||||
import {
|
||||
getRunnerPodName,
|
||||
getVolumeClaimName,
|
||||
@@ -18,10 +17,7 @@ function getKanikoName(): string {
|
||||
)}-kaniko`
|
||||
}
|
||||
|
||||
export function kanikoPod(
|
||||
dockerfile: string,
|
||||
imagePath: string // <handle>/<image>:<tag>
|
||||
): k8s.V1Pod {
|
||||
export function kanikoPod(dockerfile: string, destination: string): k8s.V1Pod {
|
||||
const pod = new k8s.V1Pod()
|
||||
pod.apiVersion = 'v1'
|
||||
pod.kind = 'Pod'
|
||||
@@ -53,7 +49,7 @@ export function kanikoPod(
|
||||
c.args = [
|
||||
`--dockerfile=${path.basename(dockerfile)}`,
|
||||
`--context=dir://${KANIKO_MOUNT_PATH}`,
|
||||
`--destination=${registryHost()}.${namespace()}.svc.cluster.local:${registryPort()}/${imagePath}`
|
||||
`--destination=${destination}`
|
||||
]
|
||||
spec.containers = [c]
|
||||
spec.dnsPolicy = 'ClusterFirst'
|
||||
|
||||
@@ -22,26 +22,42 @@ export function namespace(): string {
|
||||
return context.namespace
|
||||
}
|
||||
|
||||
export function registryHost(): string {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_REGISTRY_HOST'
|
||||
export function localRegistryHost(): string {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_LOCAL_REGISTRY_HOST'
|
||||
if (process.env[name]) {
|
||||
return process.env[name]
|
||||
}
|
||||
throw new Error(`environment variable ${name} is not set`)
|
||||
}
|
||||
|
||||
export function registryPort(): number {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_REGISTRY_PORT'
|
||||
export function localRegistryPort(): number {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_LOCAL_REGISTRY_PORT'
|
||||
if (process.env[name]) {
|
||||
return parseInt(process.env[name])
|
||||
}
|
||||
throw new Error(`environment variable ${name} is not set`)
|
||||
}
|
||||
|
||||
export function registryNodePort(): number {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_REGISTRY_NODE_PORT'
|
||||
export function localRegistryNodePort(): number {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_LOCAL_REGISTRY_NODE_PORT'
|
||||
if (process.env[name]) {
|
||||
return parseInt(process.env[name])
|
||||
}
|
||||
throw new Error(`environment variable ${name} is not set`)
|
||||
}
|
||||
|
||||
export function remoteRegistryHost(): string {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_REMOTE_REGISTRY_HOST'
|
||||
if (process.env[name]) {
|
||||
return process.env[name]
|
||||
}
|
||||
throw new Error(`environment variable ${name} is not set`)
|
||||
}
|
||||
|
||||
export function remoteRegistryHandle(): string {
|
||||
const name = 'ACTIONS_RUNNER_CONTAINER_HOOKS_REMOTE_REGISTRY_HANDLE'
|
||||
if (process.env[name]) {
|
||||
return process.env[name]
|
||||
}
|
||||
throw new Error(`environment variable ${name} is not set`)
|
||||
}
|
||||
|
||||
@@ -3,41 +3,41 @@ import { TestHelper } from './test-setup'
|
||||
|
||||
jest.useRealTimers()
|
||||
|
||||
describe('Run container step with image', () => {
|
||||
let testHelper: TestHelper
|
||||
let runContainerStepData: any
|
||||
// describe('Run container step with image', () => {
|
||||
// let testHelper: TestHelper
|
||||
// let runContainerStepData: any
|
||||
|
||||
beforeEach(async () => {
|
||||
testHelper = new TestHelper()
|
||||
await testHelper.initialize()
|
||||
runContainerStepData = testHelper.getRunContainerStepDefinition()
|
||||
})
|
||||
// beforeEach(async () => {
|
||||
// testHelper = new TestHelper()
|
||||
// await testHelper.initialize()
|
||||
// runContainerStepData = testHelper.getRunContainerStepDefinition()
|
||||
// })
|
||||
|
||||
afterEach(async () => {
|
||||
await testHelper.cleanup()
|
||||
})
|
||||
// afterEach(async () => {
|
||||
// await testHelper.cleanup()
|
||||
// })
|
||||
|
||||
it('should not throw', async () => {
|
||||
const exitCode = await runContainerStep(runContainerStepData.args)
|
||||
expect(exitCode).toBe(0)
|
||||
})
|
||||
// it('should not throw', async () => {
|
||||
// const exitCode = await runContainerStep(runContainerStepData.args)
|
||||
// expect(exitCode).toBe(0)
|
||||
// })
|
||||
|
||||
it('should fail if the working directory does not exist', async () => {
|
||||
runContainerStepData.args.workingDirectory = '/foo/bar'
|
||||
await expect(runContainerStep(runContainerStepData.args)).rejects.toThrow()
|
||||
})
|
||||
// it('should fail if the working directory does not exist', async () => {
|
||||
// runContainerStepData.args.workingDirectory = '/foo/bar'
|
||||
// await expect(runContainerStep(runContainerStepData.args)).rejects.toThrow()
|
||||
// })
|
||||
|
||||
it('should shold have env variables available', async () => {
|
||||
runContainerStepData.args.entryPoint = 'bash'
|
||||
runContainerStepData.args.entryPointArgs = [
|
||||
'-c',
|
||||
"'if [[ -z $NODE_ENV ]]; then exit 1; fi'"
|
||||
]
|
||||
await expect(
|
||||
runContainerStep(runContainerStepData.args)
|
||||
).resolves.not.toThrow()
|
||||
})
|
||||
})
|
||||
// it('should shold have env variables available', async () => {
|
||||
// runContainerStepData.args.entryPoint = 'bash'
|
||||
// runContainerStepData.args.entryPointArgs = [
|
||||
// '-c',
|
||||
// "'if [[ -z $NODE_ENV ]]; then exit 1; fi'"
|
||||
// ]
|
||||
// await expect(
|
||||
// runContainerStep(runContainerStepData.args)
|
||||
// ).resolves.not.toThrow()
|
||||
// })
|
||||
// })
|
||||
|
||||
describe('run container step with docker build', () => {
|
||||
let testHelper: TestHelper
|
||||
@@ -53,13 +53,13 @@ describe('run container step with docker build', () => {
|
||||
})
|
||||
|
||||
it('should build container and execute docker action', async () => {
|
||||
const { registryName, registryPort, nodePort } =
|
||||
const { registryName, localRegistryPort, nodePort } =
|
||||
await testHelper.createContainerRegistry()
|
||||
|
||||
process.env.ACTIONS_RUNNER_CONTAINER_HOOKS_REGISTRY_HOST = registryName
|
||||
process.env.ACTIONS_RUNNER_CONTAINER_HOOKS_REGISTRY_PORT =
|
||||
registryPort.toString()
|
||||
process.env.ACTIONS_RUNNER_CONTAINER_HOOKS_REGISTRY_NODE_PORT =
|
||||
process.env.ACTIONS_RUNNER_CONTAINER_HOOKS_LOCAL_REGISTRY_HOST = registryName
|
||||
process.env.ACTIONS_RUNNER_CONTAINER_HOOKS_LOCAL_REGISTRY_PORT =
|
||||
localRegistryPort.toString()
|
||||
process.env.ACTIONS_RUNNER_CONTAINER_HOOKS_LOCAL_REGISTRY_NODE_PORT =
|
||||
nodePort.toString()
|
||||
const actionPath = testHelper.initializeDockerAction()
|
||||
const data = JSON.parse(JSON.stringify(runContainerStepData))
|
||||
|
||||
@@ -209,17 +209,17 @@ export class TestHelper {
|
||||
|
||||
public async createContainerRegistry(): Promise<{
|
||||
registryName: string
|
||||
registryPort: number
|
||||
localRegistryPort: number
|
||||
nodePort: number
|
||||
}> {
|
||||
const registryName = 'docker-registry'
|
||||
const registryPort = 5000
|
||||
const localRegistryPort = 5000
|
||||
const nodePort = 31500
|
||||
|
||||
const cm = registryConfigMap(registryName, registryPort)
|
||||
const cm = registryConfigMap(registryName, localRegistryPort)
|
||||
const secret = registrySecret(registryName)
|
||||
const ss = registryStatefulSet(registryName, registryPort)
|
||||
const svc = registryService(registryName, registryPort, nodePort)
|
||||
const ss = registryStatefulSet(registryName, localRegistryPort)
|
||||
const svc = registryService(registryName, localRegistryPort, nodePort)
|
||||
const namespace =
|
||||
process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] || 'default'
|
||||
|
||||
@@ -236,7 +236,7 @@ export class TestHelper {
|
||||
await k8sApi.createNamespacedService(namespace, svc)
|
||||
return {
|
||||
registryName,
|
||||
registryPort,
|
||||
localRegistryPort,
|
||||
nodePort
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user