github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/controller/state/imagescan/errors.go (about) 1 package imagescan 2 3 import ( 4 "errors" 5 "regexp" 6 "strings" 7 ) 8 9 const ( 10 logrusErrorPattern = `time="(?P<Timestamp>.*?)" level=(?P<Level>.*?) msg="(?P<Message>.*?)" component=(?P<Component>.*)` 11 ) 12 13 var ( 14 re = regexp.MustCompile(logrusErrorPattern) 15 16 errImageScanLayerNotFound = errors.New("image layer not found") 17 errPrivateImage = errors.New("private image") 18 ) 19 20 type Log struct { 21 Timestamp string 22 Level string 23 Message string 24 Component string 25 } 26 27 func isPrivateImageError(rawErr error) bool { 28 errStr := strings.ToLower(rawErr.Error()) 29 30 // Error codes from https://github.com/google/go-containerregistry/blob/190ad0e4d556f199a07951d55124f8a394ebccd9/pkg/v1/remote/transport/error.go#L115 31 // Connection refused error can happen for localhost image. 32 for _, errPart := range []string{"unauthorized", "manifest_unknown", "denied", "connection refused"} { 33 if strings.Contains(errStr, errPart) { 34 return true 35 } 36 } 37 return false 38 } 39 40 func isHostFSError(rawErr error) bool { 41 return strings.Contains(rawErr.Error(), "no such file or directory") || strings.Contains(rawErr.Error(), "failed to get the layer") 42 } 43 44 func parseErrorFromLog(rawErr error) error { 45 if isPrivateImageError(rawErr) { 46 return errPrivateImage 47 } 48 if isHostFSError(rawErr) { 49 return errImageScanLayerNotFound 50 } 51 logs := parseLogrusLog(rawErr.Error()) 52 var errs []error 53 for _, log := range logs { 54 if log.Level == "error" || log.Level == "fatal" { 55 errs = append(errs, errors.New(log.Message)) 56 } 57 } 58 if len(errs) != 0 { 59 return errors.Join(errs...) 60 } 61 return rawErr 62 } 63 64 func parseLogrusLog(logMessage string) []Log { 65 var logs []Log 66 lines := strings.Split(logMessage, "\n") 67 for _, line := range lines { 68 match := re.FindStringSubmatch(line) 69 if match != nil { 70 result := make(map[string]string) 71 for i, name := range re.SubexpNames() { 72 if i != 0 && name != "" { 73 result[name] = match[i] 74 } 75 } 76 logs = append(logs, Log{ 77 Timestamp: result["Timestamp"], 78 Level: result["Level"], 79 Message: result["Message"], 80 Component: result["Component"], 81 }) 82 } 83 } 84 return logs 85 }