Skip to content

Commit a4ec981

Browse files
authored
[QT-352] Always output exec information (#76)
When executing commands that output information we should always display it in the operation summary. This change ensures the `output` and `exec` scenario sub-commands are always displayed in the operation summary in the human readable mode. * Always display the output of exec sub-commands in the operation status. * Always configure the exec operation runner with a reference to the scenario Terraform module. * Bump version * Use the diagnostics helper function to determine the status for all scenario sub-command operations. * Update acceptance test runners to use different ports to allow for better parallel acceptance test execution. Signed-off-by: Ryan Cragun <[email protected]>
1 parent 239ebc3 commit a4ec981

File tree

9 files changed

+76
-12
lines changed

9 files changed

+76
-12
lines changed

acceptance/acceptance_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,12 @@ func (r *acceptanceRunner) run(ctx context.Context, subCommand string) ([]byte,
193193
if err != nil {
194194
return nil, nil
195195
}
196-
cmd := exec.CommandContext(ctx, path, strings.Split(subCommand, " ")...)
196+
197+
cmdParts := strings.Split(subCommand, " ")
198+
// Don't specify a port so we can execute tests in parallel
199+
cmdParts = append(cmdParts, "--listen-grpc", "http://localhost")
200+
201+
cmd := exec.CommandContext(ctx, path, cmdParts...)
197202
cmd.Env = os.Environ()
198203
return cmd.CombinedOutput()
199204
}

internal/operation/operator_local.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,10 @@ func (o *LocalOperator) Stop() error {
117117
defer o.mu.Unlock()
118118
o.running = false // Prevent new work requests from being dispatched
119119
o.drainWorkReqQueue() // Drain any queued operations
120-
o.ctxCancel() // Cancel in-flight operations, kill operation workers, drain the event queue
121-
o.publisher.Stop() // Turn off event publisher
120+
if o.ctxCancel != nil {
121+
o.ctxCancel() // Cancel in-flight operations, kill operation workers, drain the event queue
122+
}
123+
o.publisher.Stop() // Turn off event publisher
122124
return nil
123125
}
124126

internal/operation/runner_scenario_destroy.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ func DestroyScenario(req *pb.Operation_Request) WorkFunc {
9494

9595
// Destroy the scenario
9696
resVal.Destroy.Destroy = runner.terraformDestroy(ctx, req, events, state)
97-
res.Status = diagnostics.Status(runner.TFConfig.FailOnWarnings, resVal.Destroy.Destroy.GetDiagnostics()...)
97+
98+
// Determine our final status from all operations
99+
res.Status = diagnostics.OperationStatus(runner.TFConfig.FailOnWarnings, res)
98100

99101
return res
100102
}

internal/operation/runner_scenario_exec.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,34 @@ func ExecScenario(req *pb.Operation_Request) WorkFunc {
4040
WithLogger(log),
4141
)
4242

43+
// Exec is tricky in that the sub-command may or may not actually need
44+
// to execute in the context of a generated scenario Terraform module.
45+
// As such, we'll try and configure it with the module but rewrite any
46+
// failure diags as warnings. If the sub-command needs to the module and
47+
// it doesn't exist the sub-command failure will be reported.
48+
49+
// Try and configure the runner with the module
50+
mod, diags := moduleForReq(req)
51+
52+
if len(diags) > 0 {
53+
// Rewrite failure diags to warnings since we might not need the module
54+
for i := range diags {
55+
if diags[i].Severity == pb.Diagnostic_SEVERITY_ERROR {
56+
diags[i].Severity = pb.Diagnostic_SEVERITY_WARNING
57+
}
58+
}
59+
}
60+
61+
resVal.Exec.Diagnostics = append(resVal.Exec.GetDiagnostics(), diags...)
62+
63+
// Configure our Terraform executor to use module that may or may not exist
64+
runner.TFConfig.WithModule(mod)
65+
66+
// Execute the exec command
4367
resVal.Exec.Exec = runner.terraformExec(ctx, req, events)
44-
res.Status = diagnostics.Status(runner.TFConfig.FailOnWarnings, resVal.Exec.Exec.GetDiagnostics()...)
68+
69+
// Determine our final status from all operations
70+
res.Status = diagnostics.OperationStatus(runner.TFConfig.FailOnWarnings, res)
4571

4672
return res
4773
}

internal/operation/runner_scenario_generate.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ func GenerateScenario(req *pb.Operation_Request) WorkFunc {
3838
// Run generate and update the generic status
3939
resVal := runner.moduleGenerate(ctx, req, events)
4040
res.Value = resVal
41-
res.Status = diagnostics.Status(runner.TFConfig.FailOnWarnings, resVal.Generate.GetDiagnostics()...)
41+
42+
// Determine our final status from all operations
43+
res.Status = diagnostics.OperationStatus(runner.TFConfig.FailOnWarnings, res)
4244

4345
return res
4446
}

internal/operation/runner_scenario_output.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ func OutputScenario(req *pb.Operation_Request) WorkFunc {
3939
WithLogger(log),
4040
)
4141

42+
// Configure the runner with the existing Terraform module. If it doesn't
43+
// exit there's nothing to output.
4244
mod, diags := moduleForReq(req)
4345
resVal.Output.Diagnostics = append(resVal.Output.GetDiagnostics(), diags...)
4446

@@ -57,7 +59,9 @@ func OutputScenario(req *pb.Operation_Request) WorkFunc {
5759
// Run the output command in the context of the module that should already
5860
// exist
5961
resVal.Output.Output = runner.terraformOutput(ctx, req, events)
60-
res.Status = diagnostics.Status(runner.TFConfig.FailOnWarnings, resVal.Output.Output.GetDiagnostics()...)
62+
63+
// Determine our final status from all operations
64+
res.Status = diagnostics.OperationStatus(runner.TFConfig.FailOnWarnings, res)
6165

6266
return res
6367
}

internal/ui/basic/show_op_response.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,7 @@ func (v *View) showOperationResponse(res *pb.Operation_Response, fullOnComplete
105105
scenario.FromRef(res.GetOp().GetScenario())
106106
v.ui.Info(fmt.Sprintf("Scenario: %s %s", scenario.String(), v.opStatusString(res.GetStatus())))
107107

108-
// If we have a successful operation and fullOnComplete has not been set to
109-
// true we'll move on after printing a single line for the scenario.
110-
if res.GetStatus() == pb.Operation_STATUS_COMPLETED && !fullOnComplete {
108+
if !shouldShowFullResponse(res, fullOnComplete) {
111109
return nil
112110
}
113111

@@ -162,3 +160,27 @@ func (v *View) showOperationResponse(res *pb.Operation_Response, fullOnComplete
162160

163161
return nil
164162
}
163+
164+
// shouldShowFullResponse determines whether or not we should display the entire
165+
// operation response. We show the full response if something went wrong, if
166+
// a full response has been requested, or if there is operation information for
167+
// for sub-operations that have output like exec or output.
168+
func shouldShowFullResponse(res *pb.Operation_Response, fullOnComplete bool) bool {
169+
if fullOnComplete {
170+
return true
171+
}
172+
173+
if res.GetStatus() != pb.Operation_STATUS_COMPLETED {
174+
return true
175+
}
176+
177+
if res.GetExec() != nil {
178+
return true
179+
}
180+
181+
if res.GetOutput() != nil {
182+
return true
183+
}
184+
185+
return false
186+
}

internal/ui/basic/tf_responses.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (v *View) writeExecResponse(exec *pb.Terraform_Command_Exec_Response) {
8181
}
8282

8383
v.ui.Info(exec.GetStdout())
84+
v.ui.Error(exec.GetStderr())
8485
v.ui.Debug(fmt.Sprintf(" Sub-command: %s", exec.GetSubCommand()))
8586
v.WriteDiagnostics(exec.GetDiagnostics())
8687
}
@@ -97,7 +98,7 @@ func (v *View) writeOutputResponse(res *pb.Operation_Response) {
9798

9899
scenario := flightplan.NewScenario()
99100
scenario.FromRef(res.GetOp().GetScenario())
100-
v.ui.Info(fmt.Sprintf("Scenario: %s", scenario.String()))
101+
v.ui.Info(fmt.Sprintf("Scenario: %s %s", scenario.String(), v.opStatusString(res.GetStatus())))
101102

102103
if status.HasFailed(v.settings.FailOnWarnings, out) {
103104
msg := " Output: failed!"

version/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ var (
1414
//
1515
// Version must conform to the format expected by github.com/hashicorp/go-version
1616
// for tests to work.
17-
Version = "0.0.13"
17+
Version = "0.0.14"
1818

1919
// VersionPrerelease is a pre-release marker for the version. If this is ""
2020
// (empty string) then it means that it is a final release. Otherwise, this

0 commit comments

Comments
 (0)