In ReadRemoteConfig, that have no less than one remote providers, but only retrieve the first found configuration. Is there a specific reason?
// Retrieve the first found remote configuration.
func (v *Viper) getKeyValueConfig() error {
if RemoteConfig == nil {
return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
}
for _, rp := range v.remoteProviders {
val, err := v.getRemoteConfig(rp)
if err != nil {
continue
}
v.kvstore = val
return nil
}
return RemoteConfigError("No Files Found")
}
Comment From: kingmorning
maybe should modify the line: v.kvstore = val
merge the old value and new value.
v.kvstore should store all val from remoteProviders.
Comment From: gangxie112
So, due to this, there is no away to load multiple remote config. Wonder why it's designed/implemented like this? really unthoughtful.
Comment From: iatoz
I can confirm this issue still exists in v1.20.1. I've just spent some time debugging this exact problem and traced it back to the getKeyValueConfig
function in remote.go
.
The analysis from the original poster is spot on. The function has two main issues:
- Assignment instead of Merging: The line
v.kvstore = val
overwrites the entire configuration map with the values from the current provider, rather than merging them. - Premature Return: The
return nil
statement at the end of the loop causes the function to exit after successfully reading the very first provider, ignoring all others in thev.remoteProviders
slice. Suggested Fix
A potential fix would involve iterating through all providers, fetching their configuration, and merging the results into v.kvstore
.
Here is a conceptual implementation of the fix:
// In getKeyValueConfig:
// ...
for _, rp := range v.remoteProviders {
...
// Merge val into v.kvstore
for k, v := range val {
v.kvstore[k] = v
}
}
return nil // Return after the loop finishes
// In getRemoteConfig:
func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
reader, err := RemoteConfig.Get(provider)
if err != nil {
return nil, err
}
var newVals map[string]any
err = v.unmarshalReader(reader, &newVals)
return newVals, err
}