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