Home > database >  Use environment variables in YAML file
Use environment variables in YAML file

Time:10-23

I have a GO script that generates pager duty on call reporting, and it has its own config.yaml file as such:

# PagerDuty auth token
pdAuthToken: 12345

# Explicitly set report time range (RFC822)
reportTimeRange:
  start: 01 Jan 20 00:00 UTC
  end: 01 Feb 20 00:00 UTC

# Rotation general information
rotationInfo:
  dailyRotationStartsAt: 8
  checkRotationChangeEvery: 30 # minutes

I need to pass environment variables in the config.yaml file. I tried to use ${THE_VARIABLE} as such:

reportTimeRange:
    start: ${THE_VARIABLE}

Can anyone help on how I can passmy Linux environment variables in the config.yaml file without the need of editing the script.

CodePudding user response:

After unmarshaling the yaml file you can use reflect on the result to update any string fields whose value matches variable format of your choice.

var reVar = regexp.MustCompile(`^\${(\w )}$`)

func fromenv(v interface{}) {
    _fromenv(reflect.ValueOf(v).Elem())// assumes pointer to struct
}

// recursive
func _fromenv(rv reflect.Value) {
    for i := 0; i < rv.NumField(); i   {
        fv := rv.Field(i)
        if fv.Kind() == reflect.Ptr {
            fv = fv.Elem()
        }
        if fv.Kind() == reflect.Struct {
            _fromenv(fv)
            continue
        }
        if fv.Kind() == reflect.String {
            match := reVar.FindStringSubmatch(fv.String())
            if len(match) > 1 {
                fv.SetString(os.Getenv(match[1]))
            }
        }
    }
}

https://play.golang.org/p/1zuK7Mhtvsa


Alternatively, you could declare types that implement the yaml.Unmarshaler interface and use those types for fields in the config struct that expect the corresponding yaml properties to contain environment variables.

type Config struct {
    ReportTimeRange struct {
        Start StringFromEnv `yaml:"start"`
    } `yaml:"reportTimeRange"`
}

var reVar = regexp.MustCompile(`^\${(\w )}$`)

type StringFromEnv string

func (e *StringFromEnv) UnmarshalYAML(value *yaml.Node) error {
    var s string
    if err := value.Decode(&s); err != nil {
        return err
    }
    if match := reVar.FindStringSubmatch(s); len(match) > 0 {
        *e = StringFromEnv(os.Getenv(match[1]))
    } else {
        *e = StringFromEnv(s)
    }
    return nil
}

https://play.golang.org/p/Zy0rXJ7RRdC

CodePudding user response:

What I understand is that you want to replace the placeholder {{ .THE_VARIABLE }} with a environment var at program start in memory, without modifying the yaml file.

The idea is to load the yaml file into a var, use template.Execute to replace the data. Finally Unmarshal the string.

I just kept it simple.

YAML FILE:

Start: {{ .THE_VARIABLE }}

Replacing data:

fileData, _ := ioutil.ReadFile("test.yml")
var finalData bytes.Buffer
t := template.New("config")
t, err := t.Parse(string(fileData))
if err != nil {
    panic(err)
}

data := struct {
    THE_VARIABLE int
}{
    THE_VARIABLE: 30,  // replace with os.Getenv("FOO")
}
t.Execute(&finalData, data)
str := finalData.String()
fmt.Println(str)
// unmarshal YAML here - from finalData.Bytes()

Output:
Start: 30

  • Related