config.go (129 lines of code) (raw):
package go2chef
/*
Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
*/
import (
"github.com/mitchellh/mapstructure"
"github.com/spf13/pflag"
)
// ConfigSource defines the interface for configuration sources. These can be implemented however you like.
type ConfigSource interface {
// InitFlags sets up command line flags
InitFlags(set *pflag.FlagSet)
// ReadConfig actually reads in the configuration
ReadConfig() (map[string]interface{}, error)
}
var configSourceRegistry = make(map[string]ConfigSource)
// RegisterConfigSource registers a new configuration source plugin
func RegisterConfigSource(name string, cs ConfigSource) {
if _, ok := configSourceRegistry[name]; ok {
panic("ConfigSource " + name + " is already registered")
}
configSourceRegistry[name] = cs
}
// InitializeConfigSourceFlags initializes a flag set with the flags required by
// the currently registered configuration source plugins.
func InitializeConfigSourceFlags(set *pflag.FlagSet) {
for _, cs := range configSourceRegistry {
cs.InitFlags(set)
}
}
// GetConfigSource gets a specified configuration source plugin
func GetConfigSource(name string) ConfigSource {
if cs, ok := configSourceRegistry[name]; ok {
return cs
}
return nil
}
// Config defines the configuration for all of go2chef
type Config struct {
Loggers []Logger
Steps []Step
}
// GetConfig loads and resolves the configuration
func GetConfig(configSourceName string, earlyLogger Logger) (*Config, error) {
EarlyLogger.Printf("loading config from source %s", configSourceName)
// Get the chosen configuration source and read
configSource := GetConfigSource(configSourceName)
if configSource == nil {
return nil, &ErrComponentDoesNotExist{Component: "ConfigSource::" + configSourceName}
}
config, err := configSource.ReadConfig()
if err != nil {
return nil, err
}
cfg := &Config{}
if err := LoadGlobalConfiguration(config); err != nil {
return nil, err
}
loggers, err := GetLoggers(config)
if err != nil {
return nil, err
}
// if we're provided a copy of the early logger used
// before config load, then add it to the logger list
if earlyLogger != nil {
realLoggers := make([]Logger, len(loggers)+1)
copy(realLoggers[1:], loggers)
realLoggers[0] = earlyLogger
loggers = realLoggers
}
cfg.Loggers = loggers
// initialize the global logger!
InitGlobalLogger(cfg.Loggers)
// pull steps
steps, err := GetSteps(config)
if err != nil {
return nil, err
}
cfg.Steps = steps
return cfg, nil
}
// GetLoggers extracts an array of loggers from a config map
func GetLoggers(config map[string]interface{}) ([]Logger, error) {
parse := struct {
Loggers []map[string]interface{} `mapstructure:"loggers"`
}{}
if err := mapstructure.Decode(config, &parse); err != nil {
return nil, err
}
loggers := make([]Logger, 0, len(parse.Loggers))
for _, lconf := range parse.Loggers {
_, ltype, err := GetNameType(lconf)
if err != nil {
return nil, err
}
logger, err := GetLogger(ltype, lconf)
if err != nil {
return nil, err
}
loggers = append(loggers, logger)
}
return loggers, nil
}
// GetSteps extracts an array of steps from a config map
func GetSteps(config map[string]interface{}) ([]Step, error) {
parse := struct {
Steps []map[string]interface{} `mapstructure:"steps"`
}{}
if err := mapstructure.Decode(config, &parse); err != nil {
return nil, err
}
steps := make([]Step, 0, len(parse.Steps))
for _, sconf := range parse.Steps {
_, stype, err := GetNameType(sconf)
if err != nil {
return nil, err
}
step, err := GetStep(stype, sconf)
if err != nil {
return nil, err
}
steps = append(steps, step)
}
return steps, nil
}
// GetSourceFromStepConfig gets a Source from a Step's config map. If there is
// no `source` key, then it will return a nil Source and no error.
func GetSourceFromStepConfig(config map[string]interface{}) (Source, error) {
parse := struct {
Source map[string]interface{} `mapstructure:"source"`
}{}
if err := mapstructure.Decode(config, &parse); err != nil {
return nil, err
}
if parse.Source == nil {
return nil, nil
}
if len(parse.Source) == 0 {
return nil, nil
}
stype, err := GetType(parse.Source)
if err != nil {
return nil, err
}
src, err := GetSource(stype, parse.Source)
if err != nil {
return nil, err
}
return src, nil
}