mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-14 08:36:26 +00:00
feat(manager/terraform): support multiple container images (#16107)
Co-authored-by: Rhys Arkins <rhys@arkins.net>
This commit is contained in:
parent
d05e22e081
commit
827d313de4
5 changed files with 108 additions and 4 deletions
|
@ -11,6 +11,10 @@ resource "kubernetes_cron_job_v1" "demo" {
|
||||||
name = "kaniko"
|
name = "kaniko"
|
||||||
image = "gcr.io/kaniko-project/executor:v1.7.0@sha256:8504bde9a9a8c9c4e9a4fe659703d265697a36ff13607b7669a4caa4407baa52"
|
image = "gcr.io/kaniko-project/executor:v1.7.0@sha256:8504bde9a9a8c9c4e9a4fe659703d265697a36ff13607b7669a4caa4407baa52"
|
||||||
}
|
}
|
||||||
|
container {
|
||||||
|
name = "node"
|
||||||
|
image = "node:14"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +130,7 @@ resource "kubernetes_job" "demo_invalid" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
image = "nginx:1.21.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,8 +107,8 @@ describe('modules/manager/terraform/extract', () => {
|
||||||
|
|
||||||
it('extracts kubernetes resources', async () => {
|
it('extracts kubernetes resources', async () => {
|
||||||
const res = await extractPackageFile(kubernetes, 'kubernetes.tf', {});
|
const res = await extractPackageFile(kubernetes, 'kubernetes.tf', {});
|
||||||
expect(res.deps).toHaveLength(16);
|
expect(res.deps).toHaveLength(18);
|
||||||
expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(2);
|
expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(1);
|
||||||
expect(res.deps).toMatchObject([
|
expect(res.deps).toMatchObject([
|
||||||
{
|
{
|
||||||
depName: 'gcr.io/kaniko-project/executor',
|
depName: 'gcr.io/kaniko-project/executor',
|
||||||
|
@ -117,6 +117,11 @@ describe('modules/manager/terraform/extract', () => {
|
||||||
'sha256:8504bde9a9a8c9c4e9a4fe659703d265697a36ff13607b7669a4caa4407baa52',
|
'sha256:8504bde9a9a8c9c4e9a4fe659703d265697a36ff13607b7669a4caa4407baa52',
|
||||||
depType: 'kubernetes_cron_job_v1',
|
depType: 'kubernetes_cron_job_v1',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
depName: 'node',
|
||||||
|
currentValue: '14',
|
||||||
|
depType: 'kubernetes_cron_job_v1',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
depName: 'gcr.io/kaniko-project/executor',
|
depName: 'gcr.io/kaniko-project/executor',
|
||||||
currentValue: 'v1.8.0',
|
currentValue: 'v1.8.0',
|
||||||
|
@ -149,7 +154,6 @@ describe('modules/manager/terraform/extract', () => {
|
||||||
currentValue: '1.21.5',
|
currentValue: '1.21.5',
|
||||||
depType: 'kubernetes_job',
|
depType: 'kubernetes_job',
|
||||||
},
|
},
|
||||||
{ skipReason: 'invalid-dependency-specification' },
|
|
||||||
{ skipReason: 'invalid-value' },
|
{ skipReason: 'invalid-value' },
|
||||||
{
|
{
|
||||||
depName: 'nginx',
|
depName: 'nginx',
|
||||||
|
@ -176,11 +180,21 @@ describe('modules/manager/terraform/extract', () => {
|
||||||
currentValue: '1.21.10',
|
currentValue: '1.21.10',
|
||||||
depType: 'kubernetes_replication_controller_v1',
|
depType: 'kubernetes_replication_controller_v1',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
depName: 'nginx',
|
||||||
|
currentValue: '1.21.11',
|
||||||
|
depType: 'kubernetes_stateful_set',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
depName: 'prom/prometheus',
|
depName: 'prom/prometheus',
|
||||||
currentValue: 'v2.2.1',
|
currentValue: 'v2.2.1',
|
||||||
depType: 'kubernetes_stateful_set',
|
depType: 'kubernetes_stateful_set',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
depName: 'nginx',
|
||||||
|
currentValue: '1.21.12',
|
||||||
|
depType: 'kubernetes_stateful_set_v1',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
depName: 'prom/prometheus',
|
depName: 'prom/prometheus',
|
||||||
currentValue: 'v2.2.2',
|
currentValue: 'v2.2.2',
|
||||||
|
|
76
lib/modules/manager/terraform/extract/kubernetes.ts
Normal file
76
lib/modules/manager/terraform/extract/kubernetes.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import is from '@sindresorhus/is';
|
||||||
|
import { logger } from '../../../../logger';
|
||||||
|
import { regEx } from '../../../../util/regex';
|
||||||
|
import type { PackageDependency } from '../../types';
|
||||||
|
import { TerraformDependencyTypes } from '../common';
|
||||||
|
import type { ExtractionResult, ResourceManagerData } from '../types';
|
||||||
|
import { keyValueExtractionRegex } from '../util';
|
||||||
|
|
||||||
|
export function extractTerraformKubernetesResource(
|
||||||
|
startingLine: number,
|
||||||
|
lines: string[],
|
||||||
|
resourceType: string
|
||||||
|
): ExtractionResult {
|
||||||
|
let lineNumber = startingLine;
|
||||||
|
const deps: PackageDependency<ResourceManagerData>[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over all lines of the resource to extract the relevant key value pairs,
|
||||||
|
* e.g. the chart name for helm charts or the terraform_version for tfe_workspace
|
||||||
|
*/
|
||||||
|
let braceCounter = 0;
|
||||||
|
let inContainer = -1;
|
||||||
|
do {
|
||||||
|
// istanbul ignore if
|
||||||
|
if (lineNumber > lines.length - 1) {
|
||||||
|
logger.debug(`Malformed Terraform file detected.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = lines[lineNumber];
|
||||||
|
|
||||||
|
// istanbul ignore else
|
||||||
|
if (is.string(line)) {
|
||||||
|
// `{` will be counted with +1 and `}` with -1. Therefore if we reach braceCounter == 0. We have found the end of the terraform block
|
||||||
|
const openBrackets = (line.match(regEx(/\{/g)) || []).length;
|
||||||
|
const closedBrackets = (line.match(regEx(/\}/g)) || []).length;
|
||||||
|
braceCounter = braceCounter + openBrackets - closedBrackets;
|
||||||
|
|
||||||
|
if (line.match(regEx(/^\s*(?:init_)?container(?:\s*\{|$)/s))) {
|
||||||
|
inContainer = braceCounter;
|
||||||
|
} else if (braceCounter < inContainer) {
|
||||||
|
inContainer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const managerData: ResourceManagerData = {
|
||||||
|
terraformDependencyType: TerraformDependencyTypes.resource,
|
||||||
|
resourceType,
|
||||||
|
};
|
||||||
|
const dep: PackageDependency<ResourceManagerData> = {
|
||||||
|
managerData,
|
||||||
|
};
|
||||||
|
|
||||||
|
const kvMatch = keyValueExtractionRegex.exec(line);
|
||||||
|
if (kvMatch?.groups && inContainer > 0) {
|
||||||
|
switch (kvMatch.groups.key) {
|
||||||
|
case 'image':
|
||||||
|
managerData[kvMatch.groups.key] = kvMatch.groups.value;
|
||||||
|
managerData.sourceLine = lineNumber;
|
||||||
|
deps.push(dep);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* istanbul ignore next */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// stop - something went wrong
|
||||||
|
braceCounter = 0;
|
||||||
|
inContainer = -1;
|
||||||
|
}
|
||||||
|
lineNumber += 1;
|
||||||
|
} while (braceCounter !== 0);
|
||||||
|
|
||||||
|
// remove last lineNumber addition to not skip a line after the last bracket
|
||||||
|
lineNumber -= 1;
|
||||||
|
return { lineNumber, dependencies: deps };
|
||||||
|
}
|
|
@ -3,8 +3,8 @@ import { fs, loadFixture, mocked } from '../../../../../test/util';
|
||||||
import { GlobalConfig } from '../../../../config/global';
|
import { GlobalConfig } from '../../../../config/global';
|
||||||
import { getPkgReleases } from '../../../datasource';
|
import { getPkgReleases } from '../../../datasource';
|
||||||
import type { UpdateArtifactsConfig } from '../../types';
|
import type { UpdateArtifactsConfig } from '../../types';
|
||||||
|
import { updateArtifacts } from '../index';
|
||||||
import { TerraformProviderHash } from './hash';
|
import { TerraformProviderHash } from './hash';
|
||||||
import { updateArtifacts } from './index';
|
|
||||||
|
|
||||||
// auto-mock fs
|
// auto-mock fs
|
||||||
jest.mock('../../../../util/fs');
|
jest.mock('../../../../util/fs');
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { HelmDatasource } from '../../datasource/helm';
|
||||||
import { getDep } from '../dockerfile/extract';
|
import { getDep } from '../dockerfile/extract';
|
||||||
import type { PackageDependency } from '../types';
|
import type { PackageDependency } from '../types';
|
||||||
import { TerraformDependencyTypes, TerraformResourceTypes } from './common';
|
import { TerraformDependencyTypes, TerraformResourceTypes } from './common';
|
||||||
|
import { extractTerraformKubernetesResource } from './extract/kubernetes';
|
||||||
import { analyseTerraformVersion } from './required-version';
|
import { analyseTerraformVersion } from './required-version';
|
||||||
import type { ExtractionResult, ResourceManagerData } from './types';
|
import type { ExtractionResult, ResourceManagerData } from './types';
|
||||||
import {
|
import {
|
||||||
|
@ -46,6 +47,14 @@ export function extractTerraformResource(
|
||||||
return TerraformResourceTypes[key].includes(resourceType);
|
return TerraformResourceTypes[key].includes(resourceType);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isKnownType && resourceType.startsWith('kubernetes_')) {
|
||||||
|
return extractTerraformKubernetesResource(
|
||||||
|
startingLine,
|
||||||
|
lines,
|
||||||
|
resourceType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
managerData.resourceType = isKnownType
|
managerData.resourceType = isKnownType
|
||||||
? resourceType
|
? resourceType
|
||||||
: TerraformResourceTypes.unknown[0];
|
: TerraformResourceTypes.unknown[0];
|
||||||
|
|
Loading…
Reference in a new issue