Skip to content

Commit 27e2940

Browse files
committed
initial draft of detailed errors
1 parent a6dbd1c commit 27e2940

File tree

5 files changed

+61
-4
lines changed

5 files changed

+61
-4
lines changed

cli/cli_app.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,20 @@ func applyAll(terragruntOptions *options.TerragruntOptions) error {
742742
}
743743

744744
if shouldApplyAll {
745-
return stack.Apply(terragruntOptions)
745+
stack.SetupErrorChannel()
746+
go stack.CollectModuleErrors()
747+
err := stack.Apply(terragruntOptions)
748+
close(stack.ErrorChan)
749+
750+
terragruntOptions.Logger.Printf("Encountered the following root-causes: \n")
751+
for module, errList := range stack.ErrorMap {
752+
terragruntOptions.Logger.Printf("Module: %s \n", module)
753+
for _, err := range errList {
754+
terragruntOptions.Logger.Printf("- %s \n", err)
755+
}
756+
}
757+
758+
return err
746759
}
747760

748761
return nil

configstack/module.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type TerraformModule struct {
2727
TerragruntOptions *options.TerragruntOptions
2828
AssumeAlreadyApplied bool
2929
FlagExcluded bool
30+
ErrorChan chan map[string]error
3031
}
3132

3233
// Render this module as a human-readable string

configstack/running_module.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package configstack
22

33
import (
4+
"bytes"
45
"fmt"
6+
"io"
57
"strings"
68
"sync"
79

@@ -27,6 +29,9 @@ type runningModule struct {
2729
Dependencies map[string]*runningModule
2830
NotifyWhenDone []*runningModule
2931
FlagExcluded bool
32+
ErrorChan chan map[string]error
33+
OutStream bytes.Buffer
34+
Writer io.Writer
3035
}
3136

3237
// This controls in what order dependencies should be enforced between modules
@@ -48,6 +53,8 @@ func newRunningModule(module *TerraformModule) *runningModule {
4853
Dependencies: map[string]*runningModule{},
4954
NotifyWhenDone: []*runningModule{},
5055
FlagExcluded: module.FlagExcluded,
56+
ErrorChan: module.ErrorChan,
57+
Writer: module.TerragruntOptions.Writer,
5158
}
5259
}
5360

@@ -130,6 +137,8 @@ func removeFlagExcluded(modules map[string]*runningModule) map[string]*runningMo
130137
Err: module.Err,
131138
NotifyWhenDone: module.NotifyWhenDone,
132139
Status: module.Status,
140+
ErrorChan: module.ErrorChan,
141+
Writer: module.Module.TerragruntOptions.Writer,
133142
}
134143

135144
// Only add dependencies that should not be excluded
@@ -154,6 +163,8 @@ func runModules(modules map[string]*runningModule) error {
154163
waitGroup.Add(1)
155164
go func(module *runningModule) {
156165
defer waitGroup.Done()
166+
module.Module.TerragruntOptions.Writer = &module.OutStream
167+
module.Module.TerragruntOptions.ErrWriter = &module.OutStream
157168
module.runModuleWhenReady()
158169
}(module)
159170
}
@@ -170,6 +181,10 @@ func collectErrors(modules map[string]*runningModule) error {
170181
for _, module := range modules {
171182
if module.Err != nil {
172183
errs = append(errs, module.Err)
184+
fmt.Printf("----- ERRROR TYPE %T ----- \n", module.Err)
185+
if _, isDepErr := module.Err.(DependencyFinishedWithError); !isDepErr {
186+
module.ErrorChan <- map[string]error{module.Module.Path: fmt.Errorf("%s", module.OutStream.String())}
187+
}
173188
}
174189
}
175190

@@ -223,8 +238,11 @@ func (module *runningModule) runNow() error {
223238
module.Module.TerragruntOptions.Logger.Printf("Running module %s now", module.Module.Path)
224239
return module.Module.TerragruntOptions.RunTerragrunt(module.Module.TerragruntOptions)
225240
}
241+
226242
}
227243

244+
var separator = strings.Repeat("-", 132)
245+
228246
// Record that a module has finished executing and notify all of this module's dependencies
229247
func (module *runningModule) moduleFinished(moduleErr error) {
230248
if moduleErr == nil {
@@ -233,6 +251,8 @@ func (module *runningModule) moduleFinished(moduleErr error) {
233251
module.Module.TerragruntOptions.Logger.Printf("Module %s has finished with an error: %v", module.Module.Path, moduleErr)
234252
}
235253

254+
fmt.Fprintf(module.Writer, "%s\n%v\n\n%v\n", separator, module.Module.Path, module.OutStream.String())
255+
236256
module.Status = Finished
237257
module.Err = moduleErr
238258

configstack/stack.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,21 @@ import (
55
"fmt"
66
"strings"
77

8+
"sort"
9+
810
"github.com/gruntwork-io/terragrunt/config"
911
"github.com/gruntwork-io/terragrunt/errors"
1012
"github.com/gruntwork-io/terragrunt/options"
1113
"github.com/gruntwork-io/terragrunt/util"
12-
"sort"
1314
)
1415

1516
// Represents a stack of Terraform modules (i.e. folders with Terraform templates) that you can "spin up" or
1617
// "spin down" in a single command
1718
type Stack struct {
18-
Path string
19-
Modules []*TerraformModule
19+
Path string
20+
Modules []*TerraformModule
21+
ErrorMap map[string][]error
22+
ErrorChan chan map[string]error
2023
}
2124

2225
// Render this stack as a human-readable string
@@ -113,11 +116,25 @@ func FindStackInSubfolders(terragruntOptions *options.TerragruntOptions) (*Stack
113116
// Set the command in the TerragruntOptions object of each module in this stack to the given command.
114117
func (stack *Stack) setTerraformCommand(command []string) {
115118
for _, module := range stack.Modules {
119+
module.ErrorChan = stack.ErrorChan
116120
module.TerragruntOptions.TerraformCliArgs = append(command, module.TerragruntOptions.TerraformCliArgs...)
117121
module.TerragruntOptions.TerraformCommand = util.FirstArg(command)
118122
}
119123
}
120124

125+
func (stack *Stack) SetupErrorChannel() {
126+
stack.ErrorMap = make(map[string][]error)
127+
stack.ErrorChan = make(chan map[string]error)
128+
}
129+
130+
func (stack *Stack) CollectModuleErrors() {
131+
for errorMap := range stack.ErrorChan {
132+
for module, err := range errorMap {
133+
stack.ErrorMap[module] = append(stack.ErrorMap[module], err)
134+
}
135+
}
136+
}
137+
121138
// Find all the Terraform modules in the folders that contain the given Terragrunt config files and assemble those
122139
// modules into a Stack object that can be applied or destroyed in a single command
123140
func createStackForTerragruntConfigPaths(path string, terragruntConfigPaths []string, terragruntOptions *options.TerragruntOptions, howThesePathsWereFound string) (*Stack, error) {

shell/run_shell_cmd.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ func RunShellCommand(terragruntOptions *options.TerragruntOptions, command strin
2828
return err
2929
}
3030

31+
func RunTerraformCommandAndRedirectOutputToLogger(terragruntOptions *options.TerragruntOptions, args ...string) error {
32+
output, err := RunShellCommandWithOutput(terragruntOptions, "", terragruntOptions.TerraformPath, args...)
33+
terragruntOptions.Logger.Println(output)
34+
return err
35+
}
36+
3137
// Run the given Terraform command, writing its stdout/stderr to the terminal AND returning stdout/stderr to this
3238
// method's caller
3339
func RunTerraformCommandWithOutput(terragruntOptions *options.TerragruntOptions, args ...string) (*CmdOutput, error) {

0 commit comments

Comments
 (0)