refactored the api to accept remote registry, not complete yet

This commit is contained in:
Nikola Jokic
2022-10-21 16:03:14 +02:00
parent 4e674e284a
commit 11de25a121
6 changed files with 95 additions and 70 deletions

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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'

View File

@@ -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`)
}

View File

@@ -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))

View File

@@ -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
}
}