mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-13 15:36:25 +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"
|
||||
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 () => {
|
||||
const res = await extractPackageFile(kubernetes, 'kubernetes.tf', {});
|
||||
expect(res.deps).toHaveLength(16);
|
||||
expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(2);
|
||||
expect(res.deps).toHaveLength(18);
|
||||
expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(1);
|
||||
expect(res.deps).toMatchObject([
|
||||
{
|
||||
depName: 'gcr.io/kaniko-project/executor',
|
||||
|
@ -117,6 +117,11 @@ describe('modules/manager/terraform/extract', () => {
|
|||
'sha256:8504bde9a9a8c9c4e9a4fe659703d265697a36ff13607b7669a4caa4407baa52',
|
||||
depType: 'kubernetes_cron_job_v1',
|
||||
},
|
||||
{
|
||||
depName: 'node',
|
||||
currentValue: '14',
|
||||
depType: 'kubernetes_cron_job_v1',
|
||||
},
|
||||
{
|
||||
depName: 'gcr.io/kaniko-project/executor',
|
||||
currentValue: 'v1.8.0',
|
||||
|
@ -149,7 +154,6 @@ describe('modules/manager/terraform/extract', () => {
|
|||
currentValue: '1.21.5',
|
||||
depType: 'kubernetes_job',
|
||||
},
|
||||
{ skipReason: 'invalid-dependency-specification' },
|
||||
{ skipReason: 'invalid-value' },
|
||||
{
|
||||
depName: 'nginx',
|
||||
|
@ -176,11 +180,21 @@ describe('modules/manager/terraform/extract', () => {
|
|||
currentValue: '1.21.10',
|
||||
depType: 'kubernetes_replication_controller_v1',
|
||||
},
|
||||
{
|
||||
depName: 'nginx',
|
||||
currentValue: '1.21.11',
|
||||
depType: 'kubernetes_stateful_set',
|
||||
},
|
||||
{
|
||||
depName: 'prom/prometheus',
|
||||
currentValue: 'v2.2.1',
|
||||
depType: 'kubernetes_stateful_set',
|
||||
},
|
||||
{
|
||||
depName: 'nginx',
|
||||
currentValue: '1.21.12',
|
||||
depType: 'kubernetes_stateful_set_v1',
|
||||
},
|
||||
{
|
||||
depName: 'prom/prometheus',
|
||||
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 { getPkgReleases } from '../../../datasource';
|
||||
import type { UpdateArtifactsConfig } from '../../types';
|
||||
import { updateArtifacts } from '../index';
|
||||
import { TerraformProviderHash } from './hash';
|
||||
import { updateArtifacts } from './index';
|
||||
|
||||
// auto-mock fs
|
||||
jest.mock('../../../../util/fs');
|
||||
|
|
|
@ -5,6 +5,7 @@ import { HelmDatasource } from '../../datasource/helm';
|
|||
import { getDep } from '../dockerfile/extract';
|
||||
import type { PackageDependency } from '../types';
|
||||
import { TerraformDependencyTypes, TerraformResourceTypes } from './common';
|
||||
import { extractTerraformKubernetesResource } from './extract/kubernetes';
|
||||
import { analyseTerraformVersion } from './required-version';
|
||||
import type { ExtractionResult, ResourceManagerData } from './types';
|
||||
import {
|
||||
|
@ -46,6 +47,14 @@ export function extractTerraformResource(
|
|||
return TerraformResourceTypes[key].includes(resourceType);
|
||||
});
|
||||
|
||||
if (isKnownType && resourceType.startsWith('kubernetes_')) {
|
||||
return extractTerraformKubernetesResource(
|
||||
startingLine,
|
||||
lines,
|
||||
resourceType
|
||||
);
|
||||
}
|
||||
|
||||
managerData.resourceType = isKnownType
|
||||
? resourceType
|
||||
: TerraformResourceTypes.unknown[0];
|
||||
|
|
Loading…
Reference in a new issue