github.com/verrazzano/verrazzano@v1.7.1/tools/vz/pkg/internal/util/files/files.go (about) 1 // Copyright (c) 2021, 2024, 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 files handles searching 5 package files 6 7 import ( 8 "encoding/json" 9 "errors" 10 "fmt" 11 "io" 12 "os" 13 "path/filepath" 14 "regexp" 15 "time" 16 17 "github.com/verrazzano/verrazzano/tools/vz/pkg/constants" 18 "github.com/verrazzano/verrazzano/tools/vz/pkg/helpers" 19 utillog "github.com/verrazzano/verrazzano/tools/vz/pkg/internal/util/log" 20 "go.uber.org/zap" 21 corev1 "k8s.io/api/core/v1" 22 ) 23 24 // GetMatchingFileNames returns the filenames for files that match a regular expression. 25 func GetMatchingFileNames(log *zap.SugaredLogger, rootDirectory string, fileMatchRe *regexp.Regexp) (fileMatches []string, err error) { 26 utillog.DebugfIfNotNil(log, "GetMatchingFiles called with rootDirectory: %s", rootDirectory) 27 if len(rootDirectory) == 0 { 28 utillog.DebugfIfNotNil(log, "GetMatchingFiles requires a rootDirectory") 29 return nil, errors.New("GetMatchingFiles requires a rootDirectory") 30 } 31 32 if fileMatchRe == nil { 33 return nil, fmt.Errorf("GetMatchingFiles requires a regular expression") 34 } 35 36 walkFunc := func(fileName string, fileInfo os.FileInfo, err error) error { 37 if !fileMatchRe.MatchString(fileName) { 38 return nil 39 } 40 if !fileInfo.IsDir() { 41 utillog.DebugfIfNotNil(log, "GetMatchingFiles %s matched", fileName) 42 fileMatches = append(fileMatches, fileName) 43 } 44 return nil 45 } 46 47 err = filepath.Walk(rootDirectory, walkFunc) 48 if err != nil { 49 utillog.DebugfIfNotNil(log, "GetMatchingFiles failed to walk the filepath", err) 50 return nil, err 51 } 52 return fileMatches, err 53 } 54 55 // GetMatchingDirectoryNames returns the filenames for directories that match a regular expression. 56 func GetMatchingDirectoryNames(log *zap.SugaredLogger, rootDirectory string, fileMatchRe *regexp.Regexp) (fileMatches []string, err error) { 57 utillog.DebugfIfNotNil(log, "GetMatchingFiles called with rootDirectory: %s", rootDirectory) 58 if len(rootDirectory) == 0 { 59 utillog.DebugfIfNotNil(log, "GetMatchingDirectories requires a root directory") 60 return nil, errors.New("GetMatchingDirectories requires a rootDirectory") 61 } 62 63 if fileMatchRe == nil { 64 return nil, fmt.Errorf("GetMatchingDirectories requires a regular expression") 65 } 66 67 walkFunc := func(fileName string, fileInfo os.FileInfo, err error) error { 68 if !fileMatchRe.MatchString(fileName) { 69 return nil 70 } 71 if fileInfo.IsDir() { 72 utillog.DebugfIfNotNil(log, "GetMatchingDirectories %s matched", fileName) 73 fileMatches = append(fileMatches, fileName) 74 } 75 return nil 76 } 77 78 err = filepath.Walk(rootDirectory, walkFunc) 79 if err != nil { 80 utillog.DebugfIfNotNil(log, "GetMatchingFiles failed to walk the filepath", err) 81 return nil, err 82 } 83 return fileMatches, nil 84 } 85 86 // FindNamespaces relies on the directory structure of the cluster-snapshot/namespaces to 87 // determine the namespaces that were found in the dump. It will return the 88 // namespace only here and not the entire path. 89 func FindNamespaces(log *zap.SugaredLogger, clusterRoot string) (namespaces []string, err error) { 90 fileInfos, err := os.ReadDir(clusterRoot) 91 if err != nil { 92 return nil, fmt.Errorf("FindNamespaces failed to read directory %s: %s", clusterRoot, err.Error()) 93 } 94 95 for _, fileInfo := range fileInfos { 96 if fileInfo.IsDir() { 97 namespaces = append(namespaces, filepath.Base(fileInfo.Name())) 98 } 99 } 100 return namespaces, nil 101 } 102 103 // FormFilePathInClusterRoot will find filename in the cluster root 104 func FormFilePathInClusterRoot(clusterRoot string, filename string) string { 105 return fmt.Sprintf("%s/%s", clusterRoot, filename) 106 } 107 108 // FormFilePathInNamespace will find filename in the namespace 109 func FormFilePathInNamespace(clusterRoot string, namespace string, filename string) string { 110 return fmt.Sprintf("%s/%s/%s", clusterRoot, namespace, filename) 111 } 112 113 // FindPodLogFileName will find the name of the log file given a pod 114 func FindPodLogFileName(clusterRoot string, pod corev1.Pod) string { 115 return fmt.Sprintf("%s/%s/%s/logs.txt", clusterRoot, pod.ObjectMeta.Namespace, pod.ObjectMeta.Name) 116 } 117 118 // UnmarshallFileInClusterRoot - unmarshall a file into a struct 119 func UnmarshallFileInClusterRoot(clusterRoot string, filename string, object interface{}) error { 120 clusterPath := FormFilePathInClusterRoot(clusterRoot, filename) 121 return unmarshallFile(clusterPath, object) 122 } 123 124 // UnmarshallFileInNamespace - unmarshall a file from a namespace into a struct 125 func UnmarshallFileInNamespace(clusterRoot string, namespace string, filename string, object interface{}) error { 126 clusterPath := FormFilePathInNamespace(clusterRoot, namespace, filename) 127 return unmarshallFile(clusterPath, object) 128 } 129 130 func unmarshallFile(clusterPath string, object interface{}) error { 131 // Parse the json into local struct 132 file, err := os.Open(clusterPath) 133 if os.IsNotExist(err) { 134 // The file may not exist if the component is not installed. 135 return nil 136 } 137 if err != nil { 138 return fmt.Errorf("failed to open file %s from cluster snapshot: %s", clusterPath, err.Error()) 139 } 140 defer file.Close() 141 142 fileBytes, err := io.ReadAll(file) 143 if err != nil { 144 return fmt.Errorf("Failed reading Json file %s: %s", clusterPath, err.Error()) 145 } 146 147 // Unmarshall file contents into a struct 148 err = json.Unmarshal(fileBytes, object) 149 if err != nil { 150 return fmt.Errorf("Failed to unmarshal %s: %s", clusterPath, err.Error()) 151 } 152 153 return nil 154 } 155 156 // GetTimeOfCapture parses the metadata.json file and converts the time string into a time.Time object to be used by other functions 157 func GetTimeOfCapture(log *zap.SugaredLogger, clusterRoot string) (*time.Time, error) { 158 metadataFile := FormFilePathInClusterRoot(clusterRoot, constants.MetadataJSON) 159 if _, err := os.Stat(metadataFile); errors.Is(err, os.ErrNotExist) { 160 return nil, nil 161 } 162 metadataObjectToUnmarshalInto := &helpers.Metadata{} 163 err := unmarshallFile(metadataFile, &metadataObjectToUnmarshalInto) 164 if err != nil { 165 return nil, err 166 } 167 timeString := metadataObjectToUnmarshalInto.Time 168 timeObject, err := time.Parse(time.RFC3339, timeString) 169 if err != nil { 170 return nil, err 171 } 172 return &timeObject, err 173 174 }