github.com/magnusbaeck/logstash-filter-verifier/v2@v2.0.0-pre.1/logstash/pipelineconfigdir.go (about) 1 // Copyright (c) 2016-2018 Magnus Bäck <magnus@noun.se> 2 3 package logstash 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "sort" 11 12 lsparser "github.com/breml/logstash-config" 13 "github.com/breml/logstash-config/ast" 14 ) 15 16 // flattenFilenames flattens a list of files and directories so it 17 // only contains the given files and the files found in the 18 // directories. The flattening of directories isn't recursive, 19 // i.e. files in subdirectories of the provided directories aren't 20 // included. 21 func flattenFilenames(filenames []string) ([]string, error) { 22 result := make([]string, 0, len(filenames)) 23 for _, f := range filenames { 24 stat, err := os.Stat(f) 25 if err != nil { 26 return result, err 27 } 28 if stat.IsDir() { 29 subdirFiles, err := getFilesInDir(f, true) 30 if err != nil { 31 return result, err 32 } 33 result = append(result, subdirFiles...) 34 } else { 35 result = append(result, f) 36 } 37 } 38 return result, nil 39 } 40 41 // getPipelineConfigDir copies one or more Logstash pipeline 42 // configuration files into the root of the specified directory. 43 // Returns an error if any I/O error occurs but also if the 44 // basenames of the configuration files aren't unique, i.e. if 45 // they'd overwrite one another in the directory. 46 func getPipelineConfigDir(dir string, configs []string) error { 47 allFiles, err := flattenFilenames(configs) 48 if err != nil { 49 return fmt.Errorf("Error listing configuration files: %s", err) 50 } 51 log.Debugf("Preparing configuration file directory %s with these files: %v", dir, allFiles) 52 for _, f := range allFiles { 53 dest := filepath.Join(dir, filepath.Base(f)) 54 _, err := os.Stat(dest) 55 if err == nil { 56 _ = os.RemoveAll(dir) 57 return fmt.Errorf( 58 "The collected list of configuration files contains "+ 59 "two files with the name %q which isn't allowed.", 60 filepath.Base(f)) 61 } else if !os.IsNotExist(err) { 62 _ = os.RemoveAll(dir) 63 return err 64 } 65 err = copyFile(f, dest) 66 if err != nil { 67 _ = os.RemoveAll(dir) 68 return fmt.Errorf("Config file copy failed: %s", err) 69 } 70 71 err = removeInputOutput(dest) 72 if err != nil { 73 _ = os.RemoveAll(dir) 74 return fmt.Errorf("Failed to remove the input and output sections: %s", err) 75 } 76 } 77 return nil 78 } 79 80 // getFilesInDir returns a sorted list of the names of the 81 // (non-directory) files in the given directory. If includeDir 82 // is true the returned path will include the directory name. 83 func getFilesInDir(dir string, includeDir bool) ([]string, error) { 84 filenames := make([]string, 0) 85 files, err := ioutil.ReadDir(dir) 86 if err != nil { 87 return nil, err 88 } 89 for _, f := range files { 90 if !f.Mode().IsDir() { 91 if includeDir { 92 filenames = append(filenames, filepath.Join(dir, f.Name())) 93 } else { 94 filenames = append(filenames, f.Name()) 95 } 96 } 97 } 98 sort.Strings(filenames) 99 return filenames, nil 100 } 101 102 // removeInputOutput removes the input and output sections in the 103 // given logstash configuration file. The operation is done in place 104 // and the original file content is replaced. 105 func removeInputOutput(path string) error { 106 parsed, err := lsparser.ParseFile(path) 107 if err != nil { 108 return err 109 } 110 111 if parsed == nil { 112 return fmt.Errorf("could not parse the following Logstash config file: %v", path) 113 } 114 115 config := parsed.(ast.Config) 116 config.Input = nil 117 config.Output = nil 118 119 return ioutil.WriteFile(path, []byte(config.String()), 0600) 120 }