mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-12 06:24:10 +01:00
common/helper: add a helper to rename a configuration setting
This commit is contained in:
@@ -106,6 +106,39 @@ func DefaultValuesUnmarshallerHook[Configuration any](defaultConfiguration Confi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenameKeyUnmarshallerHook move a configuration setting from one place to another.
|
||||||
|
func RenameKeyUnmarshallerHook[Configuration any](zeroConfiguration Configuration, fromLabel, toLabel string) mapstructure.DecodeHookFunc {
|
||||||
|
return func(from, to reflect.Value) (interface{}, error) {
|
||||||
|
if from.Kind() != reflect.Map || from.IsNil() || to.Type() != reflect.TypeOf(zeroConfiguration) {
|
||||||
|
return from.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// country-database → geo-database
|
||||||
|
var fromKey, toKey *reflect.Value
|
||||||
|
fromMap := from.MapKeys()
|
||||||
|
for i, k := range fromMap {
|
||||||
|
k = ElemOrIdentity(k)
|
||||||
|
if k.Kind() != reflect.String {
|
||||||
|
return from.Interface(), nil
|
||||||
|
}
|
||||||
|
if MapStructureMatchName(k.String(), fromLabel) {
|
||||||
|
fromKey = &fromMap[i]
|
||||||
|
} else if MapStructureMatchName(k.String(), toLabel) {
|
||||||
|
toKey = &fromMap[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fromKey != nil && toKey != nil {
|
||||||
|
return nil, fmt.Errorf("cannot have both %q and %q", fromKey.String(), toKey.String())
|
||||||
|
}
|
||||||
|
if fromKey != nil {
|
||||||
|
from.SetMapIndex(reflect.ValueOf(toLabel), from.MapIndex(*fromKey))
|
||||||
|
from.SetMapIndex(*fromKey, reflect.Value{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return from.Interface(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ParametrizedConfigurationUnmarshallerHook will help decode a configuration
|
// ParametrizedConfigurationUnmarshallerHook will help decode a configuration
|
||||||
// structure parametrized by a type by selecting the appropriate concrete type
|
// structure parametrized by a type by selecting the appropriate concrete type
|
||||||
// depending on the type contained in the source. We have two configuration
|
// depending on the type contained in the source. We have two configuration
|
||||||
|
|||||||
@@ -119,6 +119,54 @@ func TestDefaultValuesConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRenameConfig(t *testing.T) {
|
||||||
|
type Configuration struct {
|
||||||
|
UnchangedLabel string
|
||||||
|
NewLabel string
|
||||||
|
}
|
||||||
|
RegisterMapstructureUnmarshallerHook(RenameKeyUnmarshallerHook(Configuration{}, "OldLabel", "NewLabel"))
|
||||||
|
TestConfigurationDecode(t, ConfigurationDecodeCases{
|
||||||
|
{
|
||||||
|
Description: "no rename needed",
|
||||||
|
Initial: func() interface{} { return Configuration{} },
|
||||||
|
Configuration: func() interface{} {
|
||||||
|
return gin.H{
|
||||||
|
"unchanged-label": "hello",
|
||||||
|
"new-label": "bye",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expected: Configuration{
|
||||||
|
UnchangedLabel: "hello",
|
||||||
|
NewLabel: "bye",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Description: "rename needed",
|
||||||
|
Initial: func() interface{} { return Configuration{} },
|
||||||
|
Configuration: func() interface{} {
|
||||||
|
return gin.H{
|
||||||
|
"unchanged-label": "hello",
|
||||||
|
"old-label": "bye",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expected: Configuration{
|
||||||
|
UnchangedLabel: "hello",
|
||||||
|
NewLabel: "bye",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Description: "conflicts",
|
||||||
|
Initial: func() interface{} { return Configuration{} },
|
||||||
|
Configuration: func() interface{} {
|
||||||
|
return gin.H{
|
||||||
|
"unchanged-label": "hello",
|
||||||
|
"old-label": "bye",
|
||||||
|
"new-label": "whatt?",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Error: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestParametrizedConfig(t *testing.T) {
|
func TestParametrizedConfig(t *testing.T) {
|
||||||
type InnerConfigurationType1 struct {
|
type InnerConfigurationType1 struct {
|
||||||
CC string
|
CC string
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
@@ -13,8 +11,6 @@ import (
|
|||||||
"akvorado/inlet/metadata/provider/gnmi"
|
"akvorado/inlet/metadata/provider/gnmi"
|
||||||
"akvorado/inlet/metadata/provider/snmp"
|
"akvorado/inlet/metadata/provider/snmp"
|
||||||
"akvorado/inlet/metadata/provider/static"
|
"akvorado/inlet/metadata/provider/static"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration describes the configuration for the metadata client
|
// Configuration describes the configuration for the metadata client
|
||||||
@@ -49,40 +45,6 @@ func DefaultConfiguration() Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigurationUnmarshallerHook renames "provider" to "providers".
|
|
||||||
func ConfigurationUnmarshallerHook() mapstructure.DecodeHookFunc {
|
|
||||||
return func(from, to reflect.Value) (interface{}, error) {
|
|
||||||
if from.Kind() != reflect.Map || from.IsNil() || to.Type() != reflect.TypeOf(Configuration{}) {
|
|
||||||
return from.Interface(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// provider → providers
|
|
||||||
{
|
|
||||||
var providerKey, providersKey *reflect.Value
|
|
||||||
fromKeys := from.MapKeys()
|
|
||||||
for i, k := range fromKeys {
|
|
||||||
k = helpers.ElemOrIdentity(k)
|
|
||||||
if k.Kind() != reflect.String {
|
|
||||||
return from.Interface(), nil
|
|
||||||
}
|
|
||||||
if helpers.MapStructureMatchName(k.String(), "Provider") {
|
|
||||||
providerKey = &fromKeys[i]
|
|
||||||
} else if helpers.MapStructureMatchName(k.String(), "Providers") {
|
|
||||||
providersKey = &fromKeys[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if providersKey != nil && providerKey != nil {
|
|
||||||
return nil, fmt.Errorf("cannot have both %q and %q", providerKey.String(), providersKey.String())
|
|
||||||
}
|
|
||||||
if providerKey != nil {
|
|
||||||
from.SetMapIndex(reflect.ValueOf("providers"), from.MapIndex(*providerKey))
|
|
||||||
from.SetMapIndex(*providerKey, reflect.Value{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return from.Interface(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProviderConfiguration represents the configuration for a metadata provider.
|
// ProviderConfiguration represents the configuration for a metadata provider.
|
||||||
type ProviderConfiguration struct {
|
type ProviderConfiguration struct {
|
||||||
// Config is the actual configuration for the provider.
|
// Config is the actual configuration for the provider.
|
||||||
@@ -101,7 +63,8 @@ var providers = map[string](func() provider.Configuration){
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
helpers.RegisterMapstructureUnmarshallerHook(ConfigurationUnmarshallerHook())
|
helpers.RegisterMapstructureUnmarshallerHook(
|
||||||
|
helpers.RenameKeyUnmarshallerHook(Configuration{}, "Provider", "Providers"))
|
||||||
helpers.RegisterMapstructureUnmarshallerHook(
|
helpers.RegisterMapstructureUnmarshallerHook(
|
||||||
helpers.ParametrizedConfigurationUnmarshallerHook(ProviderConfiguration{}, providers))
|
helpers.ParametrizedConfigurationUnmarshallerHook(ProviderConfiguration{}, providers))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,7 @@
|
|||||||
package geoip
|
package geoip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration describes the configuration for the GeoIP component.
|
// Configuration describes the configuration for the GeoIP component.
|
||||||
@@ -29,40 +24,7 @@ func DefaultConfiguration() Configuration {
|
|||||||
return Configuration{}
|
return Configuration{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigurationUnmarshallerHook normalize GeoIP configuration:
|
|
||||||
// - replace country-database by geo-database
|
|
||||||
func ConfigurationUnmarshallerHook() mapstructure.DecodeHookFunc {
|
|
||||||
return func(from, to reflect.Value) (interface{}, error) {
|
|
||||||
if from.Kind() != reflect.Map || from.IsNil() || to.Type() != reflect.TypeOf(Configuration{}) {
|
|
||||||
return from.Interface(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// country-database → geo-database
|
|
||||||
var countryKey, geoKey *reflect.Value
|
|
||||||
fromMap := from.MapKeys()
|
|
||||||
for i, k := range fromMap {
|
|
||||||
k = helpers.ElemOrIdentity(k)
|
|
||||||
if k.Kind() != reflect.String {
|
|
||||||
return from.Interface(), nil
|
|
||||||
}
|
|
||||||
if helpers.MapStructureMatchName(k.String(), "CountryDatabase") {
|
|
||||||
countryKey = &fromMap[i]
|
|
||||||
} else if helpers.MapStructureMatchName(k.String(), "GeoDatabase") {
|
|
||||||
geoKey = &fromMap[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if countryKey != nil && geoKey != nil {
|
|
||||||
return nil, fmt.Errorf("cannot have both %q and %q", countryKey.String(), geoKey.String())
|
|
||||||
}
|
|
||||||
if countryKey != nil {
|
|
||||||
from.SetMapIndex(reflect.ValueOf("geo-database"), from.MapIndex(*countryKey))
|
|
||||||
from.SetMapIndex(*countryKey, reflect.Value{})
|
|
||||||
}
|
|
||||||
|
|
||||||
return from.Interface(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
helpers.RegisterMapstructureUnmarshallerHook(ConfigurationUnmarshallerHook())
|
helpers.RegisterMapstructureUnmarshallerHook(
|
||||||
|
helpers.RenameKeyUnmarshallerHook(Configuration{}, "CountryDatabase", "GeoDatabase"))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user