@ -4,6 +4,7 @@ import (
"fmt"
"github.com/hashicorp/go-hclog"
"github.com/imdario/mergo"
"github.com/mitchellh/copystructure"
"github.com/hashicorp/consul/agent/structs"
@ -20,10 +21,18 @@ func ComputeResolvedServiceConfig(
thisReply . MeshGateway . Mode = structs . MeshGatewayModeDefault
// Store the upstream defaults under a wildcard key so that they can be applied to
// upstreams that are inferred from intentions and do not have explicit upstream configuration.
wildcard := structs . NewServiceID ( structs . WildcardSpecifier , args . WithWildcardNamespace ( ) )
wildcardUpstreamDefaults := make ( map [ string ] interface { } )
// resolvedConfigs stores the opaque config map for each upstream and is keyed on the upstream's ID.
resolvedConfigs := make ( map [ structs . ServiceID ] map [ string ] interface { } )
// TODO(freddy) Refactor this into smaller set of state store functions
// Pass the WatchSet to both the service and proxy config lookups. If either is updated during the
// blocking query, this function will be rerun and these state store lookups will both be current.
// We use the default enterprise meta to look up the global proxy defaults because they are not namespaced.
var proxyConfGlobalProtocol string
proxyConf := entries . GetProxyDefaults ( args . PartitionOrDefault ( ) )
if proxyConf != nil {
@ -32,20 +41,27 @@ func ComputeResolvedServiceConfig(
if err != nil {
return nil , fmt . Errorf ( "failed to copy global proxy-defaults: %v" , err )
}
thisReply . ProxyConfig = mapCopy . ( map [ string ] interface { } )
thisReply . Mode = proxyConf . Mode
thisReply . TransparentProxy = proxyConf . TransparentProxy
thisReply . MeshGateway = proxyConf . MeshGateway
thisReply . Expose = proxyConf . Expose
// Extract the global protocol from proxyConf for upstream configs.
rawProtocol := proxyConf . Config [ "protocol" ]
if rawProtocol != nil {
var ok bool
proxyConfGlobalProtocol , ok = rawProtocol . ( string )
if ! ok {
return nil , fmt . Errorf ( "invalid protocol type %T" , rawProtocol )
}
parsed , err := structs . ParseUpstreamConfigNoDefaults ( mapCopy . ( map [ string ] interface { } ) )
if err != nil {
return nil , fmt . Errorf ( "failed to parse upstream config map for proxy-defaults: %v" , err )
}
proxyConfGlobalProtocol = parsed . Protocol
// MeshGateway is strange. It's marshaled into UpstreamConfigs via the arbitrary map, but it
// uses concrete fields everywhere else. We always take the explicit definition here for
// wildcard upstreams and discard the user setting it via arbitrary map in proxy-defaults.
if err := mergo . MergeWithOverwrite ( & wildcardUpstreamDefaults , mapCopy ) ; err != nil {
return nil , fmt . Errorf ( "failed to merge upstream config map for proxy-defaults: %v" , err )
}
if ! proxyConf . MeshGateway . IsZero ( ) {
wildcardUpstreamDefaults [ "mesh_gateway" ] = proxyConf . MeshGateway
}
}
@ -62,6 +78,7 @@ func ComputeResolvedServiceConfig(
}
if serviceConf . MeshGateway . Mode != structs . MeshGatewayModeDefault {
thisReply . MeshGateway . Mode = serviceConf . MeshGateway . Mode
wildcardUpstreamDefaults [ "mesh_gateway" ] = serviceConf . MeshGateway
}
if serviceConf . TransparentProxy . OutboundListenerPort != 0 {
thisReply . TransparentProxy . OutboundListenerPort = serviceConf . TransparentProxy . OutboundListenerPort
@ -134,10 +151,8 @@ func ComputeResolvedServiceConfig(
// Then store upstreams inferred from service-defaults and mapify the overrides.
var (
upstreamOverrides = make ( map [ structs . ServiceID ] * structs . UpstreamConfig )
upstreamDefaults * structs . UpstreamConfig
// resolvedConfigs stores the opaque config map for each upstream and is keyed on the upstream's ID.
resolvedConfigs = make ( map [ structs . ServiceID ] map [ string ] interface { } )
upstreamOverrides = make ( map [ structs . ServiceID ] * structs . UpstreamConfig )
)
if serviceConf != nil && serviceConf . UpstreamConfig != nil {
for i , override := range serviceConf . UpstreamConfig . Overrides {
@ -156,23 +171,24 @@ func ComputeResolvedServiceConfig(
}
if serviceConf . UpstreamConfig . Defaults != nil {
upstreamDefaults = serviceConf . UpstreamConfig . Defaults
if upstreamDefaults . MeshGateway . Mode == structs . MeshGatewayModeDefault {
upstreamDefaults . MeshGateway . Mode = thisReply . MeshGateway . Mode
}
upstreamDefaults . MergeInto ( wildcardUpstreamDefaults )
// Always add the wildcard upstream if a service-defaults default-upstream was configured.
resolvedConfigs [ wildcard ] = wildcardUpstreamDefaults
}
}
// Store the upstream defaults under a wildcard key so that they can be applied to
// upstreams that are inferred from intentions and do not have explicit upstream configuration.
cfgMap := make ( map [ string ] interface { } )
upstreamDefaults . MergeInto ( cfgMap )
if ! args . MeshGateway . IsZero ( ) {
cfgMap [ "mesh_gateway" ] = args . MeshGateway
}
if ! args . MeshGateway . IsZero ( ) {
wildcardUpstreamDefaults [ "mesh_gateway" ] = args . MeshGateway
}
wildcard := structs . NewServiceID ( structs . WildcardSpecifier , args . WithWildcardNamespace ( ) )
resolvedConfigs [ wildcard ] = cfgMap
}
// Add the wildcard upstream if any fields were populated (it may have been already
// added if a service-defaults exists). We likely could always add it without issues,
// but this has been existing behavior, and many unit tests would break.
if len ( wildcardUpstreamDefaults ) > 0 {
resolvedConfigs [ wildcard ] = wildcardUpstreamDefaults
}
for upstream := range seenUpstreams {