206 lines
5.7 KiB
Go
206 lines
5.7 KiB
Go
// Licensed to Elasticsearch B.V. under one or more contributor
|
|
// license agreements. See the NOTICE file distributed with
|
|
// this work for additional information regarding copyright
|
|
// ownership. Elasticsearch B.V. licenses this file to you under
|
|
// the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package cfgfile
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/elastic/beats/libbeat/common"
|
|
"github.com/elastic/beats/libbeat/logp"
|
|
)
|
|
|
|
// Command line flags.
|
|
var (
|
|
// The default config cannot include the beat name as it is not initialized
|
|
// when this variable is created. See ChangeDefaultCfgfileFlag which should
|
|
// be called prior to flags.Parse().
|
|
configfiles = common.StringArrFlag(nil, "c", "beat.yml", "Configuration file, relative to path.config")
|
|
overwrites = common.SettingFlag(nil, "E", "Configuration overwrite")
|
|
testConfig = flag.Bool("configtest", false, "Test configuration and exit.")
|
|
|
|
// Additional default settings, that must be available for variable expansion
|
|
defaults = common.MustNewConfigFrom(map[string]interface{}{
|
|
"path": map[string]interface{}{
|
|
"home": ".", // to be initialized by beat
|
|
"config": "${path.home}",
|
|
"data": fmt.Sprint("${path.home}", string(os.PathSeparator), "data"),
|
|
"logs": fmt.Sprint("${path.home}", string(os.PathSeparator), "logs"),
|
|
},
|
|
})
|
|
|
|
// home-path CLI flag (initialized in init)
|
|
homePath *string
|
|
configPath *string
|
|
)
|
|
|
|
func init() {
|
|
// add '-path.x' options overwriting paths in 'overwrites' config
|
|
makePathFlag := func(name, usage string) *string {
|
|
return common.ConfigOverwriteFlag(nil, overwrites, name, name, "", usage)
|
|
}
|
|
|
|
homePath = makePathFlag("path.home", "Home path")
|
|
configPath = makePathFlag("path.config", "Configuration path")
|
|
makePathFlag("path.data", "Data path")
|
|
makePathFlag("path.logs", "Logs path")
|
|
}
|
|
|
|
// ChangeDefaultCfgfileFlag replaces the value and default value for the `-c`
|
|
// flag so that it reflects the beat name.
|
|
func ChangeDefaultCfgfileFlag(beatName string) error {
|
|
configfiles.SetDefault(beatName + ".yml")
|
|
return nil
|
|
}
|
|
|
|
// GetDefaultCfgfile gets the full path of the default config file. Understood
|
|
// as the first value for the `-c` flag. By default this will be `<beatname>.yml`
|
|
func GetDefaultCfgfile() string {
|
|
if len(configfiles.List()) == 0 {
|
|
return ""
|
|
}
|
|
|
|
cfg := configfiles.List()[0]
|
|
cfgpath := GetPathConfig()
|
|
|
|
if !filepath.IsAbs(cfg) {
|
|
return filepath.Join(cfgpath, cfg)
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
// HandleFlags adapts default config settings based on command line flags.
|
|
func HandleFlags() error {
|
|
// default for the home path is the binary location
|
|
home, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
|
if err != nil {
|
|
if *homePath == "" {
|
|
return fmt.Errorf("The absolute path to %s could not be obtained. %v",
|
|
os.Args[0], err)
|
|
}
|
|
home = *homePath
|
|
}
|
|
|
|
defaults.SetString("path.home", -1, home)
|
|
|
|
if len(overwrites.GetFields()) > 0 {
|
|
overwrites.PrintDebugf("CLI setting overwrites (-E flag):")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Deprecated: Please use Load().
|
|
//
|
|
// Read reads the configuration from a YAML file into the given interface
|
|
// structure. If path is empty this method reads from the configuration
|
|
// file specified by the '-c' command line flag.
|
|
func Read(out interface{}, path string) error {
|
|
config, err := Load(path, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return config.Unpack(out)
|
|
}
|
|
|
|
// Load reads the configuration from a YAML file structure. If path is empty
|
|
// this method reads from the configuration file specified by the '-c' command
|
|
// line flag.
|
|
func Load(path string, beatOverrides *common.Config) (*common.Config, error) {
|
|
var config *common.Config
|
|
var err error
|
|
|
|
cfgpath := GetPathConfig()
|
|
|
|
if path == "" {
|
|
list := []string{}
|
|
for _, cfg := range configfiles.List() {
|
|
if !filepath.IsAbs(cfg) {
|
|
list = append(list, filepath.Join(cfgpath, cfg))
|
|
} else {
|
|
list = append(list, cfg)
|
|
}
|
|
}
|
|
config, err = common.LoadFiles(list...)
|
|
} else {
|
|
if !filepath.IsAbs(path) {
|
|
path = filepath.Join(cfgpath, path)
|
|
}
|
|
config, err = common.LoadFile(path)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if beatOverrides != nil {
|
|
config, err = common.MergeConfigs(
|
|
defaults,
|
|
beatOverrides,
|
|
config,
|
|
overwrites,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
config, err = common.MergeConfigs(
|
|
defaults,
|
|
config,
|
|
overwrites,
|
|
)
|
|
}
|
|
|
|
config.PrintDebugf("Complete configuration loaded:")
|
|
return config, nil
|
|
}
|
|
|
|
// LoadList loads a list of configs data from the given file.
|
|
func LoadList(file string) ([]*common.Config, error) {
|
|
logp.Debug("cfgfile", "Load config from file: %s", file)
|
|
rawConfig, err := common.LoadFile(file)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid config: %s", err)
|
|
}
|
|
|
|
var c []*common.Config
|
|
err = rawConfig.Unpack(&c)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading configuration from file %s: %s", file, err)
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// GetPathConfig returns ${path.config}. If ${path.config} is not set, ${path.home} is returned.
|
|
func GetPathConfig() string {
|
|
if *configPath != "" {
|
|
return *configPath
|
|
} else if *homePath != "" {
|
|
return *homePath
|
|
}
|
|
// TODO: Do we need this or should we always return *homePath?
|
|
return ""
|
|
}
|
|
|
|
// IsTestConfig returns whether or not this is configuration used for testing
|
|
func IsTestConfig() bool {
|
|
return *testConfig
|
|
}
|