Skip to content

Commit b68b1ef

Browse files
committed
refactoring
1 parent 4235479 commit b68b1ef

File tree

4 files changed

+71
-42
lines changed

4 files changed

+71
-42
lines changed

cli/cli_app.go

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,11 @@ func checkDeprecated(command string, terragruntOptions *options.TerragruntOption
224224
// terragrunt command
225225
func runCommand(command string, terragruntOptions *options.TerragruntOptions) (finalEff error) {
226226
if isMultiModuleCommand(command) {
227-
return runMultiModuleCommand(command, terragruntOptions)
227+
err := runMultiModuleCommand(command, terragruntOptions)
228+
229+
// wait until all detailed errors have been printed
230+
<-configstack.DonePrintingDetailedError
231+
return err
228232
}
229233
return runTerragrunt(terragruntOptions)
230234
}
@@ -685,20 +689,7 @@ func applyAll(terragruntOptions *options.TerragruntOptions) error {
685689
}
686690

687691
if shouldApplyAll {
688-
stack.SetupErrorChannel()
689-
go stack.CollectModuleErrors()
690-
err := stack.Apply(terragruntOptions)
691-
close(stack.ErrorChan)
692-
693-
terragruntOptions.Logger.Printf("Encountered the following root-causes: \n")
694-
for module, errList := range stack.ErrorMap {
695-
terragruntOptions.Logger.Printf("Module: %s \n", module)
696-
for _, err := range errList {
697-
terragruntOptions.Logger.Printf("- %s \n", err)
698-
}
699-
}
700-
701-
return err
692+
return stack.Apply(terragruntOptions)
702693
}
703694

704695
return nil

configstack/module.go

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

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

configstack/running_module.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ type runningModule struct {
2929
Dependencies map[string]*runningModule
3030
NotifyWhenDone []*runningModule
3131
FlagExcluded bool
32-
ErrorChan chan map[string]error
3332
OutStream bytes.Buffer
3433
Writer io.Writer
3534
}
@@ -53,7 +52,6 @@ func newRunningModule(module *TerraformModule) *runningModule {
5352
Dependencies: map[string]*runningModule{},
5453
NotifyWhenDone: []*runningModule{},
5554
FlagExcluded: module.FlagExcluded,
56-
ErrorChan: module.ErrorChan,
5755
Writer: module.TerragruntOptions.Writer,
5856
}
5957
}
@@ -137,7 +135,6 @@ func removeFlagExcluded(modules map[string]*runningModule) map[string]*runningMo
137135
Err: module.Err,
138136
NotifyWhenDone: module.NotifyWhenDone,
139137
Status: module.Status,
140-
ErrorChan: module.ErrorChan,
141138
Writer: module.Module.TerragruntOptions.Writer,
142139
}
143140

@@ -181,13 +178,17 @@ func collectErrors(modules map[string]*runningModule) error {
181178
for _, module := range modules {
182179
if module.Err != nil {
183180
errs = append(errs, module.Err)
184-
fmt.Printf("----- ERRROR TYPE %T ----- \n", module.Err)
181+
182+
// send all non dependency errors to the DetailedErrorChan
185183
if _, isDepErr := module.Err.(DependencyFinishedWithError); !isDepErr {
186-
module.ErrorChan <- map[string]error{module.Module.Path: fmt.Errorf("%s", module.OutStream.String())}
184+
DetailedErrorChan <- map[string]string{module.Module.Path: module.OutStream.String()}
187185
}
188186
}
189187
}
190188

189+
// close the DetailedErrorChan after all errors have been sent
190+
close(DetailedErrorChan)
191+
191192
if len(errs) == 0 {
192193
return nil
193194
} else {
@@ -241,8 +242,6 @@ func (module *runningModule) runNow() error {
241242

242243
}
243244

244-
var separator = strings.Repeat("-", 132)
245-
246245
// Record that a module has finished executing and notify all of this module's dependencies
247246
func (module *runningModule) moduleFinished(moduleErr error) {
248247
if moduleErr == nil {
@@ -251,7 +250,8 @@ func (module *runningModule) moduleFinished(moduleErr error) {
251250
module.Module.TerragruntOptions.Logger.Printf("Module %s has finished with an error: %v", module.Module.Path, moduleErr)
252251
}
253252

254-
fmt.Fprintf(module.Writer, "%s\n%v\n\n%v\n", separator, module.Module.Path, module.OutStream.String())
253+
// print the separated module output
254+
fmt.Fprintf(module.Writer, "%s\n%v\n\n%v\n", OutputMessageSeparator, module.Module.Path, module.OutStream.String())
255255

256256
module.Status = Finished
257257
module.Err = moduleErr

configstack/stack.go

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,21 @@ import (
1616
// Represents a stack of Terraform modules (i.e. folders with Terraform templates) that you can "spin up" or
1717
// "spin down" in a single command
1818
type Stack struct {
19-
Path string
20-
Modules []*TerraformModule
21-
ErrorMap map[string][]error
22-
ErrorChan chan map[string]error
19+
Path string
20+
Modules []*TerraformModule
2321
}
2422

23+
var (
24+
// DetailedErrorMap is a map which contains the module name and matching detailed error messages
25+
DetailedErrorMap map[string][]string
26+
// DetailedErrorChan is the channel which processes all detailed error messages
27+
DetailedErrorChan chan map[string]string
28+
// DonePrintingDetailedError is a channel which blocks the go routine until all detailed errors have been displayed
29+
DonePrintingDetailedError chan bool
30+
// OutputMessageSeparator is the string used for separating the different module outputs
31+
OutputMessageSeparator = strings.Repeat("-", 132)
32+
)
33+
2534
// Render this stack as a human-readable string
2635
func (stack *Stack) String() string {
2736
modules := []string{}
@@ -116,32 +125,21 @@ func FindStackInSubfolders(terragruntOptions *options.TerragruntOptions) (*Stack
116125
// Set the command in the TerragruntOptions object of each module in this stack to the given command.
117126
func (stack *Stack) setTerraformCommand(command []string) {
118127
for _, module := range stack.Modules {
119-
module.ErrorChan = stack.ErrorChan
120128
module.TerragruntOptions.TerraformCliArgs = append(command, module.TerragruntOptions.TerraformCliArgs...)
121129
module.TerragruntOptions.TerraformCommand = util.FirstArg(command)
122130
}
123131
}
124132

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-
138133
// Find all the Terraform modules in the folders that contain the given Terragrunt config files and assemble those
139134
// modules into a Stack object that can be applied or destroyed in a single command
140135
func createStackForTerragruntConfigPaths(path string, terragruntConfigPaths []string, terragruntOptions *options.TerragruntOptions, howThesePathsWereFound string) (*Stack, error) {
141136
if len(terragruntConfigPaths) == 0 {
142137
return nil, errors.WithStackTrace(NoTerraformModulesFound)
143138
}
144139

140+
// configure the channels for collecting detailed error messages
141+
setupDetailedErrorChannel(terragruntOptions)
142+
145143
modules, err := ResolveTerraformModules(terragruntConfigPaths, terragruntOptions, howThesePathsWereFound)
146144
if err != nil {
147145
return nil, err
@@ -155,6 +153,47 @@ func createStackForTerragruntConfigPaths(path string, terragruntConfigPaths []st
155153
return stack, nil
156154
}
157155

156+
// setupDetailedErrorChannel configures the channels responsible for storing detailed error messages
157+
func setupDetailedErrorChannel(terragruntOptions *options.TerragruntOptions) {
158+
DetailedErrorMap = make(map[string][]string)
159+
DetailedErrorChan = make(chan map[string]string)
160+
DonePrintingDetailedError = make(chan bool)
161+
162+
// process all detailed error messages
163+
go collectModuleErrors(terragruntOptions)
164+
}
165+
166+
// collectModuleErrors listens on the DetailedErrorChan and maps errors to their matching modules
167+
func collectModuleErrors(terragruntOptions *options.TerragruntOptions) {
168+
for {
169+
errorMap, more := <-DetailedErrorChan
170+
if more {
171+
for module, err := range errorMap {
172+
DetailedErrorMap[module] = append(DetailedErrorMap[module], err)
173+
}
174+
} else {
175+
printDetailedErrorSummary(terragruntOptions)
176+
DonePrintingDetailedError <- true
177+
return
178+
}
179+
}
180+
}
181+
182+
// printDetailedErrorSummary logs the detailed error messages
183+
func printDetailedErrorSummary(terragruntOptions *options.TerragruntOptions) {
184+
summaryMessage := []string{}
185+
summaryMessage = append(summaryMessage, "Encountered the following root-causes:")
186+
for module, errSlice := range DetailedErrorMap {
187+
summaryMessage = append(summaryMessage, OutputMessageSeparator)
188+
summaryMessage = append(summaryMessage, fmt.Sprintf("Module %s:", module))
189+
for _, err := range errSlice {
190+
summaryMessage = append(summaryMessage, err)
191+
}
192+
}
193+
194+
terragruntOptions.Logger.Printf("%s \n", strings.Join(summaryMessage, "\n"))
195+
}
196+
158197
// Custom error types
159198

160199
var NoTerraformModulesFound = fmt.Errorf("Could not find any subfolders with Terragrunt configuration files")

0 commit comments

Comments
 (0)