mirror of https://github.com/status-im/consul.git
connect: update centralized upstreams representation in service-defaults (#10015)
This commit is contained in:
parent
f33feeeec4
commit
4db8b78854
|
@ -4,14 +4,15 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics/prometheus"
|
||||
|
||||
metrics "github.com/armon/go-metrics"
|
||||
"github.com/armon/go-metrics/prometheus"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
memdb "github.com/hashicorp/go-memdb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/consul/state"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
memdb "github.com/hashicorp/go-memdb"
|
||||
"github.com/mitchellh/copystructure"
|
||||
)
|
||||
|
||||
var ConfigSummaries = []prometheus.SummaryDefinition{
|
||||
|
@ -43,7 +44,8 @@ var ConfigSummaries = []prometheus.SummaryDefinition{
|
|||
|
||||
// The ConfigEntry endpoint is used to query centralized config information
|
||||
type ConfigEntry struct {
|
||||
srv *Server
|
||||
srv *Server
|
||||
logger hclog.Logger
|
||||
}
|
||||
|
||||
// Apply does an upsert of the given config entry.
|
||||
|
@ -449,23 +451,30 @@ func (c *ConfigEntry) ResolveServiceConfig(args *structs.ServiceConfigRequest, r
|
|||
}
|
||||
}
|
||||
|
||||
// Then store upstreams inferred from service-defaults
|
||||
if serviceConf != nil && serviceConf.Connect != nil {
|
||||
for sid := range serviceConf.Connect.UpstreamConfigs {
|
||||
seenUpstreams[structs.ServiceIDFromString(sid)] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// usConfigs stores the opaque config map for each upstream and is keyed on the upstream's ID.
|
||||
usConfigs := make(map[structs.ServiceID]map[string]interface{})
|
||||
|
||||
// Then store upstreams inferred from service-defaults and mapify the overrides.
|
||||
var (
|
||||
upstreamConfigs = make(map[structs.ServiceID]*structs.UpstreamConfig)
|
||||
upstreamDefaults *structs.UpstreamConfig
|
||||
upstreamConfigs map[string]*structs.UpstreamConfig
|
||||
// usConfigs stores the opaque config map for each upstream and is keyed on the upstream's ID.
|
||||
usConfigs = make(map[structs.ServiceID]map[string]interface{})
|
||||
)
|
||||
if serviceConf != nil && serviceConf.Connect != nil {
|
||||
if serviceConf.Connect.UpstreamDefaults != nil {
|
||||
upstreamDefaults = serviceConf.Connect.UpstreamDefaults
|
||||
if serviceConf != nil && serviceConf.UpstreamConfig != nil {
|
||||
for i, override := range serviceConf.UpstreamConfig.Overrides {
|
||||
if override.Name == "" {
|
||||
c.logger.Warn(
|
||||
"Skipping UpstreamConfig.Overrides entry without a required name field",
|
||||
"entryIndex", i,
|
||||
"kind", serviceConf.GetKind(),
|
||||
"name", serviceConf.GetName(),
|
||||
"namespace", serviceConf.GetEnterpriseMeta().NamespaceOrEmpty(),
|
||||
)
|
||||
continue // skip this impossible condition
|
||||
}
|
||||
seenUpstreams[override.ServiceID()] = struct{}{}
|
||||
upstreamConfigs[override.ServiceID()] = override
|
||||
}
|
||||
if serviceConf.UpstreamConfig.Defaults != nil {
|
||||
upstreamDefaults = serviceConf.UpstreamConfig.Defaults
|
||||
|
||||
// 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.
|
||||
|
@ -475,9 +484,6 @@ func (c *ConfigEntry) ResolveServiceConfig(args *structs.ServiceConfigRequest, r
|
|||
wildcard := structs.NewServiceID(structs.WildcardSpecifier, structs.WildcardEnterpriseMeta())
|
||||
usConfigs[wildcard] = cfgMap
|
||||
}
|
||||
if serviceConf.Connect.UpstreamConfigs != nil {
|
||||
upstreamConfigs = serviceConf.Connect.UpstreamConfigs
|
||||
}
|
||||
}
|
||||
|
||||
for upstream := range seenUpstreams {
|
||||
|
@ -486,7 +492,7 @@ func (c *ConfigEntry) ResolveServiceConfig(args *structs.ServiceConfigRequest, r
|
|||
// The protocol of an upstream is resolved in this order:
|
||||
// 1. Default protocol from proxy-defaults (how all services should be addressed)
|
||||
// 2. Protocol for upstream service defined in its service-defaults (how the upstream wants to be addressed)
|
||||
// 3. Protocol defined for the upstream in the service-defaults.(upstream_defaults|upstream_configs) of the downstream
|
||||
// 3. Protocol defined for the upstream in the service-defaults.(upstream_config.defaults|upstream_config.overrides) of the downstream
|
||||
// (how the downstream wants to address it)
|
||||
protocol := proxyConfGlobalProtocol
|
||||
|
||||
|
@ -518,14 +524,14 @@ func (c *ConfigEntry) ResolveServiceConfig(args *structs.ServiceConfigRequest, r
|
|||
// The goal is to flatten the mesh gateway mode in this order:
|
||||
// 0. Value from centralized upstream_defaults
|
||||
// 1. Value from local proxy registration
|
||||
// 2. Value from centralized upstream_configs
|
||||
// 2. Value from centralized upstream_config
|
||||
// 3. Value from local upstream definition. This last step is done in the client's service manager.
|
||||
if !args.MeshGateway.IsZero() {
|
||||
resolvedCfg["mesh_gateway"] = args.MeshGateway
|
||||
}
|
||||
|
||||
if upstreamConfigs[upstream.String()] != nil {
|
||||
upstreamConfigs[upstream.String()].MergeInto(resolvedCfg)
|
||||
if upstreamConfigs[upstream] != nil {
|
||||
upstreamConfigs[upstream].MergeInto(resolvedCfg)
|
||||
}
|
||||
|
||||
if len(resolvedCfg) > 0 {
|
||||
|
|
|
@ -1029,9 +1029,10 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
&structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "api",
|
||||
Connect: &structs.ConnectConfiguration{
|
||||
UpstreamConfigs: map[string]*structs.UpstreamConfig{
|
||||
mysql.String(): {
|
||||
UpstreamConfig: &structs.UpstreamConfiguration{
|
||||
Overrides: []*structs.UpstreamConfig{
|
||||
{
|
||||
Name: "mysql",
|
||||
Protocol: "http",
|
||||
},
|
||||
},
|
||||
|
@ -1070,9 +1071,10 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
&structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "api",
|
||||
Connect: &structs.ConnectConfiguration{
|
||||
UpstreamConfigs: map[string]*structs.UpstreamConfig{
|
||||
mysql.String(): {
|
||||
UpstreamConfig: &structs.UpstreamConfiguration{
|
||||
Overrides: []*structs.UpstreamConfig{
|
||||
{
|
||||
Name: "mysql",
|
||||
Protocol: "http",
|
||||
},
|
||||
},
|
||||
|
@ -1115,8 +1117,8 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
&structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "api",
|
||||
Connect: &structs.ConnectConfiguration{
|
||||
UpstreamDefaults: &structs.UpstreamConfig{
|
||||
UpstreamConfig: &structs.UpstreamConfiguration{
|
||||
Defaults: &structs.UpstreamConfig{
|
||||
MeshGateway: structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeRemote},
|
||||
},
|
||||
},
|
||||
|
@ -1154,7 +1156,7 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "upstream_configs overrides all",
|
||||
name: "upstream_config.overrides override all",
|
||||
entries: []structs.ConfigEntry{
|
||||
&structs.ProxyConfigEntry{
|
||||
Kind: structs.ProxyDefaults,
|
||||
|
@ -1171,8 +1173,8 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
&structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "api",
|
||||
Connect: &structs.ConnectConfiguration{
|
||||
UpstreamDefaults: &structs.UpstreamConfig{
|
||||
UpstreamConfig: &structs.UpstreamConfiguration{
|
||||
Defaults: &structs.UpstreamConfig{
|
||||
Protocol: "http",
|
||||
MeshGateway: structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeRemote},
|
||||
PassiveHealthCheck: &structs.PassiveHealthCheck{
|
||||
|
@ -1180,8 +1182,9 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
MaxFailures: 2,
|
||||
},
|
||||
},
|
||||
UpstreamConfigs: map[string]*structs.UpstreamConfig{
|
||||
mysql.String(): {
|
||||
Overrides: []*structs.UpstreamConfig{
|
||||
{
|
||||
Name: "mysql",
|
||||
Protocol: "grpc",
|
||||
MeshGateway: structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeLocal},
|
||||
},
|
||||
|
@ -1239,12 +1242,13 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
&structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "api",
|
||||
Connect: &structs.ConnectConfiguration{
|
||||
UpstreamDefaults: &structs.UpstreamConfig{
|
||||
UpstreamConfig: &structs.UpstreamConfiguration{
|
||||
Defaults: &structs.UpstreamConfig{
|
||||
MeshGateway: structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeRemote},
|
||||
},
|
||||
UpstreamConfigs: map[string]*structs.UpstreamConfig{
|
||||
mysql.String(): {
|
||||
Overrides: []*structs.UpstreamConfig{
|
||||
{
|
||||
Name: "mysql",
|
||||
Protocol: "grpc",
|
||||
},
|
||||
},
|
||||
|
@ -1286,12 +1290,13 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
&structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "api",
|
||||
Connect: &structs.ConnectConfiguration{
|
||||
UpstreamDefaults: &structs.UpstreamConfig{
|
||||
UpstreamConfig: &structs.UpstreamConfiguration{
|
||||
Defaults: &structs.UpstreamConfig{
|
||||
MeshGateway: structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeRemote},
|
||||
},
|
||||
UpstreamConfigs: map[string]*structs.UpstreamConfig{
|
||||
mysql.String(): {
|
||||
Overrides: []*structs.UpstreamConfig{
|
||||
{
|
||||
Name: "mysql",
|
||||
Protocol: "grpc",
|
||||
},
|
||||
},
|
||||
|
@ -1338,12 +1343,13 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
|
|||
&structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "api",
|
||||
Connect: &structs.ConnectConfiguration{
|
||||
UpstreamDefaults: &structs.UpstreamConfig{
|
||||
UpstreamConfig: &structs.UpstreamConfiguration{
|
||||
Defaults: &structs.UpstreamConfig{
|
||||
MeshGateway: structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeRemote},
|
||||
},
|
||||
UpstreamConfigs: map[string]*structs.UpstreamConfig{
|
||||
mysql.String(): {
|
||||
Overrides: []*structs.UpstreamConfig{
|
||||
{
|
||||
Name: "mysql",
|
||||
Protocol: "grpc",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -6,7 +6,7 @@ func init() {
|
|||
registerEndpoint(func(s *Server) interface{} { return &ACL{s, s.loggers.Named(logging.ACL)} })
|
||||
registerEndpoint(func(s *Server) interface{} { return &Catalog{s, s.loggers.Named(logging.Catalog)} })
|
||||
registerEndpoint(func(s *Server) interface{} { return NewCoordinate(s, s.logger) })
|
||||
registerEndpoint(func(s *Server) interface{} { return &ConfigEntry{s} })
|
||||
registerEndpoint(func(s *Server) interface{} { return &ConfigEntry{s, s.loggers.Named(logging.ConfigEntry)} })
|
||||
registerEndpoint(func(s *Server) interface{} { return &ConnectCA{srv: s, logger: s.loggers.Named(logging.Connect)} })
|
||||
registerEndpoint(func(s *Server) interface{} { return &FederationState{s} })
|
||||
registerEndpoint(func(s *Server) interface{} { return &DiscoveryChain{s} })
|
||||
|
|
|
@ -89,10 +89,8 @@ type ServiceConfigEntry struct {
|
|||
TransparentProxy TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||
Expose ExposeConfig `json:",omitempty"`
|
||||
|
||||
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
||||
|
||||
Connect *ConnectConfiguration `json:",omitempty"`
|
||||
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
||||
UpstreamConfig *UpstreamConfiguration `json:",omitempty" alias:"upstream_config"`
|
||||
|
||||
Meta map[string]string `json:",omitempty"`
|
||||
EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
||||
|
@ -102,6 +100,7 @@ type ServiceConfigEntry struct {
|
|||
func (e *ServiceConfigEntry) Clone() *ServiceConfigEntry {
|
||||
e2 := *e
|
||||
e2.Expose = e.Expose.Clone()
|
||||
e2.UpstreamConfig = e.UpstreamConfig.Clone()
|
||||
return &e2
|
||||
}
|
||||
|
||||
|
@ -131,20 +130,48 @@ func (e *ServiceConfigEntry) Normalize() error {
|
|||
|
||||
e.Kind = ServiceDefaults
|
||||
e.Protocol = strings.ToLower(e.Protocol)
|
||||
|
||||
e.Connect.Normalize()
|
||||
e.EnterpriseMeta.Normalize()
|
||||
|
||||
return nil
|
||||
var validationErr error
|
||||
|
||||
if e.UpstreamConfig != nil {
|
||||
for _, override := range e.UpstreamConfig.Overrides {
|
||||
err := override.NormalizeWithName(&e.EnterpriseMeta)
|
||||
if err != nil {
|
||||
validationErr = multierror.Append(validationErr, fmt.Errorf("error in upstream override for %s: %v", override.ServiceName(), err))
|
||||
}
|
||||
}
|
||||
|
||||
if e.UpstreamConfig.Defaults != nil {
|
||||
err := e.UpstreamConfig.Defaults.NormalizeWithoutName()
|
||||
if err != nil {
|
||||
validationErr = multierror.Append(validationErr, fmt.Errorf("error in upstream defaults: %v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validationErr
|
||||
}
|
||||
|
||||
func (e *ServiceConfigEntry) Validate() error {
|
||||
if e.Name == "" {
|
||||
return fmt.Errorf("Name is required")
|
||||
}
|
||||
|
||||
validationErr := validateConfigEntryMeta(e.Meta)
|
||||
|
||||
if e.Connect != nil {
|
||||
err := e.Connect.Validate()
|
||||
if err != nil {
|
||||
validationErr = multierror.Append(validationErr, err)
|
||||
if e.UpstreamConfig != nil {
|
||||
for _, override := range e.UpstreamConfig.Overrides {
|
||||
err := override.ValidateWithName()
|
||||
if err != nil {
|
||||
validationErr = multierror.Append(validationErr, fmt.Errorf("error in upstream override for %s: %v", override.ServiceName(), err))
|
||||
}
|
||||
}
|
||||
|
||||
if e.UpstreamConfig.Defaults != nil {
|
||||
if err := e.UpstreamConfig.Defaults.ValidateWithoutName(); err != nil {
|
||||
validationErr = multierror.Append(validationErr, fmt.Errorf("error in upstream defaults: %v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,44 +206,32 @@ func (e *ServiceConfigEntry) GetEnterpriseMeta() *EnterpriseMeta {
|
|||
return &e.EnterpriseMeta
|
||||
}
|
||||
|
||||
type ConnectConfiguration struct {
|
||||
// UpstreamConfigs is a map of <namespace/>service to per-upstream configuration
|
||||
UpstreamConfigs map[string]*UpstreamConfig `json:",omitempty" alias:"upstream_configs"`
|
||||
type UpstreamConfiguration struct {
|
||||
// Overrides is a slice of per-service configuration. The name field is
|
||||
// required.
|
||||
Overrides []*UpstreamConfig `json:",omitempty"`
|
||||
|
||||
// UpstreamDefaults contains default configuration for all upstreams of a given service
|
||||
UpstreamDefaults *UpstreamConfig `json:",omitempty" alias:"upstream_defaults"`
|
||||
// Defaults contains default configuration for all upstreams of a given
|
||||
// service. The name field must be empty.
|
||||
Defaults *UpstreamConfig `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (cfg *ConnectConfiguration) Normalize() {
|
||||
if cfg == nil {
|
||||
return
|
||||
}
|
||||
for _, v := range cfg.UpstreamConfigs {
|
||||
v.Normalize()
|
||||
}
|
||||
|
||||
if cfg.UpstreamDefaults != nil {
|
||||
cfg.UpstreamDefaults.Normalize()
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg ConnectConfiguration) Validate() error {
|
||||
var validationErr error
|
||||
|
||||
for k, v := range cfg.UpstreamConfigs {
|
||||
if err := v.Validate(); err != nil {
|
||||
validationErr = multierror.Append(validationErr, fmt.Errorf("error in upstream config for %s: %v", k, err))
|
||||
func (c *UpstreamConfiguration) Clone() *UpstreamConfiguration {
|
||||
var c2 UpstreamConfiguration
|
||||
if len(c.Overrides) > 0 {
|
||||
c2.Overrides = make([]*UpstreamConfig, 0, len(c.Overrides))
|
||||
for _, o := range c.Overrides {
|
||||
dup := o.Clone()
|
||||
c2.Overrides = append(c2.Overrides, &dup)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.UpstreamDefaults != nil {
|
||||
err := cfg.UpstreamDefaults.Validate()
|
||||
if err != nil {
|
||||
validationErr = multierror.Append(validationErr, fmt.Errorf("error in upstream defaults %v", err))
|
||||
}
|
||||
if c.Defaults != nil {
|
||||
def2 := c.Defaults.Clone()
|
||||
c2.Defaults = &def2
|
||||
}
|
||||
|
||||
return validationErr
|
||||
return &c2
|
||||
}
|
||||
|
||||
// ProxyConfigEntry is the top-level struct for global proxy configuration defaults.
|
||||
|
@ -651,6 +666,11 @@ func (r *ServiceConfigRequest) CacheInfo() cache.RequestInfo {
|
|||
}
|
||||
|
||||
type UpstreamConfig struct {
|
||||
// Name is only accepted within a service-defaults config entry.
|
||||
Name string `json:",omitempty"`
|
||||
// EnterpriseMeta is only accepted within a service-defaults config entry.
|
||||
EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
||||
|
||||
// EnvoyListenerJSON is a complete override ("escape hatch") for the upstream's
|
||||
// listener.
|
||||
//
|
||||
|
@ -688,6 +708,29 @@ type UpstreamConfig struct {
|
|||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway" `
|
||||
}
|
||||
|
||||
func (cfg UpstreamConfig) Clone() UpstreamConfig {
|
||||
cfg2 := cfg
|
||||
|
||||
cfg2.Limits = cfg.Limits.Clone()
|
||||
cfg2.PassiveHealthCheck = cfg.PassiveHealthCheck.Clone()
|
||||
|
||||
return cfg2
|
||||
}
|
||||
|
||||
func (cfg *UpstreamConfig) ServiceID() ServiceID {
|
||||
if cfg.Name == "" {
|
||||
return ServiceID{}
|
||||
}
|
||||
return NewServiceID(cfg.Name, &cfg.EnterpriseMeta)
|
||||
}
|
||||
|
||||
func (cfg *UpstreamConfig) ServiceName() ServiceName {
|
||||
if cfg.Name == "" {
|
||||
return ServiceName{}
|
||||
}
|
||||
return NewServiceName(cfg.Name, &cfg.EnterpriseMeta)
|
||||
}
|
||||
|
||||
func (cfg UpstreamConfig) MergeInto(dst map[string]interface{}) {
|
||||
// Avoid storing empty values in the map, since these can act as overrides
|
||||
if cfg.EnvoyListenerJSON != "" {
|
||||
|
@ -713,15 +756,48 @@ func (cfg UpstreamConfig) MergeInto(dst map[string]interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (cfg *UpstreamConfig) Normalize() {
|
||||
func (cfg *UpstreamConfig) NormalizeWithoutName() error {
|
||||
return cfg.normalize(false, nil)
|
||||
}
|
||||
func (cfg *UpstreamConfig) NormalizeWithName(entMeta *EnterpriseMeta) error {
|
||||
return cfg.normalize(true, entMeta)
|
||||
}
|
||||
func (cfg *UpstreamConfig) normalize(named bool, entMeta *EnterpriseMeta) error {
|
||||
if named {
|
||||
// If the upstream namespace is omitted it inherits that of the enclosing
|
||||
// config entry.
|
||||
cfg.EnterpriseMeta.MergeNoWildcard(entMeta)
|
||||
cfg.EnterpriseMeta.Normalize()
|
||||
}
|
||||
|
||||
cfg.Protocol = strings.ToLower(cfg.Protocol)
|
||||
|
||||
if cfg.ConnectTimeoutMs < 0 {
|
||||
cfg.ConnectTimeoutMs = 0
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg UpstreamConfig) Validate() error {
|
||||
func (cfg UpstreamConfig) ValidateWithoutName() error {
|
||||
return cfg.validate(false)
|
||||
}
|
||||
func (cfg UpstreamConfig) ValidateWithName() error {
|
||||
return cfg.validate(true)
|
||||
}
|
||||
func (cfg UpstreamConfig) validate(named bool) error {
|
||||
if named {
|
||||
if cfg.Name == "" {
|
||||
return fmt.Errorf("Name is required")
|
||||
}
|
||||
} else {
|
||||
if cfg.Name != "" {
|
||||
return fmt.Errorf("Name must be empty")
|
||||
}
|
||||
if cfg.EnterpriseMeta.NamespaceOrEmpty() != "" {
|
||||
return fmt.Errorf("Namespace must be empty")
|
||||
}
|
||||
}
|
||||
|
||||
var validationErr error
|
||||
|
||||
if cfg.PassiveHealthCheck != nil {
|
||||
|
@ -758,8 +834,11 @@ func ParseUpstreamConfigNoDefaults(m map[string]interface{}) (UpstreamConfig, er
|
|||
return cfg, err
|
||||
}
|
||||
|
||||
err = decoder.Decode(m)
|
||||
cfg.Normalize()
|
||||
if err := decoder.Decode(m); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
err = cfg.NormalizeWithoutName()
|
||||
|
||||
return cfg, err
|
||||
}
|
||||
|
@ -791,6 +870,14 @@ type PassiveHealthCheck struct {
|
|||
MaxFailures uint32 `json:",omitempty" alias:"max_failures"`
|
||||
}
|
||||
|
||||
func (chk *PassiveHealthCheck) Clone() *PassiveHealthCheck {
|
||||
if chk == nil {
|
||||
return nil
|
||||
}
|
||||
chk2 := *chk
|
||||
return &chk2
|
||||
}
|
||||
|
||||
func (chk *PassiveHealthCheck) IsZero() bool {
|
||||
zeroVal := PassiveHealthCheck{}
|
||||
return *chk == zeroVal
|
||||
|
@ -822,6 +909,25 @@ type UpstreamLimits struct {
|
|||
MaxConcurrentRequests *int `json:",omitempty" alias:"max_concurrent_requests"`
|
||||
}
|
||||
|
||||
func (ul *UpstreamLimits) Clone() *UpstreamLimits {
|
||||
if ul == nil {
|
||||
return nil
|
||||
}
|
||||
return &UpstreamLimits{
|
||||
MaxConnections: intPointerCopy(ul.MaxConnections),
|
||||
MaxPendingRequests: intPointerCopy(ul.MaxPendingRequests),
|
||||
MaxConcurrentRequests: intPointerCopy(ul.MaxConcurrentRequests),
|
||||
}
|
||||
}
|
||||
|
||||
func intPointerCopy(v *int) *int {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
v2 := *v
|
||||
return &v2
|
||||
}
|
||||
|
||||
func (ul *UpstreamLimits) IsZero() bool {
|
||||
zeroVal := UpstreamLimits{}
|
||||
return *ul == zeroVal
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
"github.com/hashicorp/hcl"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
)
|
||||
|
||||
// TestDecodeConfigEntry is the 'structs' mirror image of
|
||||
|
@ -113,22 +115,23 @@ func TestDecodeConfigEntry(t *testing.T) {
|
|||
mesh_gateway {
|
||||
mode = "remote"
|
||||
}
|
||||
connect {
|
||||
upstream_configs {
|
||||
redis {
|
||||
upstream_config {
|
||||
overrides = [
|
||||
{
|
||||
name = "redis"
|
||||
passive_health_check {
|
||||
interval = "2s"
|
||||
max_failures = 3
|
||||
}
|
||||
}
|
||||
|
||||
"finance/billing" {
|
||||
},
|
||||
{
|
||||
name = "finance--billing"
|
||||
mesh_gateway {
|
||||
mode = "remote"
|
||||
}
|
||||
}
|
||||
}
|
||||
upstream_defaults {
|
||||
},
|
||||
]
|
||||
defaults {
|
||||
connect_timeout_ms = 5
|
||||
protocol = "http"
|
||||
envoy_listener_json = "foo"
|
||||
|
@ -153,22 +156,23 @@ func TestDecodeConfigEntry(t *testing.T) {
|
|||
MeshGateway {
|
||||
Mode = "remote"
|
||||
}
|
||||
Connect {
|
||||
UpstreamConfigs {
|
||||
"redis" {
|
||||
UpstreamConfig {
|
||||
Overrides = [
|
||||
{
|
||||
Name = "redis"
|
||||
PassiveHealthCheck {
|
||||
MaxFailures = 3
|
||||
Interval = "2s"
|
||||
}
|
||||
}
|
||||
|
||||
"finance/billing" {
|
||||
},
|
||||
{
|
||||
Name = "finance--billing"
|
||||
MeshGateway {
|
||||
Mode = "remote"
|
||||
}
|
||||
}
|
||||
}
|
||||
UpstreamDefaults {
|
||||
},
|
||||
]
|
||||
Defaults {
|
||||
EnvoyListenerJSON = "foo"
|
||||
EnvoyClusterJSON = "bar"
|
||||
ConnectTimeoutMs = 5
|
||||
|
@ -193,19 +197,21 @@ func TestDecodeConfigEntry(t *testing.T) {
|
|||
MeshGateway: MeshGatewayConfig{
|
||||
Mode: MeshGatewayModeRemote,
|
||||
},
|
||||
Connect: &ConnectConfiguration{
|
||||
UpstreamConfigs: map[string]*UpstreamConfig{
|
||||
"redis": {
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "redis",
|
||||
PassiveHealthCheck: &PassiveHealthCheck{
|
||||
MaxFailures: 3,
|
||||
Interval: 2 * time.Second,
|
||||
},
|
||||
},
|
||||
"finance/billing": {
|
||||
{
|
||||
Name: "finance--billing",
|
||||
MeshGateway: MeshGatewayConfig{Mode: MeshGatewayModeRemote},
|
||||
},
|
||||
},
|
||||
UpstreamDefaults: &UpstreamConfig{
|
||||
Defaults: &UpstreamConfig{
|
||||
EnvoyListenerJSON: "foo",
|
||||
EnvoyClusterJSON: "bar",
|
||||
ConnectTimeoutMs: 5,
|
||||
|
@ -1537,6 +1543,75 @@ func TestServiceConfigEntry_Normalize(t *testing.T) {
|
|||
input ServiceConfigEntry
|
||||
expect ServiceConfigEntry
|
||||
}{
|
||||
{
|
||||
// This will do nothing to normalization, but it will fail at validation later
|
||||
name: "upstream config override no name",
|
||||
input: ServiceConfigEntry{
|
||||
Name: "web",
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "good",
|
||||
Protocol: "grpc",
|
||||
},
|
||||
{
|
||||
Protocol: "http2",
|
||||
},
|
||||
{
|
||||
Name: "also-good",
|
||||
Protocol: "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: ServiceConfigEntry{
|
||||
Kind: ServiceDefaults,
|
||||
Name: "web",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "good",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
Protocol: "grpc",
|
||||
},
|
||||
{
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
Protocol: "http2",
|
||||
},
|
||||
{
|
||||
Name: "also-good",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
Protocol: "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// This will do nothing to normalization, but it will fail at validation later
|
||||
name: "upstream config defaults with name",
|
||||
input: ServiceConfigEntry{
|
||||
Name: "web",
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Defaults: &UpstreamConfig{
|
||||
Name: "also-good",
|
||||
Protocol: "http2",
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: ServiceConfigEntry{
|
||||
Kind: ServiceDefaults,
|
||||
Name: "web",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Defaults: &UpstreamConfig{
|
||||
Name: "also-good",
|
||||
Protocol: "http2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fill-in-kind",
|
||||
input: ServiceConfigEntry{
|
||||
|
@ -1567,33 +1642,39 @@ func TestServiceConfigEntry_Normalize(t *testing.T) {
|
|||
input: ServiceConfigEntry{
|
||||
Kind: ServiceDefaults,
|
||||
Name: "web",
|
||||
Connect: &ConnectConfiguration{
|
||||
UpstreamConfigs: map[string]*UpstreamConfig{
|
||||
"redis": {
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "redis",
|
||||
Protocol: "TcP",
|
||||
},
|
||||
"memcached": {
|
||||
{
|
||||
Name: "memcached",
|
||||
ConnectTimeoutMs: -1,
|
||||
},
|
||||
},
|
||||
UpstreamDefaults: &UpstreamConfig{ConnectTimeoutMs: -20},
|
||||
Defaults: &UpstreamConfig{ConnectTimeoutMs: -20},
|
||||
},
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
},
|
||||
expect: ServiceConfigEntry{
|
||||
Kind: ServiceDefaults,
|
||||
Name: "web",
|
||||
Connect: &ConnectConfiguration{
|
||||
UpstreamConfigs: map[string]*UpstreamConfig{
|
||||
"redis": {
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "redis",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
Protocol: "tcp",
|
||||
ConnectTimeoutMs: 0,
|
||||
},
|
||||
"memcached": {
|
||||
{
|
||||
Name: "memcached",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
ConnectTimeoutMs: 0,
|
||||
},
|
||||
},
|
||||
UpstreamDefaults: &UpstreamConfig{
|
||||
Defaults: &UpstreamConfig{
|
||||
ConnectTimeoutMs: 0,
|
||||
},
|
||||
},
|
||||
|
@ -1611,6 +1692,108 @@ func TestServiceConfigEntry_Normalize(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServiceConfigEntry_Validate(t *testing.T) {
|
||||
tt := []struct {
|
||||
name string
|
||||
input *ServiceConfigEntry
|
||||
expect *ServiceConfigEntry
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "upstream config override no name",
|
||||
input: &ServiceConfigEntry{
|
||||
Name: "web",
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "good",
|
||||
Protocol: "grpc",
|
||||
},
|
||||
{
|
||||
Protocol: "http2",
|
||||
},
|
||||
{
|
||||
Name: "also-good",
|
||||
Protocol: "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: `error in upstream override for : Name is required`,
|
||||
},
|
||||
{
|
||||
name: "upstream config defaults with name",
|
||||
input: &ServiceConfigEntry{
|
||||
Name: "web",
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Defaults: &UpstreamConfig{
|
||||
Name: "also-good",
|
||||
Protocol: "http2",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: `error in upstream defaults: Name must be empty`,
|
||||
},
|
||||
{
|
||||
name: "connect-kitchen-sink",
|
||||
input: &ServiceConfigEntry{
|
||||
Kind: ServiceDefaults,
|
||||
Name: "web",
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "redis",
|
||||
Protocol: "TcP",
|
||||
},
|
||||
{
|
||||
Name: "memcached",
|
||||
ConnectTimeoutMs: -1,
|
||||
},
|
||||
},
|
||||
Defaults: &UpstreamConfig{ConnectTimeoutMs: -20},
|
||||
},
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
},
|
||||
expect: &ServiceConfigEntry{
|
||||
Kind: ServiceDefaults,
|
||||
Name: "web",
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "redis",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
Protocol: "tcp",
|
||||
ConnectTimeoutMs: 0,
|
||||
},
|
||||
{
|
||||
Name: "memcached",
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
ConnectTimeoutMs: 0,
|
||||
},
|
||||
},
|
||||
Defaults: &UpstreamConfig{ConnectTimeoutMs: 0},
|
||||
},
|
||||
EnterpriseMeta: *DefaultEnterpriseMeta(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// normalize before validate since they always happen in that order
|
||||
require.NoError(t, tc.input.Normalize())
|
||||
|
||||
err := tc.input.Validate()
|
||||
if tc.expectErr != "" {
|
||||
testutil.RequireErrorContains(t, err, tc.expectErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expect, tc.input)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||
tt := []struct {
|
||||
name string
|
||||
|
|
|
@ -383,6 +383,7 @@ func (u *Upstream) Validate() error {
|
|||
if u.LocalBindPort == 0 && !u.CentrallyConfigured {
|
||||
return fmt.Errorf("upstream local bind port cannot be zero")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,12 @@ import (
|
|||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
bexpr "github.com/hashicorp/go-bexpr"
|
||||
"github.com/mitchellh/pointerstructure"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
)
|
||||
|
||||
var dumpFieldConfig = flag.Bool("dump-field-config", false, "generate field config dump file")
|
||||
|
|
|
@ -115,15 +115,22 @@ type ExposePath struct {
|
|||
ParsedFromCheck bool
|
||||
}
|
||||
|
||||
type ConnectConfiguration struct {
|
||||
// UpstreamConfigs is a map of <namespace/>service to per-upstream configuration
|
||||
UpstreamConfigs map[string]UpstreamConfig `json:",omitempty" alias:"upstream_configs"`
|
||||
type UpstreamConfiguration struct {
|
||||
// Overrides is a slice of per-service configuration. The name field is
|
||||
// required.
|
||||
Overrides []*UpstreamConfig `json:",omitempty"`
|
||||
|
||||
// UpstreamDefaults contains default configuration for all upstreams of a given service
|
||||
UpstreamDefaults *UpstreamConfig `json:",omitempty" alias:"upstream_defaults"`
|
||||
// Defaults contains default configuration for all upstreams of a given
|
||||
// service. The name field must be empty.
|
||||
Defaults *UpstreamConfig `json:",omitempty"`
|
||||
}
|
||||
|
||||
type UpstreamConfig struct {
|
||||
// Name is only accepted within a service-defaults config entry.
|
||||
Name string `json:",omitempty"`
|
||||
// Namespace is only accepted within a service-defaults config entry.
|
||||
Namespace string `json:",omitempty"`
|
||||
|
||||
// EnvoyListenerJSON is a complete override ("escape hatch") for the upstream's
|
||||
// listener.
|
||||
//
|
||||
|
@ -176,18 +183,18 @@ type PassiveHealthCheck struct {
|
|||
type UpstreamLimits struct {
|
||||
// MaxConnections is the maximum number of connections the local proxy can
|
||||
// make to the upstream service.
|
||||
MaxConnections int `alias:"max_connections"`
|
||||
MaxConnections *int `alias:"max_connections"`
|
||||
|
||||
// MaxPendingRequests is the maximum number of requests that will be queued
|
||||
// waiting for an available connection. This is mostly applicable to HTTP/1.1
|
||||
// clusters since all HTTP/2 requests are streamed over a single
|
||||
// connection.
|
||||
MaxPendingRequests int `alias:"max_pending_requests"`
|
||||
MaxPendingRequests *int `alias:"max_pending_requests"`
|
||||
|
||||
// MaxConcurrentRequests is the maximum number of in-flight requests that will be allowed
|
||||
// to the upstream cluster at a point in time. This is mostly applicable to HTTP/2
|
||||
// clusters since all HTTP/1.1 requests are limited by MaxConnections.
|
||||
MaxConcurrentRequests int `alias:"max_concurrent_requests"`
|
||||
MaxConcurrentRequests *int `alias:"max_concurrent_requests"`
|
||||
}
|
||||
|
||||
type ServiceConfigEntry struct {
|
||||
|
@ -198,12 +205,13 @@ type ServiceConfigEntry struct {
|
|||
Mode ProxyMode `json:",omitempty"`
|
||||
TransparentProxy *TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||
Connect *ConnectConfiguration `json:",omitempty"`
|
||||
Expose ExposeConfig `json:",omitempty"`
|
||||
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
||||
Meta map[string]string `json:",omitempty"`
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
UpstreamConfig *UpstreamConfiguration `json:",omitempty" alias:"upstream_config"`
|
||||
|
||||
Meta map[string]string `json:",omitempty"`
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
func (s *ServiceConfigEntry) GetKind() string {
|
||||
|
|
|
@ -343,21 +343,23 @@ func TestDecodeConfigEntry(t *testing.T) {
|
|||
"TransparentProxy": {
|
||||
"OutboundListenerPort": 808
|
||||
},
|
||||
"Connect": {
|
||||
"UpstreamConfigs": {
|
||||
"redis": {
|
||||
"UpstreamConfig": {
|
||||
"Overrides": [
|
||||
{
|
||||
"Name": "redis",
|
||||
"PassiveHealthCheck": {
|
||||
"MaxFailures": 3,
|
||||
"Interval": "2s"
|
||||
}
|
||||
},
|
||||
"finance/billing": {
|
||||
{
|
||||
"Name": "finance--billing",
|
||||
"MeshGateway": {
|
||||
"Mode": "remote"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpstreamDefaults": {
|
||||
],
|
||||
"Defaults": {
|
||||
"EnvoyClusterJSON": "zip",
|
||||
"EnvoyListenerJSON": "zop",
|
||||
"ConnectTimeoutMs": 5000,
|
||||
|
@ -389,27 +391,29 @@ func TestDecodeConfigEntry(t *testing.T) {
|
|||
},
|
||||
Mode: ProxyModeTransparent,
|
||||
TransparentProxy: &TransparentProxyConfig{OutboundListenerPort: 808},
|
||||
Connect: &ConnectConfiguration{
|
||||
UpstreamConfigs: map[string]UpstreamConfig{
|
||||
"redis": {
|
||||
UpstreamConfig: &UpstreamConfiguration{
|
||||
Overrides: []*UpstreamConfig{
|
||||
{
|
||||
Name: "redis",
|
||||
PassiveHealthCheck: &PassiveHealthCheck{
|
||||
MaxFailures: 3,
|
||||
Interval: 2 * time.Second,
|
||||
},
|
||||
},
|
||||
"finance/billing": {
|
||||
{
|
||||
Name: "finance--billing",
|
||||
MeshGateway: MeshGatewayConfig{Mode: "remote"},
|
||||
},
|
||||
},
|
||||
UpstreamDefaults: &UpstreamConfig{
|
||||
Defaults: &UpstreamConfig{
|
||||
EnvoyClusterJSON: "zip",
|
||||
EnvoyListenerJSON: "zop",
|
||||
Protocol: "http",
|
||||
ConnectTimeoutMs: 5000,
|
||||
Limits: &UpstreamLimits{
|
||||
MaxConnections: 3,
|
||||
MaxPendingRequests: 4,
|
||||
MaxConcurrentRequests: 5,
|
||||
MaxConnections: intPointer(3),
|
||||
MaxPendingRequests: intPointer(4),
|
||||
MaxConcurrentRequests: intPointer(5),
|
||||
},
|
||||
PassiveHealthCheck: &PassiveHealthCheck{
|
||||
MaxFailures: 5,
|
||||
|
@ -1188,3 +1192,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func intPointer(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ function main {
|
|||
gogo_proto_imp_replace="${gogo_proto_imp_replace},Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types"
|
||||
gogo_proto_imp_replace="${gogo_proto_imp_replace},Mgoogle/protobuf/empty.proto=github.com/gogo/protobuf/types"
|
||||
gogo_proto_imp_replace="${gogo_proto_imp_replace},Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types"
|
||||
gogo_proto_imp_replace="${gogo_proto_imp_replace},Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types"
|
||||
gogo_proto_imp_replace="${gogo_proto_imp_replace},Mgoogle/api/annotations.proto=github.com/gogo/googleapis/google/api"
|
||||
gogo_proto_imp_replace="${gogo_proto_imp_replace},Mgoogle/protobuf/field_mask.proto=github.com/gogo/protobuf/types"
|
||||
gogo_proto_imp_replace="${gogo_proto_imp_replace},Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types"
|
||||
|
|
|
@ -465,21 +465,32 @@ func TestParseConfigEntry(t *testing.T) {
|
|||
transparent_proxy = {
|
||||
outbound_listener_port = 10101
|
||||
}
|
||||
connect {
|
||||
upstream_configs {
|
||||
"redis" {
|
||||
upstream_config {
|
||||
overrides = [
|
||||
{
|
||||
name = "redis"
|
||||
passive_health_check {
|
||||
max_failures = 3
|
||||
interval = "2s"
|
||||
}
|
||||
}
|
||||
"finance/billing" {
|
||||
envoy_listener_json = "{ \"listener-foo\": 5 }"
|
||||
envoy_cluster_json = "{ \"cluster-bar\": 5 }"
|
||||
protocol = "grpc"
|
||||
connect_timeout_ms = 6543
|
||||
},
|
||||
{
|
||||
name = "finance--billing"
|
||||
mesh_gateway {
|
||||
mode = "remote"
|
||||
}
|
||||
limits {
|
||||
max_connections = 1111
|
||||
max_pending_requests = 2222
|
||||
max_concurrent_requests = 3333
|
||||
}
|
||||
}
|
||||
}
|
||||
upstream_defaults {
|
||||
]
|
||||
defaults {
|
||||
envoy_cluster_json = "zip"
|
||||
envoy_listener_json = "zop"
|
||||
connect_timeout_ms = 5000
|
||||
|
@ -512,33 +523,44 @@ func TestParseConfigEntry(t *testing.T) {
|
|||
TransparentProxy = {
|
||||
outbound_listener_port = 10101
|
||||
}
|
||||
connect = {
|
||||
upstream_configs = {
|
||||
"redis" = {
|
||||
passive_health_check = {
|
||||
max_failures = 3
|
||||
interval = "2s"
|
||||
UpstreamConfig {
|
||||
Overrides = [
|
||||
{
|
||||
Name = "redis"
|
||||
PassiveHealthCheck {
|
||||
MaxFailures = 3
|
||||
Interval = "2s"
|
||||
}
|
||||
EnvoyListenerJson = "{ \"listener-foo\": 5 }"
|
||||
EnvoyClusterJson = "{ \"cluster-bar\": 5 }"
|
||||
Protocol = "grpc"
|
||||
ConnectTimeoutMs = 6543
|
||||
},
|
||||
{
|
||||
Name = "finance--billing"
|
||||
MeshGateway {
|
||||
Mode = "remote"
|
||||
}
|
||||
Limits {
|
||||
MaxConnections = 1111
|
||||
MaxPendingRequests = 2222
|
||||
MaxConcurrentRequests = 3333
|
||||
}
|
||||
}
|
||||
"finance/billing" = {
|
||||
mesh_gateway = {
|
||||
mode = "remote"
|
||||
}
|
||||
]
|
||||
Defaults {
|
||||
EnvoyClusterJson = "zip"
|
||||
EnvoyListenerJson = "zop"
|
||||
ConnectTimeoutMs = 5000
|
||||
Protocol = "http"
|
||||
Limits {
|
||||
MaxConnections = 3
|
||||
MaxPendingRequests = 4
|
||||
MaxConcurrentRequests = 5
|
||||
}
|
||||
}
|
||||
upstream_defaults = {
|
||||
envoy_cluster_json = "zip"
|
||||
envoy_listener_json = "zop"
|
||||
connect_timeout_ms = 5000
|
||||
protocol = "http"
|
||||
limits = {
|
||||
max_connections = 3
|
||||
max_pending_requests = 4
|
||||
max_concurrent_requests = 5
|
||||
}
|
||||
passive_health_check = {
|
||||
max_failures = 5
|
||||
interval = "4s"
|
||||
PassiveHealthCheck {
|
||||
MaxFailures = 5
|
||||
Interval = "4s"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -560,21 +582,32 @@ func TestParseConfigEntry(t *testing.T) {
|
|||
"transparent_proxy": {
|
||||
"outbound_listener_port": 10101
|
||||
},
|
||||
"connect": {
|
||||
"upstream_configs": {
|
||||
"redis": {
|
||||
"upstream_config": {
|
||||
"overrides": [
|
||||
{
|
||||
"name": "redis",
|
||||
"passive_health_check": {
|
||||
"max_failures": 3,
|
||||
"interval": "2s"
|
||||
}
|
||||
},
|
||||
"envoy_listener_json": "{ \"listener-foo\": 5 }",
|
||||
"envoy_cluster_json": "{ \"cluster-bar\": 5 }",
|
||||
"protocol": "grpc",
|
||||
"connect_timeout_ms": 6543
|
||||
},
|
||||
"finance/billing": {
|
||||
{
|
||||
"name": "finance--billing",
|
||||
"mesh_gateway": {
|
||||
"mode": "remote"
|
||||
},
|
||||
"limits": {
|
||||
"max_connections": 1111,
|
||||
"max_pending_requests": 2222,
|
||||
"max_concurrent_requests": 3333
|
||||
}
|
||||
}
|
||||
},
|
||||
"upstream_defaults": {
|
||||
],
|
||||
"defaults": {
|
||||
"envoy_cluster_json": "zip",
|
||||
"envoy_listener_json": "zop",
|
||||
"connect_timeout_ms": 5000,
|
||||
|
@ -609,23 +642,34 @@ func TestParseConfigEntry(t *testing.T) {
|
|||
"TransparentProxy": {
|
||||
"OutboundListenerPort": 10101
|
||||
},
|
||||
"Connect": {
|
||||
"UpstreamConfigs": {
|
||||
"redis": {
|
||||
"UpstreamConfig": {
|
||||
"Overrides": [
|
||||
{
|
||||
"Name": "redis",
|
||||
"PassiveHealthCheck": {
|
||||
"MaxFailures": 3,
|
||||
"Interval": "2s"
|
||||
}
|
||||
},
|
||||
"EnvoyListenerJson": "{ \"listener-foo\": 5 }",
|
||||
"EnvoyClusterJson": "{ \"cluster-bar\": 5 }",
|
||||
"Protocol": "grpc",
|
||||
"ConnectTimeoutMs": 6543
|
||||
},
|
||||
"finance/billing": {
|
||||
{
|
||||
"Name": "finance--billing",
|
||||
"MeshGateway": {
|
||||
"Mode": "remote"
|
||||
},
|
||||
"Limits": {
|
||||
"MaxConnections": 1111,
|
||||
"MaxPendingRequests": 2222,
|
||||
"MaxConcurrentRequests": 3333
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpstreamDefaults": {
|
||||
"EnvoyClusterJSON": "zip",
|
||||
"EnvoyListenerJSON": "zop",
|
||||
],
|
||||
"Defaults": {
|
||||
"EnvoyClusterJson": "zip",
|
||||
"EnvoyListenerJson": "zop",
|
||||
"ConnectTimeoutMs": 5000,
|
||||
"Protocol": "http",
|
||||
"Limits": {
|
||||
|
@ -634,8 +678,8 @@ func TestParseConfigEntry(t *testing.T) {
|
|||
"MaxConcurrentRequests": 5
|
||||
},
|
||||
"PassiveHealthCheck": {
|
||||
"MaxFailures": 5,
|
||||
"Interval": "4s"
|
||||
"MaxFailures": 5,
|
||||
"Interval": "4s"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -657,29 +701,40 @@ func TestParseConfigEntry(t *testing.T) {
|
|||
TransparentProxy: &api.TransparentProxyConfig{
|
||||
OutboundListenerPort: 10101,
|
||||
},
|
||||
Connect: &api.ConnectConfiguration{
|
||||
UpstreamConfigs: map[string]api.UpstreamConfig{
|
||||
"redis": {
|
||||
UpstreamConfig: &api.UpstreamConfiguration{
|
||||
Overrides: []*api.UpstreamConfig{
|
||||
{
|
||||
Name: "redis",
|
||||
PassiveHealthCheck: &api.PassiveHealthCheck{
|
||||
MaxFailures: 3,
|
||||
Interval: 2 * time.Second,
|
||||
},
|
||||
EnvoyListenerJSON: `{ "listener-foo": 5 }`,
|
||||
EnvoyClusterJSON: `{ "cluster-bar": 5 }`,
|
||||
Protocol: "grpc",
|
||||
ConnectTimeoutMs: 6543,
|
||||
},
|
||||
"finance/billing": {
|
||||
{
|
||||
Name: "finance--billing",
|
||||
MeshGateway: api.MeshGatewayConfig{
|
||||
Mode: "remote",
|
||||
},
|
||||
Limits: &api.UpstreamLimits{
|
||||
MaxConnections: intPointer(1111),
|
||||
MaxPendingRequests: intPointer(2222),
|
||||
MaxConcurrentRequests: intPointer(3333),
|
||||
},
|
||||
},
|
||||
},
|
||||
UpstreamDefaults: &api.UpstreamConfig{
|
||||
Defaults: &api.UpstreamConfig{
|
||||
EnvoyClusterJSON: "zip",
|
||||
EnvoyListenerJSON: "zop",
|
||||
Protocol: "http",
|
||||
ConnectTimeoutMs: 5000,
|
||||
Limits: &api.UpstreamLimits{
|
||||
MaxConnections: 3,
|
||||
MaxPendingRequests: 4,
|
||||
MaxConcurrentRequests: 5,
|
||||
MaxConnections: intPointer(3),
|
||||
MaxPendingRequests: intPointer(4),
|
||||
MaxConcurrentRequests: intPointer(5),
|
||||
},
|
||||
PassiveHealthCheck: &api.PassiveHealthCheck{
|
||||
MaxFailures: 5,
|
||||
|
@ -2677,3 +2732,7 @@ func requireContainsLower(t *testing.T, haystack, needle string) {
|
|||
t.Helper()
|
||||
require.Contains(t, strings.ToLower(haystack), strings.ToLower(needle))
|
||||
}
|
||||
|
||||
func intPointer(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ func CheckTypeToStructs(s CheckType) structs.CheckType {
|
|||
t.Notes = s.Notes
|
||||
t.ScriptArgs = s.ScriptArgs
|
||||
t.HTTP = s.HTTP
|
||||
t.H2PING = s.H2PING
|
||||
t.Header = MapHeadersToStructs(s.Header)
|
||||
t.Method = s.Method
|
||||
t.Body = s.Body
|
||||
|
@ -21,7 +22,6 @@ func CheckTypeToStructs(s CheckType) structs.CheckType {
|
|||
t.AliasService = s.AliasService
|
||||
t.DockerContainerID = s.DockerContainerID
|
||||
t.Shell = s.Shell
|
||||
t.H2PING = s.H2PING
|
||||
t.GRPC = s.GRPC
|
||||
t.GRPCUseTLS = s.GRPCUseTLS
|
||||
t.TLSServerName = s.TLSServerName
|
||||
|
@ -44,6 +44,7 @@ func NewCheckTypeFromStructs(t structs.CheckType) CheckType {
|
|||
s.Notes = t.Notes
|
||||
s.ScriptArgs = t.ScriptArgs
|
||||
s.HTTP = t.HTTP
|
||||
s.H2PING = t.H2PING
|
||||
s.Header = NewMapHeadersFromStructs(t.Header)
|
||||
s.Method = t.Method
|
||||
s.Body = t.Body
|
||||
|
@ -53,7 +54,6 @@ func NewCheckTypeFromStructs(t structs.CheckType) CheckType {
|
|||
s.AliasService = t.AliasService
|
||||
s.DockerContainerID = t.DockerContainerID
|
||||
s.Shell = t.Shell
|
||||
s.H2PING = t.H2PING
|
||||
s.GRPC = t.GRPC
|
||||
s.GRPCUseTLS = t.GRPCUseTLS
|
||||
s.TLSServerName = t.TLSServerName
|
||||
|
@ -111,6 +111,7 @@ func HealthCheckDefinitionToStructs(s HealthCheckDefinition) structs.HealthCheck
|
|||
t.Method = s.Method
|
||||
t.Body = s.Body
|
||||
t.TCP = s.TCP
|
||||
t.H2PING = s.H2PING
|
||||
t.Interval = s.Interval
|
||||
t.OutputMaxSize = uint(s.OutputMaxSize)
|
||||
t.Timeout = s.Timeout
|
||||
|
@ -118,7 +119,6 @@ func HealthCheckDefinitionToStructs(s HealthCheckDefinition) structs.HealthCheck
|
|||
t.ScriptArgs = s.ScriptArgs
|
||||
t.DockerContainerID = s.DockerContainerID
|
||||
t.Shell = s.Shell
|
||||
t.H2PING = s.H2PING
|
||||
t.GRPC = s.GRPC
|
||||
t.GRPCUseTLS = s.GRPCUseTLS
|
||||
t.AliasNode = s.AliasNode
|
||||
|
@ -135,6 +135,7 @@ func NewHealthCheckDefinitionFromStructs(t structs.HealthCheckDefinition) Health
|
|||
s.Method = t.Method
|
||||
s.Body = t.Body
|
||||
s.TCP = t.TCP
|
||||
s.H2PING = t.H2PING
|
||||
s.Interval = t.Interval
|
||||
s.OutputMaxSize = uint32(t.OutputMaxSize)
|
||||
s.Timeout = t.Timeout
|
||||
|
@ -142,7 +143,6 @@ func NewHealthCheckDefinitionFromStructs(t structs.HealthCheckDefinition) Health
|
|||
s.ScriptArgs = t.ScriptArgs
|
||||
s.DockerContainerID = t.DockerContainerID
|
||||
s.Shell = t.Shell
|
||||
s.H2PING = t.H2PING
|
||||
s.GRPC = t.GRPC
|
||||
s.GRPCUseTLS = t.GRPCUseTLS
|
||||
s.AliasNode = t.AliasNode
|
||||
|
|
|
@ -10,12 +10,12 @@ func ConnectProxyConfigToStructs(s ConnectProxyConfig) structs.ConnectProxyConfi
|
|||
t.DestinationServiceID = s.DestinationServiceID
|
||||
t.LocalServiceAddress = s.LocalServiceAddress
|
||||
t.LocalServicePort = int(s.LocalServicePort)
|
||||
t.Mode = s.Mode
|
||||
t.Config = ProtobufTypesStructToMapStringInterface(s.Config)
|
||||
t.Upstreams = UpstreamsToStructs(s.Upstreams)
|
||||
t.MeshGateway = MeshGatewayConfigToStructs(s.MeshGateway)
|
||||
t.Expose = ExposeConfigToStructs(s.Expose)
|
||||
t.TransparentProxy = TransparentProxyConfigToStructs(s.TransparentProxy)
|
||||
t.Mode = s.Mode
|
||||
return t
|
||||
}
|
||||
func NewConnectProxyConfigFromStructs(t structs.ConnectProxyConfig) ConnectProxyConfig {
|
||||
|
@ -24,12 +24,12 @@ func NewConnectProxyConfigFromStructs(t structs.ConnectProxyConfig) ConnectProxy
|
|||
s.DestinationServiceID = t.DestinationServiceID
|
||||
s.LocalServiceAddress = t.LocalServiceAddress
|
||||
s.LocalServicePort = int32(t.LocalServicePort)
|
||||
s.Mode = t.Mode
|
||||
s.Config = MapStringInterfaceToProtobufTypesStruct(t.Config)
|
||||
s.Upstreams = NewUpstreamsFromStructs(t.Upstreams)
|
||||
s.MeshGateway = NewMeshGatewayConfigFromStructs(t.MeshGateway)
|
||||
s.Expose = NewExposeConfigFromStructs(t.Expose)
|
||||
s.TransparentProxy = NewTransparentProxyConfigFromStructs(t.TransparentProxy)
|
||||
s.Mode = t.Mode
|
||||
return s
|
||||
}
|
||||
func ExposeConfigToStructs(s ExposeConfig) structs.ExposeConfig {
|
||||
|
@ -72,16 +72,6 @@ func NewMeshGatewayConfigFromStructs(t structs.MeshGatewayConfig) MeshGatewayCon
|
|||
s.Mode = t.Mode
|
||||
return s
|
||||
}
|
||||
func TransparentProxyConfigToStructs(s TransparentProxyConfig) structs.TransparentProxyConfig {
|
||||
var t structs.TransparentProxyConfig
|
||||
t.OutboundListenerPort = int(s.OutboundListenerPort)
|
||||
return t
|
||||
}
|
||||
func NewTransparentProxyConfigFromStructs(t structs.TransparentProxyConfig) TransparentProxyConfig {
|
||||
var s TransparentProxyConfig
|
||||
s.OutboundListenerPort = int32(t.OutboundListenerPort)
|
||||
return s
|
||||
}
|
||||
func ServiceConnectToStructs(s ServiceConnect) structs.ServiceConnect {
|
||||
var t structs.ServiceConnect
|
||||
t.Native = s.Native
|
||||
|
@ -134,6 +124,16 @@ func NewServiceDefinitionFromStructs(t structs.ServiceDefinition) ServiceDefinit
|
|||
s.Connect = NewServiceConnectPtrFromStructs(t.Connect)
|
||||
return s
|
||||
}
|
||||
func TransparentProxyConfigToStructs(s TransparentProxyConfig) structs.TransparentProxyConfig {
|
||||
var t structs.TransparentProxyConfig
|
||||
t.OutboundListenerPort = int(s.OutboundListenerPort)
|
||||
return t
|
||||
}
|
||||
func NewTransparentProxyConfigFromStructs(t structs.TransparentProxyConfig) TransparentProxyConfig {
|
||||
var s TransparentProxyConfig
|
||||
s.OutboundListenerPort = int32(t.OutboundListenerPort)
|
||||
return s
|
||||
}
|
||||
func UpstreamToStructs(s Upstream) structs.Upstream {
|
||||
var t structs.Upstream
|
||||
t.DestinationType = s.DestinationType
|
||||
|
|
|
@ -395,6 +395,7 @@ var xxx_messageInfo_MeshGatewayConfig proto.InternalMessageInfo
|
|||
// output=service.gen.go
|
||||
// name=Structs
|
||||
type TransparentProxyConfig struct {
|
||||
// mog: func-to=int func-from=int32
|
||||
OutboundListenerPort int32 `protobuf:"varint,1,opt,name=OutboundListenerPort,proto3" json:"OutboundListenerPort,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,7 @@ message MeshGatewayConfig {
|
|||
// output=service.gen.go
|
||||
// name=Structs
|
||||
message TransparentProxyConfig {
|
||||
// mog: func-to=int func-from=int32
|
||||
int32 OutboundListenerPort = 1;
|
||||
}
|
||||
|
||||
|
@ -273,4 +274,4 @@ message Weights {
|
|||
int32 Passing = 1;
|
||||
// mog: func-to=int func-from=int32
|
||||
int32 Warning = 2;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue