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  }