Skip to content

Commit

Permalink
feat(terraform-provider): Implement terraform helm chart update (#6631)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
  • Loading branch information
secustor and viceice committed Jul 2, 2020
1 parent 3f2c989 commit f3d920c
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 2 deletions.
40 changes: 40 additions & 0 deletions lib/manager/terraform/__fixtures__/helm.tf
@@ -0,0 +1,40 @@
# legit use cases
## complete example
resource "helm_release" "example" {
name = "my-redis-release"
repository = "https://kubernetes-charts.storage.googleapis.com"
chart = "redis"
version = "1.0.1"
}

## example without version, this will default to latest in Terraform
resource "helm_release" "example" {
name = "my-redis-release"
repository = "https://kubernetes-charts.storage.googleapis.com"
chart = "redis"
}

## local chart
resource "helm_release" "local" {
name = "my-local-chart"
chart = "./charts/example"
}

## malformed examples
resource "helm_release" "example" {
name = "my-redis-release"
repository = "https://kubernetes-charts.storage.googleapis.com"
version = "4.0.1"
}

resource "helm_release" "example" {
repository = "https://kubernetes-charts.storage.googleapis.com"
chart = "redis"
version = "5.0.1"
}

resource "helm_release" "example" {
name = "my-redis-release"
chart = "redis"
version = "6.0.1"
}
68 changes: 68 additions & 0 deletions lib/manager/terraform/__snapshots__/extract.spec.ts.snap
@@ -1,5 +1,73 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`lib/manager/terraform/extract extractPackageFile() extract helm releases 1`] = `
Object {
"deps": Array [
Object {
"currentValue": "1.0.1",
"datasource": "helm",
"depName": "redis",
"depNameShort": "redis",
"depType": "helm",
"registryUrls": Array [
"https://kubernetes-charts.storage.googleapis.com",
],
},
Object {
"datasource": "helm",
"depName": "redis",
"depNameShort": "redis",
"depType": "helm",
"registryUrls": Array [
"https://kubernetes-charts.storage.googleapis.com",
],
"skipReason": "unsupported-version",
},
Object {
"datasource": "helm",
"depName": "./charts/example",
"depNameShort": "./charts/example",
"depType": "helm",
"registryUrls": Array [
undefined,
],
"skipReason": "local-chart",
},
Object {
"currentValue": "4.0.1",
"datasource": "helm",
"depName": undefined,
"depNameShort": undefined,
"depType": "helm",
"registryUrls": Array [
"https://kubernetes-charts.storage.googleapis.com",
],
"skipReason": "invalid-name",
},
Object {
"currentValue": "5.0.1",
"datasource": "helm",
"depName": "redis",
"depNameShort": "redis",
"depType": "helm",
"registryUrls": Array [
"https://kubernetes-charts.storage.googleapis.com",
],
},
Object {
"currentValue": "6.0.1",
"datasource": "helm",
"depName": "redis",
"depNameShort": "redis",
"depType": "helm",
"registryUrls": Array [
undefined,
],
},
],
}
`;

exports[`lib/manager/terraform/extract extractPackageFile() extracts 1`] = `
Object {
"deps": Array [
Expand Down
7 changes: 7 additions & 0 deletions lib/manager/terraform/extract.spec.ts
Expand Up @@ -6,6 +6,7 @@ const tf2 = `module "relative" {
source = "../../modules/fe"
}
`;
const helm = readFileSync('lib/manager/terraform/__fixtures__/helm.tf', 'utf8');

describe('lib/manager/terraform/extract', () => {
describe('extractPackageFile()', () => {
Expand All @@ -21,5 +22,11 @@ describe('lib/manager/terraform/extract', () => {
it('returns null if only local deps', () => {
expect(extractPackageFile(tf2)).toBeNull();
});
it('extract helm releases', () => {
const res = extractPackageFile(helm);
expect(res).toMatchSnapshot();
expect(res.deps).toHaveLength(6);
expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(3);
});
});
});
20 changes: 18 additions & 2 deletions lib/manager/terraform/extract.ts
Expand Up @@ -6,14 +6,23 @@ import {
extractTerraformProvider,
} from './providers';
import { extractTerraformRequiredProviders } from './required_providers';
import {
analyseTerraformResource,
extractTerraformResource,
} from './resources';
import {
TerraformDependencyTypes,
checkFileContainsDependency,
getTerraformDependencyType,
} from './util';

const dependencyBlockExtractionRegex = /^\s*(?<type>module|provider|required_providers)\s+("(?<lookupName>[^"]+)"\s+)?{\s*$/;
const contentCheckList = ['module "', 'provider "', 'required_providers '];
const dependencyBlockExtractionRegex = /^\s*(?<type>[a-z_]+)\s+("(?<lookupName>[^"]+)"\s+)?("(?<terraformName>[^"]+)"\s+)?{\s*$/;
const contentCheckList = [
'module "',
'provider "',
'required_providers ',
' "helm_release" ',
];

export function extractPackageFile(content: string): PackageFile | null {
logger.trace({ content }, 'terraform.extractPackageFile()');
Expand Down Expand Up @@ -55,6 +64,10 @@ export function extractPackageFile(content: string): PackageFile | null {
);
break;
}
case TerraformDependencyTypes.resource: {
result = extractTerraformResource(lineNumber, lines);
break;
}
/* istanbul ignore next */
default:
logger.warn(
Expand All @@ -81,6 +94,9 @@ export function extractPackageFile(content: string): PackageFile | null {
case TerraformDependencyTypes.module:
analyseTerraformModule(dep);
break;
case TerraformDependencyTypes.resource:
analyseTerraformResource(dep);
break;
/* istanbul ignore next */
default:
}
Expand Down
58 changes: 58 additions & 0 deletions lib/manager/terraform/resources.ts
@@ -0,0 +1,58 @@
import * as datasourceHelm from '../../datasource/helm';
import { SkipReason } from '../../types';
import { isValid } from '../../versioning/hashicorp';
import { PackageDependency } from '../common';
import {
ExtractionResult,
TerraformDependencyTypes,
checkIfStringIsPath,
keyValueExtractionRegex,
} from './util';

export function extractTerraformResource(
startingLine: number,
lines: string[]
): ExtractionResult {
let lineNumber = startingLine;
let line;
const deps: PackageDependency[] = [];
const dep: PackageDependency = {
managerData: {
terraformDependencyType: TerraformDependencyTypes.resource,
},
};

do {
lineNumber += 1;
line = lines[lineNumber];
const kvMatch = keyValueExtractionRegex.exec(line);
if (kvMatch) {
if (kvMatch.groups.key === 'version') {
dep.currentValue = kvMatch.groups.value;
} else if (kvMatch.groups.key === 'chart') {
dep.managerData.chart = kvMatch.groups.value;
} else if (kvMatch.groups.key === 'repository') {
dep.managerData.repository = kvMatch.groups.value;
}
}
} while (line.trim() !== '}');
deps.push(dep);
return { lineNumber, dependencies: deps };
}

export function analyseTerraformResource(dep: PackageDependency): void {
/* eslint-disable no-param-reassign */
if (dep.managerData.chart == null) {
dep.skipReason = SkipReason.InvalidName;
} else if (checkIfStringIsPath(dep.managerData.chart)) {
dep.skipReason = SkipReason.LocalChart;
} else if (!isValid(dep.currentValue)) {
dep.skipReason = SkipReason.UnsupportedVersion;
}
dep.depType = 'helm';
dep.registryUrls = [dep.managerData.repository];
dep.depName = dep.managerData.chart;
dep.depNameShort = dep.managerData.chart;
dep.datasource = datasourceHelm.id;
/* eslint-enable no-param-reassign */
}
10 changes: 10 additions & 0 deletions lib/manager/terraform/util.ts
Expand Up @@ -12,6 +12,7 @@ export enum TerraformDependencyTypes {
module = 'module',
provider = 'provider',
required_providers = 'required_providers',
resource = 'resource',
}

export function getTerraformDependencyType(
Expand All @@ -27,6 +28,9 @@ export function getTerraformDependencyType(
case 'required_providers': {
return TerraformDependencyTypes.required_providers;
}
case 'resource': {
return TerraformDependencyTypes.resource;
}
default: {
return TerraformDependencyTypes.unknown;
}
Expand All @@ -41,3 +45,9 @@ export function checkFileContainsDependency(
return content.includes(check);
});
}

const pathStringRegex = /(.|..)?(\/[^/])+/;
export function checkIfStringIsPath(path: string): boolean {
const match = pathStringRegex.exec(path);
return !!match;
}

0 comments on commit f3d920c

Please sign in to comment.