-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: add custom step output scanner with error detection (#216)
* feat: add custom step output scanner with error detection * fix lint * improve keywords * add comment * fix exec error handling bug and update error detection * fix err handling * fix lint * simplify logic * require approval for destroy stages too --------- Co-authored-by: michaeljguarino <[email protected]>
- Loading branch information
1 parent
e60d5fc
commit c44a2b2
Showing
10 changed files
with
233 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package exec | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"fmt" | ||
"io" | ||
"strings" | ||
) | ||
|
||
type outputAnalyzer struct { | ||
stdout *bytes.Buffer | ||
stderr *bytes.Buffer | ||
|
||
heuristics []OutputAnalyzerHeuristic | ||
} | ||
|
||
func (in *outputAnalyzer) Stdout() io.Writer { | ||
return in.stdout | ||
} | ||
|
||
func (in *outputAnalyzer) Stderr() io.Writer { | ||
return in.stderr | ||
} | ||
|
||
func (in *outputAnalyzer) Detect() []error { | ||
errors := make([]error, 0) | ||
output := in.stdout.String() | ||
|
||
for _, heuristic := range in.heuristics { | ||
if potentialErrors := heuristic.Detect(bufio.NewScanner(strings.NewReader(output))); len(potentialErrors) > 0 { | ||
errors = append(errors, potentialErrors.ToErrors()...) | ||
} | ||
} | ||
|
||
if in.stderr.Len() > 0 { | ||
errors = append(errors, fmt.Errorf("%s", in.stderr.String())) | ||
} | ||
|
||
return errors | ||
} | ||
|
||
func NewOutputAnalyzer(heuristics ...OutputAnalyzerHeuristic) OutputAnalyzer { | ||
return &outputAnalyzer{ | ||
stdout: bytes.NewBuffer([]byte{}), | ||
stderr: bytes.NewBuffer([]byte{}), | ||
heuristics: heuristics, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package exec | ||
|
||
import ( | ||
"bufio" | ||
"strings" | ||
|
||
"github.com/pluralsh/polly/algorithms" | ||
) | ||
|
||
type keywordDetector struct { | ||
keywords []keyword | ||
} | ||
|
||
type keyword struct { | ||
content string | ||
ignoreCase bool | ||
} | ||
|
||
func (in keyword) PartOf(s string) bool { | ||
if !in.ignoreCase { | ||
return strings.Contains(s, in.content) | ||
} | ||
|
||
return strings.Contains( | ||
strings.ToLower(s), | ||
strings.ToLower(in.content), | ||
) | ||
} | ||
|
||
// Detect implements [OutputAnalyzerHeuristic] interface. | ||
// TODO: we can spread actual message analysis into multiple routines to speed up the process. | ||
func (in *keywordDetector) Detect(input *bufio.Scanner) Errors { | ||
line := 0 | ||
errors := make([]Error, 0) | ||
for input.Scan() { | ||
if !in.hasError(input.Text()) { | ||
continue | ||
} | ||
|
||
errors = append(errors, Error{ | ||
line: line, | ||
message: input.Text(), | ||
}) | ||
} | ||
|
||
return errors | ||
} | ||
|
||
func (in *keywordDetector) hasError(message string) bool { | ||
return algorithms.Index(in.keywords, func(k keyword) bool { | ||
return k.PartOf(message) | ||
}) >= 0 | ||
} | ||
|
||
func NewKeywordDetector() OutputAnalyzerHeuristic { | ||
return &keywordDetector{ | ||
keywords: []keyword{ | ||
{"error message: http remote state already locked", true}, | ||
{"error acquiring the state lock", true}, | ||
{"Error:", false}, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package exec | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
) | ||
|
||
// OutputAnalyzer captures the command output | ||
// and attempts to detect potential errors. | ||
type OutputAnalyzer interface { | ||
Stdout() io.Writer | ||
Stderr() io.Writer | ||
|
||
// Detect scans the output for potential errors. | ||
// It uses a custom heuristics to detect issues. | ||
// It can result in a false positives. | ||
// | ||
// Note: Make sure that it is executed after Write | ||
// has finished to ensure proper detection. | ||
Detect() []error | ||
} | ||
|
||
type OutputAnalyzerHeuristic interface { | ||
Detect(input *bufio.Scanner) Errors | ||
} | ||
|
||
type Error struct { | ||
line int | ||
message string | ||
} | ||
|
||
func (in Error) ToError() error { | ||
return fmt.Errorf("[%d] %s", in.line, in.message) | ||
} | ||
|
||
type Errors []Error | ||
|
||
func (in Errors) ToErrors() []error { | ||
errors := make([]error, len(in)) | ||
for _, err := range in { | ||
errors = append(errors, err.ToError()) | ||
} | ||
|
||
return errors | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters