Skip to content

Commit

Permalink
Add back in debug mode flag and ensure autogenerated file is removed
Browse files Browse the repository at this point in the history
  • Loading branch information
yorinasub17 committed Aug 1, 2020
1 parent c7c4b71 commit 150b34b
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 10 deletions.
20 changes: 20 additions & 0 deletions cli/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ func parseTerragruntOptionsFromArgs(terragruntVersion string, args []string, wri

strictInclude := parseBooleanArg(args, OPT_TERRAGRUNT_STRICT_INCLUDE, false)

debugMode := parseBooleanArg(args, OPT_TERRAGRUNT_DEBUG, false)

opts, err := options.NewTerragruntOptions(filepath.ToSlash(terragruntConfigPath))
if err != nil {
return nil, err
Expand Down Expand Up @@ -162,6 +164,7 @@ func parseTerragruntOptionsFromArgs(terragruntVersion string, args []string, wri
opts.ExcludeDirs = excludeDirs
opts.IncludeDirs = includeDirs
opts.StrictInclude = strictInclude
opts.DebugMode = debugMode
opts.Parallelism = parallelism
opts.Check = parseBooleanArg(args, OPT_TERRAGRUNT_CHECK, os.Getenv("TERRAGRUNT_CHECK") == "true")
opts.HclFile = filepath.ToSlash(terragruntHclFilePath)
Expand Down Expand Up @@ -350,6 +353,22 @@ func parseMultiStringArg(args []string, argName string, defaultValue []string) (
return stringArgs, nil
}

// deleteTFVarsFile will delete the autogenerated tfvars file from disk, unless in debug mode. This should be done at
// the end of each terragrunt call, to prevent unintended leakage of secrets from the filesystem.
func deleteTFVarsFile(terragruntOptions *options.TerragruntOptions, terragruntConfig *config.TerragruntConfig) error {
if terragruntOptions.DebugMode {
terragruntOptions.Logger.Printf("Detected DEBUG mode: will skip removing tfvars file %s in working dir (%s)", TerragruntTFVarsFileName, terragruntOptions.WorkingDir)
return nil
}

terragruntOptions.Logger.Printf("Removing tfvars file %s in working dir (%s)", TerragruntTFVarsFileName, terragruntOptions.WorkingDir)
fileName := filepath.Join(terragruntOptions.WorkingDir, TerragruntTFVarsFileName)
if util.FileExists(fileName) {
return os.Remove(fileName)
}
return nil
}

// writeTFVarsFile will create a tfvars file that can be used to invoke the terraform module with the inputs generated
// in terragrunt.
func writeTFVarsFile(terragruntOptions *options.TerragruntOptions, terragruntConfig *config.TerragruntConfig) error {
Expand All @@ -372,6 +391,7 @@ func writeTFVarsFile(terragruntOptions *options.TerragruntOptions, terragruntCon
// If the file already exists, log a warning indicating that we will overwrite it.
if util.FileExists(fileName) {
util.Debugf(
terragruntOptions.Logger,
"WARNING: File with name \"%s\" already exists in terraform working directory. This file will be replaced with terragrunt generated vars",
TerragruntTFVarsFileName,
)
Expand Down
4 changes: 4 additions & 0 deletions cli/cli_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const OPT_TERRAGRUNT_STRICT_INCLUDE = "terragrunt-strict-include"
const OPT_TERRAGRUNT_PARALLELISM = "terragrunt-parallelism"
const OPT_TERRAGRUNT_CHECK = "terragrunt-check"
const OPT_TERRAGRUNT_HCLFMT_FILE = "terragrunt-hclfmt-file"
const OPT_TERRAGRUNT_DEBUG = "terragrunt-debug"

var ALL_TERRAGRUNT_BOOLEAN_OPTS = []string{
OPT_NON_INTERACTIVE,
Expand All @@ -54,6 +55,7 @@ var ALL_TERRAGRUNT_BOOLEAN_OPTS = []string{
OPT_TERRAGRUNT_NO_AUTO_RETRY,
OPT_TERRAGRUNT_CHECK,
OPT_TERRAGRUNT_STRICT_INCLUDE,
OPT_TERRAGRUNT_DEBUG,
}
var ALL_TERRAGRUNT_STRING_OPTS = []string{
OPT_TERRAGRUNT_CONFIG,
Expand Down Expand Up @@ -172,6 +174,7 @@ GLOBAL OPTIONS:
terragrunt-parallelism <N> *-all commands parallelism set to at most N modules
terragrunt-exclude-dir Unix-style glob of directories to exclude when running *-all commands
terragrunt-include-dir Unix-style glob of directories to include when running *-all commands
terragrunt-debug Enable debug mode: keep the tfvars file that is generated instead of cleaning it up
terragrunt-check Enable check mode in the hclfmt command.
terragrunt-hclfmt-file The path to a single terragrunt.hcl file that the hclfmt command should run on.
Expand Down Expand Up @@ -370,6 +373,7 @@ func RunTerragrunt(terragruntOptions *options.TerragruntOptions) error {

// Generate the tfvars file here, after all the terragrunt generated terraform files are created, so that the module
// variables check includes variables defined in `generate` blocks.
defer deleteTFVarsFile(terragruntOptions, terragruntConfig)
if err := writeTFVarsFile(terragruntOptions, terragruntConfig); err != nil {
return err
}
Expand Down
15 changes: 10 additions & 5 deletions docs/_docs/02_features/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ Terragrunt and Terraform usually play well together in helping you
write DRY, re-usable infrastructure. But how do we figure out what
went wrong in the rare case that they _don't_ play well?

Whenever you run a Terragrunt command, two things happen:
Whenever you run a Terragrunt command, it will convert the inputs into [a tfvars json
file](https://www.terraform.io/docs/configuration/variables.html#variable-definitions-tfvars-files) named
`terragrunt-generated.auto.tfvars.json`. This file will be autoloaded by terraform when it is invoked. However, normally
this file is cleaned up at the end of each execution, which makes it hard to understand what inputs were passed into
terraform.

- Terragrunt will convert the inputs into [a tfvars json
file](https://www.terraform.io/docs/configuration/variables.html#variable-definitions-tfvars-files) named
`terragrunt-generated.auto.tfvars.json`. This file will be autoloaded by terraform when it is invoked.
To help with debugging, Terragrunt offers a CLI flag `--terragrunt-debug` which can be used to run in debug mode.
Whenever you run a Terragrunt command in debug mode, two things happen:

- Terragrunt will keep around the generated `terragrunt-generated.auto.tfvars.json` file.
- Print instructions on how to invoke terraform against the generated file to reproduce exactly the same terraform
output as you saw when invoking `terragrunt`. This will help you to determine where the problem's root cause lies.

Expand Down Expand Up @@ -88,7 +93,7 @@ You perform a `terragrunt apply`, and find that `outputs.task_ids` has 7
elements, but you know that the cluster only has 4 VMs in it! What's happening?
Let's figure it out. Run this:

$ terragrunt apply
$ terragrunt apply --terragrunt-debug

After applying, you will see this output on standard error

Expand Down
2 changes: 2 additions & 0 deletions docs/_docs/02_features/inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Note that Terragrunt will respect any `TF_VAR_xxx` variables you’ve manually s
}
}

Since these inputs may include unencrypted secrets, Terragrunt will clean up this file at the end of each terraform
call. To keep this file around even after terragrunt exits, pass in the `--terragrunt-debug` CLI arg.

### Variable precedence

Expand Down
8 changes: 8 additions & 0 deletions docs/_docs/04_reference/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Terragrunt forwards all arguments and options to Terraform. The only exceptions
- [terragrunt-ignore-dependency-order](#terragrunt-ignore-dependency-order)
- [terragrunt-ignore-external-dependencies](#terragrunt-ignore-external-dependencies)
- [terragrunt-include-external-dependencies](#terragrunt-include-external-dependencies)
- [terragrunt-debug](#terragrunt-debug)
- [terragrunt-check](#terragrunt-check)
- [terragrunt-hclfmt-file](#terragrunt-hclfmt-file)

Expand Down Expand Up @@ -208,6 +209,13 @@ dependency is a dependency that is outside the current terragrunt working direct
included directories with `terragrunt-include-dir`.


## terragrunt-debug

**CLI Arg**: `--terragrunt-debug`

When passed in, run in terragrunt in debug mode, where terragrunt will keep around autogenerated tfvars file instead of
cleaning them up at the end of each run.


## terragrunt-check

Expand Down
3 changes: 3 additions & 0 deletions options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ type TerragruntOptions struct {
// If set to true, do not include dependencies when processing IncludeDirs (unless they are in the included dirs)
StrictInclude bool

// If set to true, don't clean up the tfvars json file used to pass inputs to terraform.
DebugMode bool

This comment has been minimized.

Copy link
@brikis98

brikis98 Aug 1, 2020

Member

Add it to Clone method?


// Parallelism limits the number of commands to run concurrently during *-all commands
Parallelism int

Expand Down
26 changes: 21 additions & 5 deletions test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1459,7 +1459,7 @@ func TestGeneratedInputsExternalEnvVar(t *testing.T) {
tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_INPUTS)
rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_INPUTS)

runTerragrunt(t, fmt.Sprintf("terragrunt apply --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath))
runTerragrunt(t, fmt.Sprintf("terragrunt apply --terragrunt-non-interactive --terragrunt-debug --terragrunt-working-dir %s", rootPath))

pathFromRoot, err := util.PathInDirectory(cli.TerragruntTFVarsFileName, rootPath)
assert.NoError(t, err)
Expand All @@ -1472,7 +1472,7 @@ func TestGeneratedInputsExternalEnvVar(t *testing.T) {
stderr := bytes.Buffer{}
require.NoError(
t,
runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr),
runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-debug --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr),
)

outputs := map[string]TerraformOutput{}
Expand All @@ -1494,14 +1494,15 @@ func TestGeneratedInputsExternalEnvVar(t *testing.T) {

// Finally, verify that unsetting the env var will reconstruct the json file with the var included
os.Unsetenv("TF_VAR_string")
runTerragrunt(t, fmt.Sprintf("terragrunt apply --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath))
runTerragrunt(t, fmt.Sprintf("terragrunt apply --terragrunt-non-interactive --terragrunt-debug --terragrunt-working-dir %s", rootPath))
getOutputAndVerifyInputs(validateInputs)
newTfvarsJsonContents, err := ioutil.ReadFile(tfvarsPath)
require.NoError(t, err)
require.NoError(t, json.Unmarshal(newTfvarsJsonContents, &data))
assert.Equal(t, data["string"], "string")
}
func TestGeneratedInputs(t *testing.T) {

func TestGeneratedInputsFileDiscarded(t *testing.T) {
t.Parallel()

cleanupTerraformFolder(t, TEST_FIXTURE_INPUTS)
Expand All @@ -1510,6 +1511,21 @@ func TestGeneratedInputs(t *testing.T) {

runTerragrunt(t, fmt.Sprintf("terragrunt plan --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath))

// Assert that the tfvars file was deleted.
pathFromRoot, err := util.PathInDirectory(cli.TerragruntTFVarsFileName, rootPath)
assert.NoError(t, err)
assert.Equal(t, "", pathFromRoot)
}

func TestGeneratedInputs(t *testing.T) {
t.Parallel()

cleanupTerraformFolder(t, TEST_FIXTURE_INPUTS)
tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_INPUTS)
rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_INPUTS)

runTerragrunt(t, fmt.Sprintf("terragrunt plan --terragrunt-non-interactive --terragrunt-debug --terragrunt-working-dir %s", rootPath))

pathFromRoot, err := util.PathInDirectory(cli.TerragruntTFVarsFileName, rootPath)
assert.NoError(t, err)
assert.NotEqual(t, "", pathFromRoot)
Expand All @@ -1530,7 +1546,7 @@ func TestGeneratedInputs(t *testing.T) {
stderr := bytes.Buffer{}
require.NoError(
t,
runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr),
runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-debug --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr),
)

outputs := map[string]TerraformOutput{}
Expand Down

0 comments on commit 150b34b

Please sign in to comment.