// Parse is used to parse the specified ACL rules into an // intermediary set of policies, before being compiled into // the ACL func Parse(rules string) (*Policy, error) { // Decode the rules p := &Policy{Raw: rules} if err := hcl.Decode(p, rules); err != nil { return nil, fmt.Errorf("Failed to parse ACL rules: %v", err) } // Validate the path policy for _, pp := range p.Paths { // Strip the glob character if found if strings.HasSuffix(pp.Prefix, "*") { pp.Prefix = strings.TrimSuffix(pp.Prefix, "*") pp.Glob = true } // Check the policy is valid switch pp.Policy { case PathPolicyDeny: case PathPolicyRead: case PathPolicyWrite: case PathPolicySudo: default: return nil, fmt.Errorf("Invalid path policy: %#v", pp) } } return p, nil }
func LoadServices(root string) (d []Config, err error) { files, _ := filepath.Glob(root + "/*.hcl") for _, file := range files { data, err := readFile(file) if err != nil { return nil, err } var deploy ServiceFile err = hcl.Decode(&deploy, data) if err != nil { return nil, err } for i, service := range deploy.Services { for key, value := range service.RawArtifact { value["type"] = key deploy.Services[i].Artifact = value } } d = append(d, deploy.Services...) } return }
func applyConfigFile(options *Options, filePath string) error { filePath = expandHomeDir(filePath) if _, err := os.Stat(filePath); os.IsNotExist(err) { return err } fileString := []byte{} log.Printf("Loading config file at: %s", filePath) fileString, err := ioutil.ReadFile(filePath) if err != nil { return err } config := make(map[string]interface{}) hcl.Decode(&config, string(fileString)) o := structs.New(options) for _, name := range o.Names() { configName := strings.ToLower(strings.Join(camelcase.Split(name), "_")) if val, ok := config[configName]; ok { field, ok := o.FieldOk(name) if !ok { return errors.New("No such field: " + name) } err := field.Set(val) if err != nil { return err } } } return nil }
//Load provides loading of configuration file func Load(path string, item interface{}) error { data, err := ioutil.ReadFile(path) if err != nil { return err } switch checkPath(path) { case jsontype: err := json.Unmarshal([]byte(data), item) if err != nil { return err } return nil case yamltype: err := yaml.Unmarshal([]byte(data), item) if err != nil { return err } return nil case hcltype: err := hcl.Decode(item, string(data)) if err != nil { return err } return nil default: return fmt.Errorf("Failed to load: This type is unknown") } }
// Parse is used to parse the specified ACL rules into an // intermediary set of policies, before being compiled into // the ACL func Parse(rules string) (*Policy, error) { // Decode the rules p := &Policy{} if rules == "" { // Hot path for empty rules return p, nil } if err := hcl.Decode(p, rules); err != nil { return nil, fmt.Errorf("Failed to parse ACL rules: %v", err) } // Validate the key policy for _, kp := range p.Keys { switch kp.Policy { case KeyPolicyDeny: case KeyPolicyRead: case KeyPolicyWrite: default: return nil, fmt.Errorf("Invalid key policy: %#v", kp) } } // Validate the service policy for _, sp := range p.Services { switch sp.Policy { case ServicePolicyDeny: case ServicePolicyRead: case ServicePolicyWrite: default: return nil, fmt.Errorf("Invalid service policy: %#v", sp) } } // Validate the user event policies for _, ep := range p.Events { switch ep.Policy { case EventPolicyRead: case EventPolicyWrite: case EventPolicyDeny: default: return nil, fmt.Errorf("Invalid event policy: %#v", ep) } } // Validate the keyring policy switch p.Keyring { case KeyringPolicyRead: case KeyringPolicyWrite: case KeyringPolicyDeny: case "": // Special case to allow omitting the keyring policy default: return nil, fmt.Errorf("Invalid keyring policy: %#v", p.Keyring) } return p, nil }
func FromString(filename string, contents string) (*Config, error) { config := Config{} err := hcl.Decode(&config, contents) if err != nil { return nil, err } config.SourceFilename = filename return &config, nil }
func LoadTerraformConfig(path string) (*TerraformConfig, error) { var value TerraformConfig if _, err := os.Stat(path); err != nil { return nil, err } err := hcl.Decode(&value, readFile(path)) if err != nil { return nil, err } return &value, nil }
// Parse is used to parse the specified ACL rules into an // intermediary set of policies, before being compiled into // the ACL func Parse(rules string) (*Policy, error) { // Decode the rules p := &Policy{} if rules == "" { // Hot path for empty rules return p, nil } if err := hcl.Decode(p, rules); err != nil { return nil, fmt.Errorf("Failed to parse ACL rules: %v", err) } // Validate the key policy for _, kp := range p.Keys { if !isPolicyValid(kp.Policy) { return nil, fmt.Errorf("Invalid key policy: %#v", kp) } } // Validate the service policy for _, sp := range p.Services { if !isPolicyValid(sp.Policy) { return nil, fmt.Errorf("Invalid service policy: %#v", sp) } } // Validate the user event policies for _, ep := range p.Events { if !isPolicyValid(ep.Policy) { return nil, fmt.Errorf("Invalid event policy: %#v", ep) } } // Validate the prepared query policies for _, pq := range p.PreparedQueries { if !isPolicyValid(pq.Policy) { return nil, fmt.Errorf("Invalid query policy: %#v", pq) } } // Validate the keyring policy - this one is allowed to be empty if p.Keyring != "" && !isPolicyValid(p.Keyring) { return nil, fmt.Errorf("Invalid keyring policy: %#v", p.Keyring) } // Validate the operator policy - this one is allowed to be empty if p.Operator != "" && !isPolicyValid(p.Operator) { return nil, fmt.Errorf("Invalid operator policy: %#v", p.Operator) } return p, nil }
func LoadConfigFile(configFile string) Config { var conf Config configData, err := ioutil.ReadFile(configFile) if err != nil { log.Fatalf("Error: Couldn't read config file %s: %s", configFile, err) } err = hcl.Decode(&conf, string(configData)) if err != nil { log.Fatalf("Error parsing config file %s: %s", configFile, err) } return conf }
func InitializeConfig() *Config { var cfg Config cfgData, err := ioutil.ReadFile(CfgFile) if err != nil { log.Fatalln("Unable to locate Config File. make sure you specify it using the --config flag") return nil } err = hcl.Decode(&cfg, string(cfgData)) if err != nil { log.Fatalln("Unable to parse Config File.") return nil } return &cfg }
// parseVariableAsHCL parses the value of a single variable as would have been specified // on the command line via -var or in an environment variable named TF_VAR_x, where x is // the name of the variable. In order to get around the restriction of HCL requiring a // top level object, we prepend a sentinel key, decode the user-specified value as its // value and pull the value back out of the resulting map. func parseVariableAsHCL(name string, input string, targetType config.VariableType) (interface{}, error) { // expecting a string so don't decode anything, just strip quotes if targetType == config.VariableTypeString { return strings.Trim(input, `"`), nil } // return empty types if strings.TrimSpace(input) == "" { switch targetType { case config.VariableTypeList: return []interface{}{}, nil case config.VariableTypeMap: return make(map[string]interface{}), nil } } const sentinelValue = "SENTINEL_TERRAFORM_VAR_OVERRIDE_KEY" inputWithSentinal := fmt.Sprintf("%s = %s", sentinelValue, input) var decoded map[string]interface{} err := hcl.Decode(&decoded, inputWithSentinal) if err != nil { return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL: %s", name, input, err) } if len(decoded) != 1 { return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. Only one value may be specified.", name, input) } parsedValue, ok := decoded[sentinelValue] if !ok { return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) } switch targetType { case config.VariableTypeList: return parsedValue, nil case config.VariableTypeMap: if list, ok := parsedValue.([]map[string]interface{}); ok { return list[0], nil } return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) default: panic(fmt.Errorf("unknown type %s", targetType.Printable())) } }
// Parse is used to parse the specified ACL rules into an // intermediary set of policies, before being compiled into // the ACL func Parse(rules string) (*Policy, error) { // Decode the rules p := &Policy{Raw: rules} if err := hcl.Decode(p, rules); err != nil { return nil, fmt.Errorf("Failed to parse ACL rules: %v", err) } // Validate the path policy for _, pc := range p.Paths { // Strip the glob character if found if strings.HasSuffix(pc.Prefix, "*") { pc.Prefix = strings.TrimSuffix(pc.Prefix, "*") pc.Glob = true } // Map old-style policies into capabilities switch pc.Policy { case OldDenyPathPolicy: pc.Capabilities = []string{DenyCapability} case OldReadPathPolicy: pc.Capabilities = append(pc.Capabilities, []string{ReadCapability, ListCapability}...) case OldWritePathPolicy: pc.Capabilities = append(pc.Capabilities, []string{CreateCapability, ReadCapability, UpdateCapability, DeleteCapability, ListCapability}...) case OldSudoPathPolicy: pc.Capabilities = append(pc.Capabilities, []string{CreateCapability, ReadCapability, UpdateCapability, DeleteCapability, ListCapability, SudoCapability}...) } // Initialize the map pc.CapabilitiesBitmap = 0 for _, cap := range pc.Capabilities { switch cap { // If it's deny, don't include any other capability case DenyCapability: pc.Capabilities = []string{DenyCapability} pc.CapabilitiesBitmap = DenyCapabilityInt goto PathFinished case CreateCapability, ReadCapability, UpdateCapability, DeleteCapability, ListCapability, SudoCapability: pc.CapabilitiesBitmap |= cap2Int[cap] default: return nil, fmt.Errorf("Invalid capability: %#v", pc) } } PathFinished: } return p, nil }
func applyConfigFile(options *Options, filePath string) error { filePath = ExpandHomeDir(filePath) if _, err := os.Stat(filePath); os.IsNotExist(err) { return err } fileString := []byte{} log.Printf("Loading config file at: %s", filePath) fileString, err := ioutil.ReadFile(filePath) if err != nil { return err } config := make(map[string]interface{}) hcl.Decode(&config, string(fileString)) o := structs.New(options) for _, name := range o.Names() { configName := strings.ToLower(strings.Join(camelcase.Split(name), "_")) if val, ok := config[configName]; ok { field, ok := o.FieldOk(name) if !ok { return errors.New("No such option: " + name) } var err error if name == "Preferences" { prefs := val.([]map[string]interface{})[0] htermPrefs := make(map[string]interface{}) for key, value := range prefs { htermPrefs[strings.Replace(key, "_", "-", -1)] = value } err = field.Set(htermPrefs) } else { err = field.Set(val) } if err != nil { return err } } } return nil }
func initConfig() Config { var configPath = os.Getenv("HOME") var c Config var err error config, err := ioutil.ReadFile(filepath.Join(configPath, configFile)) if err != nil { log.Printf("Error parsing config: %s", err) configUsage() } err = hcl.Decode(&c, string(config)) if err != nil { log.Fatalf("Configuration decode error: %s", err) } return c }
func readConfig() *Config { bts, err := ioutil.ReadFile(Path()) if err != nil { printer.SayErr("Could not read %s", Path()) os.Exit(1) } var cfg *Config defaults := DefaultConfig() err = hcl.Decode(&cfg, string(bts[:])) if err != nil { printer.SayErr("[dcdr] config parse error %+v", err) os.Exit(1) } if cfg.Namespace == "" { cfg.Namespace = defaults.Namespace } if cfg.Username == "" { cfg.Username = defaults.Username } if cfg.Watcher.OutputPath == "" { cfg.Watcher.OutputPath = defaults.Watcher.OutputPath } if cfg.Server.Host == "" { cfg.Server.Host = defaults.Server.Host } if cfg.Server.Endpoint == "" { cfg.Server.Endpoint = defaults.Server.Endpoint } if cfg.Server.JSONRoot == "" { cfg.Server.JSONRoot = defaults.Server.JSONRoot } return cfg }
func ApplyConfigFile(options *Options, filePath string) error { filePath = ExpandHomeDir(filePath) if _, err := os.Stat(filePath); os.IsNotExist(err) { return err } fileString := []byte{} log.Printf("Loading config file at: %s", filePath) fileString, err := ioutil.ReadFile(filePath) if err != nil { return err } if err := hcl.Decode(options, string(fileString)); err != nil { return err } return nil }
// Parse is used to parse the specified ACL rules into an // intermediary set of policies, before being compiled into // the ACL func Parse(rules string) (*Policy, error) { // Decode the rules p := &Policy{Raw: rules} if err := hcl.Decode(p, rules); err != nil { return nil, fmt.Errorf("Failed to parse ACL rules: %v", err) } // Validate the path policy for _, pp := range p.Paths { switch pp.Policy { case PathPolicyDeny: case PathPolicyRead: case PathPolicyWrite: case PathPolicySudo: default: return nil, fmt.Errorf("Invalid path policy: %#v", pp) } } return p, nil }
func loadProfileFile(options *Options) (map[string]interface{}, error) { prefString := []byte{} prefPath := options.ProfileFile if options.ProfileFile == DefaultOptions.ProfileFile { prefPath = os.Getenv("HOME") + "/.gotty.prf" } if _, err := os.Stat(prefPath); os.IsNotExist(err) { if options.ProfileFile != DefaultOptions.ProfileFile { return nil, err } } else { log.Printf("Loading profile path: %s", prefPath) prefString, _ = ioutil.ReadFile(prefPath) } var prefMap map[string]interface{} err := hcl.Decode(&prefMap, string(prefString)) if err != nil { return nil, err } return prefMap, nil }
func main() { configFile := flag.String("config", "terf.conf", "path to the terf configuration file") configProfile := flag.String("profile", "development", "configuration profile to use") flag.Parse() // Load the configuration file. var config Config p, err := ioutil.ReadFile(*configFile) if err != nil { glog.Fatalln("failed to read config file:", err) } if err := hcl.Decode(&config, string(p)); err != nil { glog.Fatalln("failed to decode config file:", err) } profile, ok := config[*configProfile] if !ok { glog.Fatalf("no such config profile %q", *configProfile) } glog.Infoln("connecting to database") tplGlob := filepath.Join(profile.Terf.TemplateDir, "*.html") glog.Infof("loading templates %q", tplGlob) Templates, err = template.ParseGlob(tplGlob) if err != nil { glog.Fatalln(err) } http.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir(profile.Terf.StaticDir)))) http.HandleFunc("/", handleIndex) glog.Infoln("listening on", profile.Terf.ListenAddr) if err := http.ListenAndServe(profile.Terf.ListenAddr, nil); err != nil { glog.Fatalln(err) } glog.Infoln("terminated gracefully") }
func (cp ConfigParser) UpdateConfig(hclText string, result *Config) error { var tmp Config tmp = *result if err := hcl.Decode(&tmp, hclText); err != nil { return err } if tmp.InfluxDB.CheckLapse == 0 { tmp.InfluxDB.CheckLapse = DefaultConfig.InfluxDB.CheckLapse } if cp.AllowDNS && tmp.MesosDNS != nil { resolver := NewDNSResolver(&tmp) if err := resolver.resolve(); err != nil { return err } } log.Printf("%+v\n", tmp) *result = tmp return nil }
// parseVariableAsHCL parses the value of a single variable as would have been specified // on the command line via -var or in an environment variable named TF_VAR_x, where x is // the name of the variable. In order to get around the restriction of HCL requiring a // top level object, we prepend a sentinel key, decode the user-specified value as its // value and pull the value back out of the resulting map. func parseVariableAsHCL(name string, input interface{}, targetType config.VariableType) (interface{}, error) { if targetType == config.VariableTypeString { return input, nil } const sentinelValue = "SENTINEL_TERRAFORM_VAR_OVERRIDE_KEY" inputWithSentinal := fmt.Sprintf("%s = %s", sentinelValue, input) var decoded map[string]interface{} err := hcl.Decode(&decoded, inputWithSentinal) if err != nil { return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL: %s", name, input, err) } if len(decoded) != 1 { return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. Only one value may be specified.", name, input) } parsedValue, ok := decoded[sentinelValue] if !ok { return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) } switch targetType { case config.VariableTypeList: return parsedValue, nil case config.VariableTypeMap: if list, ok := parsedValue.([]map[string]interface{}); ok { return list[0], nil } return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) default: panic(fmt.Errorf("unknown type %s", targetType)) } }
// Parse is used to parse the specified ACL rules into an // intermediary set of policies, before being compiled into // the ACL func Parse(rules string) (*Policy, error) { // Decode the rules p := &Policy{} if rules == "" { // Hot path for empty rules return p, nil } if err := hcl.Decode(p, rules); err != nil { return nil, fmt.Errorf("Failed to parse ACL rules: %v", err) } // Validate the key policy for _, kp := range p.Keys { switch kp.Policy { case KeyPolicyDeny: case KeyPolicyRead: case KeyPolicyWrite: default: return nil, fmt.Errorf("Invalid key policy: %#v", kp) } } return p, nil }
// ParseConfig reads the configuration file at the given path and returns a new // Config struct with the data populated. func ParseConfig(path string) (*Config, error) { var errs *multierror.Error // Read the contents of the file contents, err := ioutil.ReadFile(path) if err != nil { return nil, fmt.Errorf("error reading config at %q: %s", path, err) } // Parse the file (could be HCL or JSON) var shadow interface{} if err := hcl.Decode(&shadow, string(contents)); err != nil { return nil, fmt.Errorf("error decoding config at %q: %s", path, err) } // Convert to a map and flatten the keys we want to flatten parsed, ok := shadow.(map[string]interface{}) if !ok { return nil, fmt.Errorf("error converting config at %q", path) } flattenKeys(parsed, []string{"auth", "ssl", "syslog", "vault", "deduplicate"}) // Create a new, empty config config := new(Config) // Use mapstructure to populate the basic config fields metadata := new(mapstructure.Metadata) decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( watch.StringToWaitDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), mapstructure.StringToTimeDurationHookFunc(), ), ErrorUnused: true, Metadata: metadata, Result: config, }) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } if err := decoder.Decode(parsed); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Store a reference to the path where this config was read from config.Path = path // Ensure there's a default value for the template's file permissions for _, t := range config.ConfigTemplates { if t.Perms == 0000 { t.Perms = defaultFilePerms } } // Update the list of set keys if config.setKeys == nil { config.setKeys = make(map[string]struct{}) } for _, key := range metadata.Keys { if _, ok := config.setKeys[key]; !ok { config.setKeys[key] = struct{}{} } } config.setKeys["path"] = struct{}{} d := DefaultConfig() d.Merge(config) config = d return config, errs.ErrorOrNil() }
// ParseConfig reads the configuration file at the given path and returns a new // Config struct with the data populated. func ParseConfig(path string) (*Config, error) { var errs *multierror.Error // Read the contents of the file contents, err := ioutil.ReadFile(path) if err != nil { return nil, fmt.Errorf("error reading config at %q: %s", path, err) } // Parse the file (could be HCL or JSON) var shadow interface{} if err := hcl.Decode(&shadow, string(contents)); err != nil { return nil, fmt.Errorf("error decoding config at %q: %s", path, err) } // Convert to a map and flatten the keys we want to flatten parsed, ok := shadow.(map[string]interface{}) if !ok { return nil, fmt.Errorf("error converting config at %q", path) } flattenKeys(parsed, []string{"auth", "ssl", "syslog"}) // Parse the prefixes if raw, ok := parsed["prefixes"]; ok { if typed, ok := raw.([]interface{}); !ok { err = fmt.Errorf("error converting prefixes to []interface{} at %q, was %T", path, raw) errs = multierror.Append(errs, err) delete(parsed, "prefixes") } else { prefixes := make([]*dep.StoreKeyPrefix, 0, len(typed)) for _, p := range typed { if s, ok := p.(string); ok { if prefix, err := dep.ParseStoreKeyPrefix(s); err != nil { err = fmt.Errorf("error parsing prefix %q at %q: %s", p, path, err) errs = multierror.Append(errs, err) } else { prefixes = append(prefixes, prefix) } } else { err = fmt.Errorf("error converting %T to string", p) errs = multierror.Append(errs, err) delete(parsed, "prefixes") } } parsed["prefixes"] = prefixes } } // Parse the wait component if raw, ok := parsed["wait"]; ok { if typed, ok := raw.(string); !ok { err = fmt.Errorf("error converting wait to string at %q", path) errs = multierror.Append(errs, err) delete(parsed, "wait") } else { if wait, err := watch.ParseWait(typed); err != nil { err = fmt.Errorf("error parsing wait at %q: %s", path, err) errs = multierror.Append(errs, err) delete(parsed, "wait") } else { parsed["wait"] = map[string]time.Duration{ "min": wait.Min, "max": wait.Max, } } } } // Create a new, empty config config := new(Config) // Use mapstructure to populate the basic config fields metadata := new(mapstructure.Metadata) decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.StringToSliceHookFunc(","), mapstructure.StringToTimeDurationHookFunc(), ), ErrorUnused: true, Metadata: metadata, Result: config, }) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } if err := decoder.Decode(parsed); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Store a reference to the path where this config was read from config.Path = path // Update the list of set keys if config.setKeys == nil { config.setKeys = make(map[string]struct{}) } for _, key := range metadata.Keys { if _, ok := config.setKeys[key]; !ok { config.setKeys[key] = struct{}{} } } config.setKeys["path"] = struct{}{} d := DefaultConfig() d.Merge(config) config = d return config, errs.ErrorOrNil() }
// ParseConfig reads the configuration file at the given path and returns a new // Config struct with the data populated. func ParseConfig(path string) (*Config, error) { var errs *multierror.Error // Read the contents of the file contents, err := ioutil.ReadFile(path) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Parse the file (could be HCL or JSON) var parsed interface{} if err := hcl.Decode(&parsed, string(contents)); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Create a new, empty config config := &Config{} // Use mapstructure to populate the basic config fields decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ ErrorUnused: true, Metadata: nil, Result: config, }) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } if err := decoder.Decode(parsed); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Store a reference to the path where this config was read from config.Path = path // Parse the prefix sources for _, prefix := range config.Prefixes { parsed, err := dep.ParseStoreKeyPrefix(prefix.SourceRaw) if err != nil { errs = multierror.Append(errs, err) continue } prefix.Source = parsed // If no destination was given, default to the prefix if prefix.Destination == "" { prefix.Destination = parsed.Prefix } } // Parse the MaxStale component if raw := config.MaxStaleRaw; raw != "" { stale, err := time.ParseDuration(raw) if err == nil { config.MaxStale = stale } else { errs = multierror.Append(errs, fmt.Errorf("max_stale invalid: %v", err)) } } // Extract the last Auth block if len(config.AuthRaw) > 0 { config.Auth = config.AuthRaw[len(config.AuthRaw)-1] } // Extract the last SSL block if len(config.SSLRaw) > 0 { config.SSL = config.SSLRaw[len(config.SSLRaw)-1] } // Extract the last Syslog block if len(config.SyslogRaw) > 0 { config.Syslog = config.SyslogRaw[len(config.SyslogRaw)-1] } // Parse the Retry component if raw := config.RetryRaw; raw != "" { retry, err := time.ParseDuration(raw) if err == nil { config.Retry = retry } else { errs = multierror.Append(errs, fmt.Errorf("retry invalid: %v", err)) } } // Parse the Wait component if raw := config.WaitRaw; raw != "" { wait, err := watch.ParseWait(raw) if err == nil { config.Wait = wait } else { errs = multierror.Append(errs, fmt.Errorf("wait invalid: %v", err)) } } return config, errs.ErrorOrNil() }
// ParseConfig reads the configuration file at the given path and returns a new // Config struct with the data populated. func ParseConfig(path string) (*Config, error) { var errs *multierror.Error // Read the contents of the file contents, err := ioutil.ReadFile(path) if err != nil { return nil, fmt.Errorf("error reading config at %q: %s", path, err) } // Parse the file (could be HCL or JSON) var shadow interface{} if err := hcl.Decode(&shadow, string(contents)); err != nil { return nil, fmt.Errorf("error decoding config at %q: %s", path, err) } // Convert to a map and flatten the keys we want to flatten parsed, ok := shadow.(map[string]interface{}) if !ok { return nil, fmt.Errorf("error converting config at %q", path) } flattenKeys(parsed, []string{"auth", "ssl", "syslog", "vault"}) // if raw, ok := parsed["max_stale"]; ok { if typed, ok := raw.(string); !ok { err = fmt.Errorf("error converting max_stale to string at %q", path) errs = multierror.Append(errs, err) delete(parsed, "max_stale") } else { if stale, err := time.ParseDuration(typed); err != nil { err = fmt.Errorf("error parsing max_stale at %q: %s", path, err) errs = multierror.Append(errs, err) delete(parsed, "max_stale") } else { parsed["max_stale"] = stale } } } if raw, ok := parsed["retry"]; ok { if typed, ok := raw.(string); !ok { err = fmt.Errorf("error converting retry to string at %q", path) errs = multierror.Append(errs, err) delete(parsed, "retry") } else { if stale, err := time.ParseDuration(typed); err != nil { err = fmt.Errorf("error parsing retry at %q: %s", path, err) errs = multierror.Append(errs, err) delete(parsed, "retry") } else { parsed["retry"] = stale } } } if raw, ok := parsed["wait"]; ok { if typed, ok := raw.(string); !ok { err = fmt.Errorf("error converting wait to string at %q", path) errs = multierror.Append(errs, err) delete(parsed, "wait") } else { if wait, err := watch.ParseWait(typed); err != nil { err = fmt.Errorf("error parsing wait at %q: %s", path, err) errs = multierror.Append(errs, err) delete(parsed, "wait") } else { parsed["wait"] = map[string]time.Duration{ "min": wait.Min, "max": wait.Max, } } } } // Create a new, empty config config := new(Config) // Use mapstructure to populate the basic config fields metadata := new(mapstructure.Metadata) decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ ErrorUnused: true, Metadata: metadata, Result: config, }) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } if err := decoder.Decode(parsed); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Store a reference to the path where this config was read from config.Path = path // Update the list of set keys if config.setKeys == nil { config.setKeys = make(map[string]struct{}) } for _, key := range metadata.Keys { if _, ok := config.setKeys[key]; !ok { config.setKeys[key] = struct{}{} } } config.setKeys["path"] = struct{}{} d := DefaultConfig() d.Merge(config) config = d return config, errs.ErrorOrNil() }
// Parse parses the given string contents as a config func Parse(s string) (*Config, error) { var errs *multierror.Error // Parse the file (could be HCL or JSON) var shadow interface{} if err := hcl.Decode(&shadow, s); err != nil { return nil, fmt.Errorf("error decoding config: %s", err) } // Convert to a map and flatten the keys we want to flatten parsed, ok := shadow.(map[string]interface{}) if !ok { return nil, fmt.Errorf("error converting config") } flattenKeys(parsed, []string{ "auth", "ssl", "syslog", "exec", "vault", "deduplicate", }) // Deprecations if vault, ok := parsed["vault"].(map[string]interface{}); ok { if val, ok := vault["renew"]; ok { log.Println(`[WARN] vault.renew has been renamed to vault.renew_token. ` + `Update your configuration files and change "renew" to "renew_token".`) vault["renew_token"] = val delete(vault, "renew") } } // Create a new, empty config config := new(Config) // Use mapstructure to populate the basic config fields metadata := new(mapstructure.Metadata) decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( StringToFileModeFunc(), signals.StringToSignalFunc(), watch.StringToWaitDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), mapstructure.StringToTimeDurationHookFunc(), ), ErrorUnused: true, Metadata: metadata, Result: config, }) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } if err := decoder.Decode(parsed); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Explicitly check for the nil signal and set the value back to nil if config.ReloadSignal == signals.SIGNIL { config.ReloadSignal = nil } if config.DumpSignal == signals.SIGNIL { config.DumpSignal = nil } if config.KillSignal == signals.SIGNIL { config.KillSignal = nil } if config.Exec != nil { if config.Exec.ReloadSignal == signals.SIGNIL { config.Exec.ReloadSignal = nil } if config.Exec.KillSignal == signals.SIGNIL { config.Exec.KillSignal = nil } } // Setup default values for templates for _, t := range config.ConfigTemplates { // Ensure there's a default value for the template's file permissions if t.Perms == 0000 { t.Perms = DefaultFilePerms } // Ensure we have a default command timeout if t.CommandTimeout == 0 { t.CommandTimeout = DefaultCommandTimeout } // Set up a default zero wait, which disables it for this // template. if t.Wait == nil { t.Wait = &watch.Wait{} } } // Update the list of set keys if config.setKeys == nil { config.setKeys = make(map[string]struct{}) } for _, key := range metadata.Keys { if _, ok := config.setKeys[key]; !ok { config.setKeys[key] = struct{}{} } } config.setKeys["path"] = struct{}{} d := DefaultConfig() d.Merge(config) config = d return config, errs.ErrorOrNil() }
// Parse parses the given string contents as a config func Parse(s string) (*Config, error) { var shadow interface{} if err := hcl.Decode(&shadow, s); err != nil { return nil, errors.Wrap(err, "error decoding config") } // Convert to a map and flatten the keys we want to flatten parsed, ok := shadow.(map[string]interface{}) if !ok { return nil, errors.New("error converting config") } flattenKeys(parsed, []string{ "auth", "consul", "consul.auth", "consul.retry", "consul.ssl", "deduplicate", "env", "exec", "exec.env", "ssl", "syslog", "vault", "vault.retry", "vault.ssl", "wait", }) // FlattenFlatten keys belonging to the templates. We cannot do this above // because it is an array of tmeplates. if templates, ok := parsed["template"].([]map[string]interface{}); ok { for _, template := range templates { flattenKeys(template, []string{ "env", "exec", "exec.env", "wait", }) } } // TODO: Deprecations if vault, ok := parsed["vault"].(map[string]interface{}); ok { if val, ok := vault["renew"]; ok { log.Println(`[WARN] vault.renew has been renamed to vault.renew_token. ` + `Update your configuration files and change "renew" to "renew_token".`) vault["renew_token"] = val delete(vault, "renew") } } if auth, ok := parsed["auth"].(map[string]interface{}); ok { log.Println("[WARN] auth has been moved under the consul stanza. " + "Update your configuration files and place auth inside consul { }.") if _, ok := parsed["consul"]; !ok { parsed["consul"] = make(map[string]interface{}) } parsed["consul"].(map[string]interface{})["auth"] = auth delete(parsed, "auth") } if retry, ok := parsed["retry"].(string); ok { log.Println("[WARN] retry has been moved under the consul stanza. " + "Update your configuration files and place retry inside consul { }.") if _, ok := parsed["consul"]; !ok { parsed["consul"] = make(map[string]interface{}) } parsed["consul"].(map[string]interface{})["retry"] = map[string]interface{}{ "backoff": retry, } delete(parsed, "retry") } if ssl, ok := parsed["ssl"].(map[string]interface{}); ok { log.Println("[WARN] ssl has been moved under the consul stanza. " + "Update your configuration files and place ssl inside consul { }.") if _, ok := parsed["consul"]; !ok { parsed["consul"] = make(map[string]interface{}) } parsed["consul"].(map[string]interface{})["ssl"] = ssl delete(parsed, "ssl") } if token, ok := parsed["token"].(string); ok { log.Println("[WARN] token has been moved under the consul stanza. " + "Update your configuration files and place token inside consul { }.") if _, ok := parsed["consul"]; !ok { parsed["consul"] = make(map[string]interface{}) } parsed["consul"].(map[string]interface{})["token"] = token delete(parsed, "token") } // Create a new, empty config var c Config // Use mapstructure to populate the basic config fields var md mapstructure.Metadata decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( ConsulStringToStructFunc(), StringToFileModeFunc(), signals.StringToSignalFunc(), StringToWaitDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), mapstructure.StringToTimeDurationHookFunc(), ), ErrorUnused: true, Metadata: &md, Result: &c, }) if err != nil { return nil, errors.Wrap(err, "mapstructure decoder creation failed") } if err := decoder.Decode(parsed); err != nil { return nil, errors.Wrap(err, "mapstructure decode failed") } return &c, nil }
// ParseConfig reads the configuration file at the given path and returns a new // Config struct with the data populated. func ParseConfig(path string) (*Config, error) { var errs *multierror.Error // Read the contents of the file contents, err := ioutil.ReadFile(path) if err != nil { return nil, fmt.Errorf("error reading config at %q: %s", path, err) } // Parse the file (could be HCL or JSON) var shadow interface{} if err := hcl.Decode(&shadow, string(contents)); err != nil { return nil, fmt.Errorf("error decoding config at %q: %s", path, err) } // Convert to a map and flatten the keys we want to flatten parsed, ok := shadow.(map[string]interface{}) if !ok { return nil, fmt.Errorf("error converting config at %q", path) } flattenKeys(parsed, []string{"auth", "ssl", "syslog", "vault"}) // Create a new, empty config config := new(Config) // Use mapstructure to populate the basic config fields metadata := new(mapstructure.Metadata) decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( watch.StringToWaitDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), mapstructure.StringToTimeDurationHookFunc(), ), ErrorUnused: true, Metadata: metadata, Result: config, }) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } if err := decoder.Decode(parsed); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Store a reference to the path where this config was read from config.Path = path // Handle deprecations if len(config.PrefixesOld) > 0 { log.Printf(`[WARN] Specifying the key "prefixes" in the configuration is `+ `no longer supported. Please specify each prefix individually using `+ `the key "prefix" (config at %s)`, path) prefixes := make([]*ConfigPrefix, 0, len(config.PrefixesOld)) for _, prefix := range config.PrefixesOld { prefixes = append(prefixes, &ConfigPrefix{ Path: prefix, }) } config.Prefixes = append(prefixes, config.Prefixes...) config.PrefixesOld = nil } // Update the list of set keys if config.setKeys == nil { config.setKeys = make(map[string]struct{}) } for _, key := range metadata.Keys { if _, ok := config.setKeys[key]; !ok { config.setKeys[key] = struct{}{} } } config.setKeys["path"] = struct{}{} d := DefaultConfig() d.Merge(config) config = d return config, errs.ErrorOrNil() }
func (hclParser *HCLParser) Parse(content []byte, c map[string]interface{}) error { return hcl.Decode(&c, string(content)) }