Skip to content

Commit c583606

Browse files
authored
Improve opa logging (#1011)
* Improve opa logging * Fix examples rendering in test * Remove residual comment from previous implementation * Make rerun the default
1 parent a0c867c commit c583606

File tree

5 files changed

+33
-7
lines changed

5 files changed

+33
-7
lines changed

docs/_data/examples.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@
113113
name: OPA Terraform Example
114114
image: /assets/img/logos/opa-logo.png
115115
files:
116-
- url: /examples/terraform-opa-example/pass/main.tf
116+
- url: /examples/terraform-opa-example/pass/main_pass.tf
117117
id: pass_terraform_main_code
118-
- url: /examples/terraform-opa-example/fail/main.tf
118+
- url: /examples/terraform-opa-example/fail/main_fail.tf
119119
id: fail_terraform_main_code
120120
- url: /examples/terraform-opa-example/policy/enforce_source.rego
121121
id: policy_main_code

modules/opa/eval.go

+30-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package opa
22

33
import (
4+
"path/filepath"
5+
"strings"
46
"sync"
57

68
"github.com/gruntwork-io/terratest/modules/logger"
@@ -26,6 +28,11 @@ type EvalOptions struct {
2628

2729
// When true, keep any temp files and folders that are created for the purpose of running opa eval.
2830
DebugKeepTempFiles bool
31+
32+
// When true, disable the functionality where terratest reruns the opa check on the same file and query all elements
33+
// on error. By default, terratest will rerun the opa eval call with `data` query so you can see all the contents
34+
// evaluated.
35+
DebugDisableQueryDataOnError bool
2936
}
3037

3138
// FailMode signals whether `opa eval` should fail when the query returns an undefined value (FailUndefined), a
@@ -82,13 +89,23 @@ func asyncEval(
8289
cmd := shell.Command{
8390
Command: "opa",
8491
Args: formatOPAEvalArgs(options, jsonFilePath, resultQuery),
85-
Logger: options.Logger,
92+
93+
// Do not log output from shell package so we can log the full json without breaking it up. This is ok, because
94+
// opa eval is typically very quick.
95+
Logger: logger.Discard,
8696
}
87-
err := shell.RunCommandE(t, cmd)
97+
err := runCommandWithFullLoggingE(t, options.Logger, cmd)
98+
ruleBasePath := filepath.Base(options.RulePath)
8899
if err == nil {
89-
options.Logger.Logf(t, "opa eval passed on file %s", jsonFilePath)
100+
options.Logger.Logf(t, "opa eval passed on file %s (policy %s; query %s)", jsonFilePath, ruleBasePath, resultQuery)
90101
} else {
91-
options.Logger.Logf(t, "Failed opa eval on file %s", jsonFilePath)
102+
options.Logger.Logf(t, "Failed opa eval on file %s (policy %s; query %s)", jsonFilePath, ruleBasePath, resultQuery)
103+
if options.DebugDisableQueryDataOnError == false {
104+
options.Logger.Logf(t, "DEBUG: rerunning opa eval to query for full data.")
105+
cmd.Args = formatOPAEvalArgs(options, jsonFilePath, "data")
106+
// We deliberately ignore the error here as we want to only return the original error.
107+
runCommandWithFullLoggingE(t, options.Logger, cmd)
108+
}
92109
}
93110
errChan <- err
94111
}
@@ -114,3 +131,12 @@ func formatOPAEvalArgs(options *EvalOptions, jsonFilePath string, resultQuery st
114131
)
115132
return args
116133
}
134+
135+
// runCommandWithFullLogging will log the command output in its entirety with buffering. This avoids breaking up the
136+
// logs when commands are run concurrently. This is a private function used in the context of opa only because opa runs
137+
// very quickly, and the output of opa is hard to parse if it is broken up by interleaved logs.
138+
func runCommandWithFullLoggingE(t testing.TestingT, logger *logger.Logger, cmd shell.Command) error {
139+
output, err := shell.RunCommandAndGetOutputE(t, cmd)
140+
logger.Logf(t, "Output of command `%s %s`:\n%s", cmd.Command, strings.Join(cmd.Args, " "), output)
141+
return err
142+
}

test/terraform_opa_example_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ func TestOPAEvalTerraformModuleFailsCheck(t *testing.T) {
4444
RulePath: policyPath,
4545
}
4646

47-
// website::tag::6:: Here we expect the checks to fail, so we use `OPAEvalE` to check the error.
47+
// website::tag::6:: Here we expect the checks to fail, so we use `OPAEvalE` to check the error. Note that on the files that failed, this function will rerun `opa eval` with the query set to `data`, so you can see the values of all the variables in the policy. This is useful for debugging failures.
4848
require.Error(t, terraform.OPAEvalE(t, tfOpts, opaOpts, "data.enforce_source.allow"))
4949
}

0 commit comments

Comments
 (0)