英文:
Use environment variables in YAML file
问题
我有一个生成 Pager Duty 值班报告的 GO 脚本,它有自己的 config.yaml 文件,如下所示:
# PagerDuty 授权令牌
pdAuthToken: 12345
# 显式设置报告时间范围(RFC822)
reportTimeRange:
start: 01 Jan 20 00:00 UTC
end: 01 Feb 20 00:00 UTC
# 值班轮换的一般信息
rotationInfo:
dailyRotationStartsAt: 8
checkRotationChangeEvery: 30 # 分钟
我需要在 config.yaml 文件中传递环境变量。我尝试使用 ${THE_VARIABLE}
,如下所示:
reportTimeRange:
start: ${THE_VARIABLE}
有人可以帮忙解决如何在不编辑脚本的情况下,在 config.yaml 文件中传递 Linux 环境变量吗?
英文:
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.
答案1
得分: 1
在解组 YAML 文件后,您可以对结果使用 reflect
,以更新任何值与您选择的变量格式匹配的 string
字段。
var reVar = regexp.MustCompile(`^${(\w+)}$`)
func fromenv(v interface{}) {
_fromenv(reflect.ValueOf(v).Elem())// 假设是指向结构体的指针
}
// 递归函数
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]))
}
}
}
}
或者,您可以声明实现 yaml.Unmarshaler
接口的类型,并将这些类型用于配置结构体中的字段,这些字段期望相应的 YAML 属性包含环境变量。
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
}
英文:
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
}
答案2
得分: 0
我理解的是,你想在程序启动时将占位符{{ .THE_VARIABLE }}
替换为内存中的环境变量,而不修改yaml文件。
思路是将yaml文件加载到一个变量中,使用template.Execute
替换数据。最后解析字符串。
我只是保持简单。
YAML文件:
Start: {{ .THE_VARIABLE }}
替换数据:
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, // 替换为 os.Getenv("FOO")
}
t.Execute(&finalData, data)
str := finalData.String()
fmt.Println(str)
// 在这里解析YAML - 使用 finalData.Bytes()
输出:
Start: 30
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论