config: use the new HookTranslateKeys instead of lib.TranslateKeys

With the exception of CA provider config, which will be migrated at some
later time.
This commit is contained in:
Daniel Nephin 2020-05-27 14:42:01 -04:00
parent 8ced4300c8
commit 6a2d7d77c0
6 changed files with 58 additions and 106 deletions

View File

@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/lib/decode"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl" "github.com/hashicorp/hcl"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
@ -108,32 +109,11 @@ func Parse(data string, format string) (c Config, keys []string, err error) {
"config_entries.bootstrap", // completely ignore this tree (fixed elsewhere) "config_entries.bootstrap", // completely ignore this tree (fixed elsewhere)
}) })
// There is a difference of representation of some fields depending on
// where they are used. The HTTP API uses CamelCase whereas the config
// files use snake_case and between the two there is no automatic mapping.
// While the JSON and HCL parsers match keys without case (both `id` and
// `ID` are mapped to an ID field) the same thing does not happen between
// CamelCase and snake_case. Since changing either format would break
// existing setups we have to support both and slowly transition to one of
// the formats. Also, there is at least one case where we use the "wrong"
// key and want to map that to the new key to support deprecation -
// see [GH-3179]. TranslateKeys maps potentially CamelCased values to the
// snake_case that is used in the config file parser. If both the CamelCase
// and snake_case values are set the snake_case value is used and the other
// value is discarded.
lib.TranslateKeys(m, map[string]string{
"deregistercriticalserviceafter": "deregister_critical_service_after",
"dockercontainerid": "docker_container_id",
"scriptargs": "args",
"serviceid": "service_id",
"tlsskipverify": "tls_skip_verify",
"config_entries.bootstrap": "",
})
var md mapstructure.Metadata var md mapstructure.Metadata
d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Metadata: &md, DecodeHook: decode.HookTranslateKeys,
Result: &c, Metadata: &md,
Result: &c,
}) })
if err != nil { if err != nil {
return Config{}, nil, err return Config{}, nil, err

View File

@ -9,6 +9,7 @@ import (
cachetype "github.com/hashicorp/consul/agent/cache-types" cachetype "github.com/hashicorp/consul/agent/cache-types"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/lib/decode"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
) )
@ -105,15 +106,12 @@ func decodeDiscoveryChainReadRequest(raw map[string]interface{}) (*discoveryChai
// to do this part first. // to do this part first.
raw = lib.PatchSliceOfMaps(raw, nil, nil) raw = lib.PatchSliceOfMaps(raw, nil, nil)
lib.TranslateKeys(raw, map[string]string{
"override_mesh_gateway": "overridemeshgateway",
"override_protocol": "overrideprotocol",
"override_connect_timeout": "overrideconnecttimeout",
})
var apiReq discoveryChainReadRequest var apiReq discoveryChainReadRequest
decodeConf := &mapstructure.DecoderConfig{ decodeConf := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToTimeDurationHookFunc(), DecodeHook: mapstructure.ComposeDecodeHookFunc(
decode.HookTranslateKeys,
mapstructure.StringToTimeDurationHookFunc(),
),
Result: &apiReq, Result: &apiReq,
WeaklyTypedInput: true, WeaklyTypedInput: true,
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/cache"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/lib/decode"
"github.com/hashicorp/go-msgpack/codec" "github.com/hashicorp/go-msgpack/codec"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/mitchellh/hashstructure" "github.com/mitchellh/hashstructure"
@ -283,7 +284,7 @@ func DecodeConfigEntry(raw map[string]interface{}) (ConfigEntry, error) {
return nil, fmt.Errorf("Kind value in payload is not a string") return nil, fmt.Errorf("Kind value in payload is not a string")
} }
skipWhenPatching, translateKeysDict, err := ConfigEntryDecodeRulesForKind(entry.GetKind()) skipWhenPatching, err := ConfigEntryDecodeRulesForKind(entry.GetKind())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -292,11 +293,12 @@ func DecodeConfigEntry(raw map[string]interface{}) (ConfigEntry, error) {
// to do this part first. // to do this part first.
raw = lib.PatchSliceOfMaps(raw, skipWhenPatching, nil) raw = lib.PatchSliceOfMaps(raw, skipWhenPatching, nil)
lib.TranslateKeys(raw, translateKeysDict)
var md mapstructure.Metadata var md mapstructure.Metadata
decodeConf := &mapstructure.DecoderConfig{ decodeConf := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToTimeDurationHookFunc(), DecodeHook: mapstructure.ComposeDecodeHookFunc(
decode.HookTranslateKeys,
mapstructure.StringToTimeDurationHookFunc(),
),
Metadata: &md, Metadata: &md,
Result: &entry, Result: &entry,
WeaklyTypedInput: true, WeaklyTypedInput: true,
@ -327,80 +329,48 @@ func DecodeConfigEntry(raw map[string]interface{}) (ConfigEntry, error) {
// ConfigEntryDecodeRulesForKind returns rules for 'fixing' config entry key // ConfigEntryDecodeRulesForKind returns rules for 'fixing' config entry key
// formats by kind. This is shared between the 'structs' and 'api' variations // formats by kind. This is shared between the 'structs' and 'api' variations
// of config entries. // of config entries.
func ConfigEntryDecodeRulesForKind(kind string) (skipWhenPatching []string, translateKeysDict map[string]string, err error) { func ConfigEntryDecodeRulesForKind(kind string) (skipWhenPatching []string, err error) {
switch kind { switch kind {
case ProxyDefaults: case ProxyDefaults:
return []string{ return []string{
"expose.paths", "expose.paths",
"Expose.Paths", "Expose.Paths",
}, map[string]string{ }, nil
"local_path_port": "localpathport",
"listener_port": "listenerport",
"mesh_gateway": "meshgateway",
"config": "",
}, nil
case ServiceDefaults: case ServiceDefaults:
return []string{ return []string{
"expose.paths", "expose.paths",
"Expose.Paths", "Expose.Paths",
}, map[string]string{ }, nil
"local_path_port": "localpathport",
"listener_port": "listenerport",
"mesh_gateway": "meshgateway",
"external_sni": "externalsni",
}, nil
case ServiceRouter: case ServiceRouter:
return []string{ return []string{
"routes", "routes",
"Routes", "Routes",
"routes.match.http.header", "routes.match.http.header",
"Routes.Match.HTTP.Header", "Routes.Match.HTTP.Header",
"routes.match.http.query_param", "routes.match.http.query_param",
"Routes.Match.HTTP.QueryParam", "Routes.Match.HTTP.QueryParam",
}, map[string]string{ }, nil
"num_retries": "numretries",
"path_exact": "pathexact",
"path_prefix": "pathprefix",
"path_regex": "pathregex",
"prefix_rewrite": "prefixrewrite",
"query_param": "queryparam",
"request_timeout": "requesttimeout",
"retry_on_connect_failure": "retryonconnectfailure",
"retry_on_status_codes": "retryonstatuscodes",
"service_subset": "servicesubset",
}, nil
case ServiceSplitter: case ServiceSplitter:
return []string{ return []string{
"splits", "splits",
"Splits", "Splits",
}, map[string]string{
"service_subset": "servicesubset",
}, nil
case ServiceResolver:
return nil, map[string]string{
"connect_timeout": "connecttimeout",
"default_subset": "defaultsubset",
"only_passing": "onlypassing",
"service_subset": "servicesubset",
}, nil }, nil
case ServiceResolver:
return nil, nil
case IngressGateway: case IngressGateway:
return []string{ return []string{
"listeners", "listeners",
"Listeners", "Listeners",
"listeners.services", "listeners.services",
"Listeners.Services", "Listeners.Services",
}, nil, nil }, nil
case TerminatingGateway: case TerminatingGateway:
return []string{ return []string{
"services", "services",
"Services", "Services",
}, map[string]string{ }, nil
"ca_file": "cafile",
"cert_file": "certfile",
"key_file": "keyfile",
}, nil
default: default:
return nil, nil, fmt.Errorf("kind %q should be explicitly handled here", kind) return nil, fmt.Errorf("kind %q should be explicitly handled here", kind)
} }
} }

View File

@ -7,7 +7,7 @@ import (
envoycluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster" envoycluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster"
"github.com/gogo/protobuf/types" "github.com/gogo/protobuf/types"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib/decode"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
) )
@ -97,15 +97,18 @@ type GatewayConfig struct {
// error occurs during parsing, it is returned along with the default config. This // error occurs during parsing, it is returned along with the default config. This
// allows the caller to choose whether and how to report the error // allows the caller to choose whether and how to report the error
func ParseGatewayConfig(m map[string]interface{}) (GatewayConfig, error) { func ParseGatewayConfig(m map[string]interface{}) (GatewayConfig, error) {
// Fixup for deprecated mesh gateway names
lib.TranslateKeys(m, map[string]string{
"envoy_mesh_gateway_bind_tagged_addresses": "envoy_gateway_bind_tagged_addresses",
"envoy_mesh_gateway_bind_addresses": "envoy_gateway_bind_addresses",
"envoy_mesh_gateway_no_default_bind": "envoy_gateway_no_default_bind",
})
var cfg GatewayConfig var cfg GatewayConfig
err := mapstructure.WeakDecode(m, &cfg) d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
DecodeHook: decode.HookTranslateKeys,
Result: &cfg,
WeaklyTypedInput: true,
})
if err != nil {
return cfg, err
}
if err := d.Decode(m); err != nil {
return cfg, err
}
if cfg.ConnectTimeoutMs < 1 { if cfg.ConnectTimeoutMs < 1 {
cfg.ConnectTimeoutMs = 5000 cfg.ConnectTimeoutMs = 5000

View File

@ -10,6 +10,7 @@ import (
"github.com/hashicorp/consul/command/flags" "github.com/hashicorp/consul/command/flags"
"github.com/hashicorp/consul/command/helpers" "github.com/hashicorp/consul/command/helpers"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/lib/decode"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/mitchellh/cli" "github.com/mitchellh/cli"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
@ -132,7 +133,7 @@ func newDecodeConfigEntry(raw map[string]interface{}) (api.ConfigEntry, error) {
return nil, fmt.Errorf("Kind value in payload is not a string") return nil, fmt.Errorf("Kind value in payload is not a string")
} }
skipWhenPatching, translateKeysDict, err := structs.ConfigEntryDecodeRulesForKind(entry.GetKind()) skipWhenPatching, err := structs.ConfigEntryDecodeRulesForKind(entry.GetKind())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -141,14 +142,12 @@ func newDecodeConfigEntry(raw map[string]interface{}) (api.ConfigEntry, error) {
// to do this part first. // to do this part first.
raw = lib.PatchSliceOfMaps(raw, skipWhenPatching, nil) raw = lib.PatchSliceOfMaps(raw, skipWhenPatching, nil)
// CamelCase is the canonical form for these, since this translation
// happens in the `consul config write` command and the JSON form is sent
// off to the server.
lib.TranslateKeys(raw, translateKeysDict)
var md mapstructure.Metadata var md mapstructure.Metadata
decodeConf := &mapstructure.DecoderConfig{ decodeConf := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToTimeDurationHookFunc(), DecodeHook: mapstructure.ComposeDecodeHookFunc(
decode.HookTranslateKeys,
mapstructure.StringToTimeDurationHookFunc(),
),
Metadata: &md, Metadata: &md,
Result: &entry, Result: &entry,
WeaklyTypedInput: true, WeaklyTypedInput: true,

View File

@ -34,6 +34,8 @@ import (
// // item's config field // // item's config field
// "widgets.config": "", // "widgets.config": "",
// }) // })
//
// Deprecated: Use lib/decode.HookTranslateKeys instead.
func TranslateKeys(v map[string]interface{}, dict map[string]string) { func TranslateKeys(v map[string]interface{}, dict map[string]string) {
// Convert all dict keys for exclusions to lower. so we can match against them // Convert all dict keys for exclusions to lower. so we can match against them
// unambiguously with a single lookup. // unambiguously with a single lookup.