Skip to content

Commit

Permalink
Use go.uber.org/config
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewmains12 committed Oct 24, 2019
1 parent 84b27d2 commit 262f771
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 32 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

# 0.14.2 (upcoming)

## Features
- **Config**: support env var expansion using go.uber.org/config.

# 0.14.1

## Features
Expand Down
32 changes: 31 additions & 1 deletion config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,34 @@ std.manifestYamlDoc(lib(cluster, coordinator))
3. Run the following `jsonnet` command. This will generate a file called `generated.yaml` within the directory.
```
make config-gen
```
```

## Configuration Schemas

At this time, each service's configuration is defined as a Go struct in a
corresponding `config` package. For instance, `m3aggregator`'s config is
in [src/cmd/services/m3aggregator/config/config.go](https://github.com/m3db/m3/blob/master/src/cmd/services/m3aggregator/config/config.go).

Validation is done using https://godoc.org/gopkg.in/go-playground/validator.v2 ;
look for `validate` tags.

## Advanced: Environment Variable Interpolation
M3 uses [go.uber.org/config](https://godoc.org/go.uber.org/config) to load
its configuration. This means that we support environment variable interpolation
of configs. For example:

Given the following config:

```
foo: ${MY_ENV_VAR}
```

and an environment of `MY_ENV_VAR=bar`, the interpolated YAML will be:

```
foo: bar
```
.

This can be useful for further tweaking your configuration without generating
different files for every config permutation.
45 changes: 28 additions & 17 deletions src/x/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,12 @@ package config

import (
"errors"
"io/ioutil"
"reflect"
"strings"

"go.uber.org/config"
"go.uber.org/zap"
validator "gopkg.in/validator.v2"
yaml "gopkg.in/yaml.v2"
)

const (
Expand All @@ -42,37 +41,49 @@ var errNoFilesToLoad = errors.New("attempt to load config with no files")
type Options struct {
DisableUnmarshalStrict bool
DisableValidate bool
Expand config.LookupFunc
}

// LoadFile loads a config from a file.
func LoadFile(config interface{}, file string, opts Options) error {
return LoadFiles(config, []string{file}, opts)
func LoadFile(dst interface{}, file string, opts Options) error {
return LoadFiles(dst, []string{file}, opts)
}

// LoadFiles loads a config from list of files. If value for a property is
// present in multiple files, the value from the last file will be applied.
// Validation is done after merging all values.
func LoadFiles(config interface{}, files []string, opts Options) error {
func LoadFiles(dst interface{}, files []string, opts Options) error {
if len(files) == 0 {
return errNoFilesToLoad
}

yamlOpts := make([]config.YAMLOption, 0, len(files))
for _, name := range files {
data, err := ioutil.ReadFile(name)
if err != nil {
return err
}
unmarshal := yaml.UnmarshalStrict
if opts.DisableUnmarshalStrict {
unmarshal = yaml.Unmarshal
}
if err := unmarshal(data, config); err != nil {
return err
}
yamlOpts = append(yamlOpts, config.File(name))
}

if opts.DisableUnmarshalStrict {
yamlOpts = append(yamlOpts, config.Permissive())
}

if opts.Expand != nil {
yamlOpts = append(yamlOpts, config.Expand(opts.Expand))
}

provider, err := config.NewYAML(yamlOpts...)
if err != nil {
return err
}

if err := provider.Get(config.Root).Populate(dst); err != nil {
return err
}

if opts.DisableValidate {
return nil
}
return validator.Validate(config)

return validator.Validate(dst)
}

// deprecationCheck checks the config for deprecated fields and returns any in
Expand Down
Loading

0 comments on commit 262f771

Please sign in to comment.