I'm trying to have application.yaml file in go application which contains ${RMQ_HOST} values which I want to override with environment variables.
In application.yaml I've got:
rmq:
test:
host: ${RMQ_HOST}
port: ${RMQ_PORT}
And in my loader I have:
log.Println("Loading config...")
viper.SetConfigName("application")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AutomaticEnv()
err := viper.ReadInConfig()
The problem I have is ${RMQ_HOST} won't get replaced by values I've set in my environment variables and will try connect to the RabbitMQ with this string
amqp://test:test@${RMQ_HOST}:${RMQ_PORT}/test
instead of
amqp://test:test@test:test/test
Viper doesn't have the ability to keep placeholders for values in key/value pairs, so I've managed to solve my issue with this code snippet:
log.Println("Loading config...")
viper.SetConfigName("application")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
panic("Couldn't load configuration, cannot start. Terminating. Error: " + err.Error())
}
log.Println("Config loaded successfully...")
log.Println("Getting environment variables...")
for _, k := range viper.AllKeys() {
value := viper.GetString(k)
if strings.HasPrefix(value, "${") && strings.HasSuffix(value, "}") {
viper.Set(k, getEnvOrPanic(strings.TrimSuffix(strings.TrimPrefix(value,"${"), "}")))
}
}
func getEnvOrPanic(env string) string {
res := os.Getenv(env)
if len(env) == 0 {
panic("Mandatory env variable not found:" + env)
}
return res
}
This will overwrite all the placeholders found in the collection.
Update:
I extended the native yaml parser with this functionality and released it on github.
Usage:
type Config struct {
Port string `yaml:"port"`
RabbitMQ RabbitMQ `yaml:"rabbitmq"`
}
type RabbitMQ struct {
Host string `yaml:"host"`
Port string `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Vhost string `yaml:"vhost"`
}
func main() {
var config Config
file, err := ioutil.ReadFile("application.yaml")
if err != nil {
panic(err)
}
yaml.Unmarshal(file, &config)
spew.Dump(config)
}
This is how application.yaml looks like:
port: ${SERVER_PORT}
rabbitmq:
host: ${RMQ_HOST}
port: ${RMQ_PORT}
username: ${RMQ_USERNAME}
password: ${RMQ_PASSWORD}
vhost: test
vhost value will get parsed as usual, while everything surrounded with "${" and "}" will get replaced with environment variables.