github.com/verrazzano/verrazzano@v1.7.0/tools/vz/pkg/analysis/internal/util/cluster/analyzer.go (about) 1 // Copyright (c) 2021, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 // Package cluster handles cluster analysis 5 package cluster 6 7 import ( 8 "fmt" 9 "os" 10 "regexp" 11 12 "github.com/verrazzano/verrazzano/tools/vz/pkg/analysis/internal/util/files" 13 "github.com/verrazzano/verrazzano/tools/vz/pkg/analysis/internal/util/report" 14 "go.uber.org/zap" 15 ) 16 17 // TBD: Overall the intention/design is that we could execute analysis in parallel if we want to do that in the 18 // 19 // future. So in general analyzers are independent of each other and thread safe, and not expecting to 20 // be executed in a particular order. 21 // However, there may be special cases where we want an analysis to be done and information gleaned 22 // from that analysis to be available to other analyzers. For example, the analysis of the state 23 // of Verrazzano is something that is likely to fall into that category. It will make a high level 24 // determination of where in the lifecycle we are at, and other analyzers may need to easily get that 25 // information to give better guidance on the issues/actions. 26 // 27 // The current implementation is calling the analyzers serially in order. 28 // If we do decide to handle analysis in a parallel fashion later, we likely will need to have some 29 // analyzers called deterministically in exact order before we fire off other analyzers in parallel. 30 // So we may break this into 2 lists in the future: serial analysis functions, parallel analysis functions 31 // Analyzers that may fall into this category should be annotated, with a comment, there currently is only 32 // one that may require that. 33 34 // These are the high level analysis functions that are called. The "Runtime Issues" maps to only certificate functions currently. 35 var clusterAnalysisFunctions = map[string]func(log *zap.SugaredLogger, directory string) (err error){ 36 "Verrazzano Status": AnalyzeVerrazzano, // Execute first, this may share data other analyzers can use 37 "Pod Related Issues": AnalyzePodIssues, 38 "Rancher Status": AnalyzeRancher, 39 "Runtime Issues": AnalyzeCertificateRelatedIssues, 40 "Cluster API Issues": AnalyzeClusterAPI, 41 } 42 43 // ClusterDumpDirectoriesRe is used for finding cluster-snapshot directory name matches 44 var ClusterDumpDirectoriesRe = regexp.MustCompile(`.*/cluster-snapshot$`) 45 46 // LogFilesMatchRe is used for finding pod log files in a cluster dump 47 var LogFilesMatchRe = regexp.MustCompile(`logs.txt`) 48 49 // PodFilesMatchRe is used for finding pod files in a cluster dump 50 var PodFilesMatchRe = regexp.MustCompile(`pods.json`) 51 52 // ErrorSearchRe is used for searching for case insensitive "error". This is useful when we know there is a 53 // problem lurking but we can't identify the specific issue and are trying to capture relevant information 54 // to include in support data from logs and events 55 var ErrorSearchRe = regexp.MustCompile(`(?i).*error.*`) 56 57 // WideErrorSearchRe is used for casting a wider net while looking for issues TBD: .*ERROR.*|.*Error.*|.*FAILED.* 58 var WideErrorSearchRe = regexp.MustCompile(`(?i).*error.*|.*failed.*`) 59 60 // EventReasonFailedRe is used for finding event reason failures 61 var EventReasonFailedRe = regexp.MustCompile(`.*Failed.*`) 62 63 // RunAnalysis is the main entry analysis function 64 func RunAnalysis(log *zap.SugaredLogger, rootDirectory string) (err error) { 65 log.Debugf("Cluster Analyzer runAnalysis on %s", rootDirectory) 66 67 clusterRoots, err := files.GetMatchingDirectories(log, rootDirectory, ClusterDumpDirectoriesRe) 68 if err != nil { 69 log.Debugf("Cluster Analyzer runAnalysis failed examining directories for %s", rootDirectory, err) 70 return fmt.Errorf("Cluster Analyzer runAnalysis failed examining directories for %s", rootDirectory) 71 } 72 if len(clusterRoots) == 0 { 73 log.Debugf("Cluster Analyzer runAnalysis didn't find any clusters to analyze for %s", rootDirectory) 74 return fmt.Errorf("Cluster Analyzer runAnalysis didn't find any clusters to analyze for %s", rootDirectory) 75 } 76 77 for _, clusterRoot := range clusterRoots { 78 // Ignore directories if they don't contain snapshots. Checking if verrazzano-resources.json exists in the dir 79 // that implies the directory has the required snapshots. 80 vzResourcesPath := files.FindFileInClusterRoot(clusterRoot, verrazzanoResource) 81 fileInfo, e := os.Stat(vzResourcesPath) 82 if e != nil || fileInfo.Size() == 0 { 83 log.Debugf("Verrazzano resource file %s is either empty or not there", vzResourcesPath) 84 continue 85 } 86 analyzeCluster(log, clusterRoot) 87 } 88 89 return nil 90 } 91 92 func analyzeCluster(log *zap.SugaredLogger, clusterRoot string) (err error) { 93 log.Debugf("analyzeCluster called for %s", clusterRoot) 94 report.AddSourceAnalyzed(clusterRoot) 95 96 for functionName, function := range clusterAnalysisFunctions { 97 err := function(log, clusterRoot) 98 if err != nil { 99 // Log the error and continue on 100 log.Errorf("Error processing analysis function %s", functionName, err) 101 } 102 } 103 104 return nil 105 }