Example #1
0
// treeFunc returns or accumulates keyPrefix dependencies.
func treeFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, error) {
	return func(s string) ([]*dep.KeyPair, error) {
		result := []*dep.KeyPair{}

		if len(s) == 0 {
			return result, nil
		}

		d, err := dep.NewKVListQuery(s)
		if err != nil {
			return result, err
		}

		used.Add(d)

		// Only return non-empty top-level keys
		if value, ok := b.Recall(d); ok {
			for _, pair := range value.([]*dep.KeyPair) {
				parts := strings.Split(pair.Key, "/")
				if parts[len(parts)-1] != "" {
					result = append(result, pair)
				}
			}
			return result, nil
		}

		missing.Add(d)

		return result, nil
	}
}
Example #2
0
// ParsePrefix parses a prefix of the format "source@dc:destination" into the
// Prefix component.
func ParsePrefix(s string) (*Prefix, error) {
	if len(strings.TrimSpace(s)) < 1 {
		return nil, fmt.Errorf("cannot specify empty prefix declaration")
	}

	parts := strings.SplitN(s, ":", 2)

	var source, destination string
	switch len(parts) {
	case 1:
		source, destination = parts[0], ""
	case 2:
		source, destination = parts[0], parts[1]
	default:
		return nil, fmt.Errorf("invalid format: %q", s)
	}

	if source == "" || !dep.KVListQueryRe.MatchString(source) {
		return nil, fmt.Errorf("invalid format: %q", s)
	}
	m := regexpMatch(dep.KVListQueryRe, source)
	prefix := m["prefix"]
	dc := m["dc"]

	d, err := dep.NewKVListQuery(source)
	if err != nil {
		return nil, err
	}

	if destination == "" {
		destination = prefix
	}

	return &Prefix{
		Dependency:  d,
		Source:      prefix,
		DataCenter:  dc,
		Destination: destination,
	}, nil
}
Example #3
0
// g 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"})

	// Create a new, empty config
	c := new(Config)

	// Use mapstructure to populate the basic config fields
	metadata := new(mapstructure.Metadata)
	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		DecodeHook: mapstructure.ComposeDecodeHookFunc(
			config.StringToWaitDurationHookFunc(),
			mapstructure.StringToSliceHookFunc(","),
			mapstructure.StringToTimeDurationHookFunc(),
		),
		ErrorUnused: true,
		Metadata:    metadata,
		Result:      c,
	})
	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
	c.Path = path

	// Parse the prefix sources
	for _, prefix := range c.Prefixes {
		parsed, err := dep.NewKVListQuery(prefix.Source)
		if err != nil {
			errs = multierror.Append(errs, err)
			continue
		}
		prefix.Dependency = parsed

		// If no destination was given, default to the prefix
		if prefix.Destination == "" {
			prefix.Destination = prefix.Source
		}
	}

	// Update the list of set keys
	if c.setKeys == nil {
		c.setKeys = make(map[string]struct{})
	}
	for _, key := range metadata.Keys {
		if _, ok := c.setKeys[key]; !ok {
			c.setKeys[key] = struct{}{}
		}
	}
	c.setKeys["path"] = struct{}{}

	d := DefaultConfig()
	d.Merge(c)
	c = d

	return c, errs.ErrorOrNil()
}