// 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 }