From 63b6cf66ac7209d20c968a4d34fb030b9a1a2d5f Mon Sep 17 00:00:00 2001 From: Nils Plaschke <Chumper@users.noreply.github.com> Date: Thu, 8 Apr 2021 12:10:25 +0200 Subject: [PATCH] feat: introduce dockerChildPrefix option (#8613) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Rhys Arkins <rhys@arkins.net> Co-authored-by: Michael Kriese <michael.kriese@visualon.de> --- docs/usage/self-hosted-configuration.md | 8 ++++++ lib/config/admin.ts | 1 + lib/config/definitions.ts | 8 ++++++ lib/config/types.ts | 1 + lib/util/exec/docker/index.ts | 34 +++++++++++++++++-------- lib/util/exec/exec.spec.ts | 30 ++++++++++++++++++++++ lib/util/exec/index.ts | 21 ++++++++------- 7 files changed, 83 insertions(+), 20 deletions(-) diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index 138be9db3c..ee1de0277f 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -132,6 +132,14 @@ Set to `false` to prevent usage of `--ignore-platform-reqs` in the Composer pack This configuration will be applied after all other environment variables so that it can be used to override defaults. +## dockerChildPrefix + +Adds a custom prefix to the default Renovate sidecar Docker containers name and label. + +If this is set to `myprefix_` the final image name for `renovate/node` would be named `myprefix_node` instead of currently used `renovate_node` and be labeled `myprefix_child` instead of `renovate_child`. + +Note that dangling containers will not be removed until Renovate is run with the same prefix again. + ## dockerImagePrefix By default Renovate pulls the sidecar Docker containers from `docker.io/renovate`. diff --git a/lib/config/admin.ts b/lib/config/admin.ts index f6af54b53f..6d6fd61fc6 100644 --- a/lib/config/admin.ts +++ b/lib/config/admin.ts @@ -7,6 +7,7 @@ export const repoAdminOptions = [ 'allowPostUpgradeCommandTemplating', 'allowedPostUpgradeCommands', 'customEnvVariables', + 'dockerChildPrefix', 'dockerImagePrefix', 'dockerUser', 'dryRun', diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts index ecf25ed672..9cffe44733 100644 --- a/lib/config/definitions.ts +++ b/lib/config/definitions.ts @@ -251,6 +251,14 @@ const options: RenovateOptions[] = [ type: 'boolean', default: false, }, + { + name: 'dockerChildPrefix', + description: + 'Change this value in order to add a prefix to the Renovate Docker sidecar image names and labels.', + type: 'string', + admin: true, + default: 'renovate_', + }, { name: 'dockerImagePrefix', description: diff --git a/lib/config/types.ts b/lib/config/types.ts index f98003293e..5a1e066b81 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -87,6 +87,7 @@ export interface RepoAdminConfig { allowPostUpgradeCommandTemplating?: boolean; allowedPostUpgradeCommands?: string[]; customEnvVariables?: Record<string, string>; + dockerChildPrefix?: string; dockerImagePrefix?: string; dockerUser?: string; dryRun?: boolean; diff --git a/lib/util/exec/docker/index.ts b/lib/util/exec/docker/index.ts index b8707f7e72..bf0a39c2fa 100644 --- a/lib/util/exec/docker/index.ts +++ b/lib/util/exec/docker/index.ts @@ -115,12 +115,19 @@ async function getDockerTag( return 'latest'; } -function getContainerName(image: string): string { - return `renovate_${image}`.replace(/\//g, '_'); +function getContainerName(image: string, prefix?: string): string { + return `${prefix || 'renovate_'}${image}`.replace(/\//g, '_'); } -export async function removeDockerContainer(image: string): Promise<void> { - const containerName = getContainerName(image); +function getContainerLabel(prefix: string): string { + return `${prefix || 'renovate_'}child`; +} + +export async function removeDockerContainer( + image: string, + prefix: string +): Promise<void> { + const containerName = getContainerName(image, prefix); let cmd = `docker ps --filter name=${containerName} -aq`; try { const res = await rawExec(cmd, { @@ -146,11 +153,15 @@ export async function removeDockerContainer(image: string): Promise<void> { } // istanbul ignore next -export async function removeDanglingContainers(): Promise<void> { +export async function removeDanglingContainers(prefix: string): Promise<void> { try { - const res = await rawExec(`docker ps --filter label=renovate_child -aq`, { - encoding: 'utf-8', - }); + const containerLabel = getContainerLabel(prefix); + const res = await rawExec( + `docker ps --filter label=${containerLabel} -aq`, + { + encoding: 'utf-8', + } + ); if (res?.stdout?.trim().length) { const containerIds = res.stdout .trim() @@ -187,11 +198,12 @@ export async function generateDockerCommand( const preCommands = options.preCommands || []; const postCommands = options.postCommands || []; const { localDir, cacheDir } = config; - const { dockerUser, dockerImagePrefix } = getAdminConfig(); + const { dockerUser, dockerChildPrefix, dockerImagePrefix } = getAdminConfig(); const result = ['docker run --rm']; - const containerName = getContainerName(image); + const containerName = getContainerName(image, dockerChildPrefix); + const containerLabel = getContainerLabel(dockerChildPrefix); result.push(`--name=${containerName}`); - result.push(`--label=renovate_child`); + result.push(`--label=${containerLabel}`); if (dockerUser) { result.push(`--user=${dockerUser}`); } diff --git a/lib/util/exec/exec.spec.ts b/lib/util/exec/exec.spec.ts index 3fb345ca0d..f5a67fbda5 100644 --- a/lib/util/exec/exec.spec.ts +++ b/lib/util/exec/exec.spec.ts @@ -448,6 +448,36 @@ describe(getName(__filename), () => { }, ], + [ + 'Docker child prefix', + { + execConfig: { + ...execConfig, + binarySource: BinarySource.Docker, + }, + processEnv, + inCmd, + inOpts: { docker }, + outCmd: [ + dockerPullCmd, + `docker ps --filter name=myprefix_${image} -aq`, + `docker run --rm --name=myprefix_${image} --label=myprefix_child ${defaultVolumes} -w "${cwd}" ${fullImage} bash -l -c "${inCmd}"`, + ], + outOpts: [ + dockerPullOpts, + dockerRemoveOpts, + { + cwd, + encoding, + env: envMock.basic, + timeout: 900000, + maxBuffer: 10485760, + }, + ], + adminConfig: { dockerChildPrefix: 'myprefix_' }, + }, + ], + [ 'Docker extra commands', { diff --git a/lib/util/exec/index.ts b/lib/util/exec/index.ts index f4cfa79596..c2205e02c4 100644 --- a/lib/util/exec/index.ts +++ b/lib/util/exec/index.ts @@ -34,7 +34,7 @@ export async function setExecConfig( execConfig[key] = value || null; } if (execConfig.binarySource === 'docker') { - await removeDanglingContainers(); + await removeDanglingContainers(getAdminConfig().dockerChildPrefix); } } @@ -95,7 +95,8 @@ export async function exec( opts: ExecOptions = {} ): Promise<ExecResult> { const { env, docker, cwdFile } = opts; - const extraEnv = { ...opts.extraEnv, ...getAdminConfig().customEnvVariables }; + const { dockerChildPrefix, customEnvVariables } = getAdminConfig(); + const extraEnv = { ...opts.extraEnv, ...customEnvVariables }; let cwd; // istanbul ignore if if (cwdFile) { @@ -142,7 +143,7 @@ export async function exec( for (const rawExecCommand of commands) { const startTime = Date.now(); if (useDocker) { - await removeDockerContainer(docker.image); + await removeDockerContainer(docker.image, dockerChildPrefix); } logger.debug({ command: rawExecCommand }, 'Executing command'); logger.trace({ commandOptions: rawExecOptions }, 'Command options'); @@ -151,12 +152,14 @@ export async function exec( } catch (err) { logger.trace({ err }, 'rawExec err'); if (useDocker) { - await removeDockerContainer(docker.image).catch((removeErr: Error) => { - const message: string = err.message; - throw new Error( - `Error: "${removeErr.message}" - Original Error: "${message}"` - ); - }); + await removeDockerContainer(docker.image, dockerChildPrefix).catch( + (removeErr: Error) => { + const message: string = err.message; + throw new Error( + `Error: "${removeErr.message}" - Original Error: "${message}"` + ); + } + ); } if (err.signal === `SIGTERM`) { logger.debug( -- GitLab