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  }