get.porter.sh/porter@v1.3.0/pkg/exec/builder/errors.go (about) 1 package builder 2 3 import ( 4 "context" 5 "fmt" 6 "regexp" 7 "strings" 8 9 "get.porter.sh/porter/pkg/tracing" 10 ) 11 12 var _ HasErrorHandling = IgnoreErrorHandler{} 13 14 // IgnoreErrorHandler implements HasErrorHandling for the exec mixin 15 // and can be used by any other mixin to get the same error handling behavior. 16 type IgnoreErrorHandler struct { 17 // All ignores any error that happens when the command is run. 18 All bool `yaml:"all,omitempty"` 19 20 // ExitCodes ignores any exit codes in the list. 21 ExitCodes []int `yaml:"exitCodes,omitempty"` 22 23 // Output determines if the error should be ignored based on the command 24 // output. 25 Output IgnoreErrorWithOutput `yaml:"output,omitempty"` 26 } 27 28 type IgnoreErrorWithOutput struct { 29 // Contains specifies that the error is ignored when stderr contains the 30 // specified substring. 31 Contains []string `yaml:"contains,omitempty"` 32 33 // Regex specifies that the error is ignored when stderr matches the 34 // specified regular expression. 35 Regex []string `yaml:"regex,omitempty"` 36 } 37 38 func (h IgnoreErrorHandler) HandleError(ctx context.Context, err ExitError, stdout string, stderr string) error { 39 _, span := tracing.StartSpan(ctx) 40 defer span.EndSpan() 41 42 // We shouldn't be called when there is no error but just in case, let's check 43 if err == nil || err.ExitCode() == 0 { 44 return nil 45 } 46 47 span.Debugf("Evaluating mixin command error %s with the mixin's error handler", err.Error()) 48 49 // Check if the command should always be allowed to "pass" 50 if h.All { 51 span.Debug("Ignoring mixin command error because All was specified in the mixin step definition") 52 return nil 53 } 54 55 // Check if the exit code was allowed 56 exitCode := err.ExitCode() 57 for _, code := range h.ExitCodes { 58 if exitCode == code { 59 span.Debugf("Ignoring mixin command error (exit code: %d) because it was included in the allowed ExitCodes list defined in the mixin step definition", exitCode) 60 return nil 61 } 62 } 63 64 // Check if the output contains a hint that it should be allowed to pass 65 for _, allowError := range h.Output.Contains { 66 if strings.Contains(stderr, allowError) { 67 span.Debugf("Ignoring mixin command error because the error contained the substring %q defined in the mixin step definition", allowError) 68 return nil 69 } 70 } 71 72 // Check if the output matches an allowed regular expression 73 for _, allowMatch := range h.Output.Regex { 74 expression, regexErr := regexp.Compile(allowMatch) 75 if regexErr != nil { 76 err := span.Error(fmt.Errorf("Could not ignore failed command because the Regex specified by the mixin step definition (%q) is invalid:%s", allowMatch, regexErr.Error())) 77 return err 78 } 79 80 if expression.MatchString(stderr) { 81 span.Debugf("Ignoring mixin command error because the error matched the Regex %q defined in the mixin step definition", allowMatch) 82 return nil 83 } 84 } 85 86 return err 87 }