From 32719c21e1247c90233f32be9610631a38a52d93 Mon Sep 17 00:00:00 2001 From: David Mattia <8922077+dmattia@users.noreply.github.com> Date: Wed, 8 Jul 2020 00:37:18 -0500 Subject: [PATCH] Fix bug with --ignore-parent-terragrunt (#37) Co-authored-by: dmattia --- Makefile | 2 +- cmd/generate.go | 26 +++++---- cmd/generate_test.go | 11 ++++ cmd/golden/invalid_parent_module.yaml | 11 ++++ cmd/parse_hcl.go | 48 ++++++++++++++++ go.mod | 1 + main.go | 2 +- .../invalid_parent_module/child/account.hcl | 5 ++ .../child/deep/terragrunt.hcl | 11 ++++ .../invalid_parent_module/child/env.hcl | 3 + .../invalid_parent_module/child/region.hcl | 3 + .../invalid_parent_module/terragrunt.hcl | 56 +++++++++++++++++++ test_examples/with_parent/terragrunt.hcl | 3 + 13 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 cmd/golden/invalid_parent_module.yaml create mode 100644 cmd/parse_hcl.go create mode 100644 test_examples/invalid_parent_module/child/account.hcl create mode 100644 test_examples/invalid_parent_module/child/deep/terragrunt.hcl create mode 100644 test_examples/invalid_parent_module/child/env.hcl create mode 100644 test_examples/invalid_parent_module/child/region.hcl create mode 100644 test_examples/invalid_parent_module/terragrunt.hcl diff --git a/Makefile b/Makefile index 7cddee58..cd69960b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION=0.4.5 +VERSION=0.5.0 PATH_BUILD=build/ FILE_COMMAND=terragrunt-atlantis-config FILE_ARCH=darwin_amd64 diff --git a/cmd/generate.go b/cmd/generate.go index 01121d2d..c4fec46f 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -87,12 +87,6 @@ func makePathAbsolute(path string, parentPath string) string { // Parses the terragrunt config at to find all modules it depends on func getDependencies(path string) ([]string, error) { - decodeTypes := []config.PartialDecodeSectionType{ - config.DependencyBlock, - config.DependenciesBlock, - config.TerraformBlock, - } - options, err := options.NewTerragruntOptions(path) if err != nil { return nil, err @@ -100,17 +94,27 @@ func getDependencies(path string) ([]string, error) { options.RunTerragrunt = cli.RunTerragrunt options.Env = getEnvs() - parsedConfig, err := config.PartialParseConfigFile(path, options, nil, decodeTypes) + // if theres no terraform source and we're ignoring parent terragrunt configs + // return nils to indicate we should skip this project + isParent, err := isParentModule(path, options) if err != nil { return nil, err } - - // if theres no terraform source and we're ignoring parent terragrunt configs - // return nils to indicate we should skip this project - if (parsedConfig.Terraform == nil || parsedConfig.Terraform.Source == nil) && ignoreParentTerragrunt == true { + if ignoreParentTerragrunt && isParent { return nil, nil } + decodeTypes := []config.PartialDecodeSectionType{ + config.DependencyBlock, + config.DependenciesBlock, + config.TerraformBlock, + } + + parsedConfig, err := config.PartialParseConfigFile(path, options, nil, decodeTypes) + if err != nil { + return nil, err + } + dependencies, err := parseLocalDependencies(path) if err != nil { return nil, err diff --git a/cmd/generate_test.go b/cmd/generate_test.go index a8944323..7619effb 100644 --- a/cmd/generate_test.go +++ b/cmd/generate_test.go @@ -143,3 +143,14 @@ func TestTerragruntDependencies(t *testing.T) { filepath.Join("..", "test_examples", "terragrunt_dependency"), }) } + +// This test covers parent Terragrunt files that are not runnable as modules themselves. +// Sometimes it is possible to have parent files that only are runnable when included +// into child modules. +func TestUnparseableParent(t *testing.T) { + runTest(t, filepath.Join("golden", "invalid_parent_module.yaml"), []string{ + "--root", + filepath.Join("..", "test_examples", "invalid_parent_module"), + "--ignore-parent-terragrunt", + }) +} diff --git a/cmd/golden/invalid_parent_module.yaml b/cmd/golden/invalid_parent_module.yaml new file mode 100644 index 00000000..91e77001 --- /dev/null +++ b/cmd/golden/invalid_parent_module.yaml @@ -0,0 +1,11 @@ +automerge: false +parallel_apply: true +parallel_plan: true +projects: +- autoplan: + enabled: false + when_modified: + - '*.hcl' + - '*.tf*' + dir: child/deep +version: 3 diff --git a/cmd/parse_hcl.go b/cmd/parse_hcl.go new file mode 100644 index 00000000..e08349d5 --- /dev/null +++ b/cmd/parse_hcl.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "github.com/gruntwork-io/terragrunt/config" + "github.com/gruntwork-io/terragrunt/options" + "github.com/gruntwork-io/terragrunt/util" + "github.com/hashicorp/hcl/v2/gohcl" + "github.com/hashicorp/hcl/v2/hclparse" + "github.com/zclconf/go-cty/cty/function" +) + +type parsedHcl struct { + Terraform *terraformConfig `hcl:"terraform,block"` +} + +type terraformConfig struct { + Source *string `hcl:"source,attr"` +} + +func isParentModule(path string, terragruntOptions *options.TerragruntOptions) (bool, error) { + configString, err := util.ReadFileAsString(path) + if err != nil { + return false, err + } + + parser := hclparse.NewParser() + file, err := parseHcl(parser, configString, path) + if err != nil { + return false, err + } + + extensions := config.EvalContextExtensions{} + evalContext := config.CreateTerragruntEvalContext(path, terragruntOptions, extensions) + + // Mock all the functions out so they don't do anything. Otherwise they may throw errors that we don't care about + evalContext.Functions = map[string]function.Function{} + + // We don't need to check the errors/diagnostics coming from `DecodeBody`, as when errors come up, + // it will leave the partially parsed result in the output object. + var parsed parsedHcl + gohcl.DecodeBody(file.Body, evalContext, &parsed) + + if parsed.Terraform == nil || parsed.Terraform.Source == nil { + return true, nil + } + + return false, nil +} diff --git a/go.mod b/go.mod index 6318ec1d..fbdf92bb 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/hashicorp/go-multierror v1.1.0 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/go-version v1.2.1 // indirect + github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcl/v2 v2.6.0 github.com/hashicorp/hcl2 v0.0.0-20191002203319-fb75b3253c80 github.com/hashicorp/terraform v0.12.28 // indirect diff --git a/main.go b/main.go index 687e18bb..ca70d028 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import "github.com/transcend-io/terragrunt-atlantis-config/cmd" var ( - VERSION = "0.4.4" + VERSION = "0.5.0" ) func main() { diff --git a/test_examples/invalid_parent_module/child/account.hcl b/test_examples/invalid_parent_module/child/account.hcl new file mode 100644 index 00000000..aa39bba0 --- /dev/null +++ b/test_examples/invalid_parent_module/child/account.hcl @@ -0,0 +1,5 @@ +locals { + account_name = "prod" + aws_account_id = "000000000" + aws_profile = "prod" +} \ No newline at end of file diff --git a/test_examples/invalid_parent_module/child/deep/terragrunt.hcl b/test_examples/invalid_parent_module/child/deep/terragrunt.hcl new file mode 100644 index 00000000..f0c9b4a5 --- /dev/null +++ b/test_examples/invalid_parent_module/child/deep/terragrunt.hcl @@ -0,0 +1,11 @@ +include { + path = find_in_parent_folders() +} + +terraform { + source = "git::git@github.com:transcend-io/terraform-aws-fargate-container?ref=v0.0.4" +} + +inputs = { + foo = "bar" +} \ No newline at end of file diff --git a/test_examples/invalid_parent_module/child/env.hcl b/test_examples/invalid_parent_module/child/env.hcl new file mode 100644 index 00000000..9a361201 --- /dev/null +++ b/test_examples/invalid_parent_module/child/env.hcl @@ -0,0 +1,3 @@ +locals { + environment = "prod" +} \ No newline at end of file diff --git a/test_examples/invalid_parent_module/child/region.hcl b/test_examples/invalid_parent_module/child/region.hcl new file mode 100644 index 00000000..ca482204 --- /dev/null +++ b/test_examples/invalid_parent_module/child/region.hcl @@ -0,0 +1,3 @@ +locals { + aws_region = "eu-west-1" +} \ No newline at end of file diff --git a/test_examples/invalid_parent_module/terragrunt.hcl b/test_examples/invalid_parent_module/terragrunt.hcl new file mode 100644 index 00000000..c1008884 --- /dev/null +++ b/test_examples/invalid_parent_module/terragrunt.hcl @@ -0,0 +1,56 @@ +###################################################################################################################### +# This file (and test directory) is a fork of https://github.com/gruntwork-io/terragrunt-infrastructure-live-example # +###################################################################################################################### + +locals { + account_vars = read_terragrunt_config(find_in_parent_folders("account.hcl")) + region_vars = read_terragrunt_config(find_in_parent_folders("region.hcl")) + environment_vars = read_terragrunt_config(find_in_parent_folders("env.hcl")) + account_name = local.account_vars.locals.account_name + account_id = local.account_vars.locals.aws_account_id + aws_region = local.region_vars.locals.aws_region +} + +# Generate an AWS provider block +generate "provider" { + path = "provider.tf" + if_exists = "overwrite_terragrunt" + contents = <