1
1
package opa
2
2
3
3
import (
4
+ "path/filepath"
5
+ "strings"
4
6
"sync"
5
7
6
8
"github.com/gruntwork-io/terratest/modules/logger"
@@ -26,6 +28,11 @@ type EvalOptions struct {
26
28
27
29
// When true, keep any temp files and folders that are created for the purpose of running opa eval.
28
30
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
29
36
}
30
37
31
38
// FailMode signals whether `opa eval` should fail when the query returns an undefined value (FailUndefined), a
@@ -82,13 +89,23 @@ func asyncEval(
82
89
cmd := shell.Command {
83
90
Command : "opa" ,
84
91
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 ,
86
96
}
87
- err := shell .RunCommandE (t , cmd )
97
+ err := runCommandWithFullLoggingE (t , options .Logger , cmd )
98
+ ruleBasePath := filepath .Base (options .RulePath )
88
99
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 )
90
101
} 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
+ }
92
109
}
93
110
errChan <- err
94
111
}
@@ -114,3 +131,12 @@ func formatOPAEvalArgs(options *EvalOptions, jsonFilePath string, resultQuery st
114
131
)
115
132
return args
116
133
}
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
+ }
0 commit comments