diff --git a/agent/structs/config_entry.go b/agent/structs/config_entry.go index 73a797eb2eba..5be0a5089823 100644 --- a/agent/structs/config_entry.go +++ b/agent/structs/config_entry.go @@ -38,6 +38,8 @@ const ( MeshConfigMesh string = "mesh" DefaultServiceProtocol = "tcp" + + ConnectionExactBalance = "exact_balance" ) var AllConfigEntryKinds = []string{ @@ -184,6 +186,10 @@ func (e *ServiceConfigEntry) Validate() error { validationErr := validateConfigEntryMeta(e.Meta) + if !isValidConnectionBalance(e.BalanceInboundConnections) { + validationErr = multierror.Append(validationErr, fmt.Errorf("invalid value for balance_inbound_connections: %v", e.BalanceInboundConnections)) + } + // External endpoints are invalid with an existing service's upstream configuration if e.UpstreamConfig != nil && e.Destination != nil { validationErr = multierror.Append(validationErr, errors.New("UpstreamConfig and Destination are mutually exclusive for service defaults")) @@ -925,6 +931,10 @@ func (cfg UpstreamConfig) validate(named bool) error { } } + if !isValidConnectionBalance(cfg.BalanceOutboundConnections) { + validationErr = multierror.Append(validationErr, fmt.Errorf("invalid value for balance_outbound_connections: %v", cfg.BalanceOutboundConnections)) + } + return validationErr } @@ -1230,3 +1240,7 @@ func validateConfigEntryMeta(meta map[string]string) error { type ConfigEntryDeleteResponse struct { Deleted bool } + +func isValidConnectionBalance(s string) bool { + return s == "" || s == ConnectionExactBalance +} diff --git a/agent/structs/config_entry_test.go b/agent/structs/config_entry_test.go index 22cf7309a0e9..6aca9af4eaf9 100644 --- a/agent/structs/config_entry_test.go +++ b/agent/structs/config_entry_test.go @@ -340,7 +340,7 @@ func TestDecodeConfigEntry(t *testing.T) { "moreconfig" { "moar" = "config" } - "balance_inbound_connections" = "exact_balance" + "balance_inbound_connections" = "exact_balance" } mesh_gateway { mode = "remote" @@ -359,7 +359,7 @@ func TestDecodeConfigEntry(t *testing.T) { "moreconfig" { "moar" = "config" } - "balance_inbound_connections" = "exact_balance" + "balance_inbound_connections" = "exact_balance" } MeshGateway { Mode = "remote" @@ -399,6 +399,7 @@ func TestDecodeConfigEntry(t *testing.T) { mesh_gateway { mode = "remote" } + balance_inbound_connections = "exact_balance" upstream_config { overrides = [ { @@ -441,6 +442,7 @@ func TestDecodeConfigEntry(t *testing.T) { MeshGateway { Mode = "remote" } + BalanceInboundConnections = "exact_balance" UpstreamConfig { Overrides = [ { @@ -483,6 +485,7 @@ func TestDecodeConfigEntry(t *testing.T) { MeshGateway: MeshGatewayConfig{ Mode: MeshGatewayModeRemote, }, + BalanceInboundConnections: "exact_balance", UpstreamConfig: &UpstreamConfiguration{ Overrides: []*UpstreamConfig{ { @@ -2657,6 +2660,44 @@ func TestServiceConfigEntry(t *testing.T) { }, validateErr: "Duplicate address", }, + "validate: invalid inbound connection balance": { + entry: &ServiceConfigEntry{ + Kind: ServiceDefaults, + Name: "external", + Protocol: "http", + BalanceInboundConnections: "invalid", + }, + validateErr: "invalid value for balance_inbound_connections", + }, + "validate: invalid default outbound connection balance": { + entry: &ServiceConfigEntry{ + Kind: ServiceDefaults, + Name: "external", + Protocol: "http", + UpstreamConfig: &UpstreamConfiguration{ + Defaults: &UpstreamConfig{ + BalanceOutboundConnections: "invalid", + }, + }, + }, + validateErr: "invalid value for balance_outbound_connections", + }, + "validate: invalid override outbound connection balance": { + entry: &ServiceConfigEntry{ + Kind: ServiceDefaults, + Name: "external", + Protocol: "http", + UpstreamConfig: &UpstreamConfiguration{ + Overrides: []*UpstreamConfig{ + { + Name: "upstream", + BalanceOutboundConnections: "invalid", + }, + }, + }, + }, + validateErr: "invalid value for balance_outbound_connections", + }, } testConfigEntryNormalizeAndValidate(t, cases) } diff --git a/agent/xds/listeners.go b/agent/xds/listeners.go index d0ac2700868f..9f9136bf3f67 100644 --- a/agent/xds/listeners.go +++ b/agent/xds/listeners.go @@ -190,7 +190,7 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg. } upstreamListener := makeListener(uid.EnvoyID(), upstreamCfg, envoy_core_v3.TrafficDirection_OUTBOUND) - injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener) + s.injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener) upstreamListener.FilterChains = []*envoy_listener_v3.FilterChain{ filterChain, } @@ -386,7 +386,7 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg. } upstreamListener := makeListener(uid.EnvoyID(), upstreamCfg, envoy_core_v3.TrafficDirection_OUTBOUND) - injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener) + s.injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener) upstreamListener.FilterChains = []*envoy_listener_v3.FilterChain{ filterChain, @@ -562,7 +562,7 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg. } upstreamListener := makeListener(uid.EnvoyID(), u, envoy_core_v3.TrafficDirection_OUTBOUND) - injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener) + s.injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener) filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{ // TODO (SNI partition) add partition for upstream SNI @@ -909,11 +909,16 @@ func makeListenerFromUserConfig(configJSON string) (*envoy_listener_v3.Listener, return &l, nil } -func injectConnectionBalanceConfig(balanceType string, listener *envoy_listener_v3.Listener) { - if balanceType == "exact_balance" { +func (s *ResourceGenerator) injectConnectionBalanceConfig(balanceType string, listener *envoy_listener_v3.Listener) { + switch balanceType { + case "": + // Default with no balancing. + case structs.ConnectionExactBalance: listener.ConnectionBalanceConfig = &envoy_listener_v3.Listener_ConnectionBalanceConfig{ BalanceType: &envoy_listener_v3.Listener_ConnectionBalanceConfig_ExactBalance_{}, } + default: + s.Logger.Warn("ignoring invalid connection balance option", "value", balanceType) } } @@ -1233,7 +1238,7 @@ func (s *ResourceGenerator) makeInboundListener(cfgSnap *proxycfg.ConfigSnapshot } l = makePortListener(name, addr, port, envoy_core_v3.TrafficDirection_INBOUND) - injectConnectionBalanceConfig(cfg.BalanceInboundConnections, l) + s.injectConnectionBalanceConfig(cfg.BalanceInboundConnections, l) var tracing *envoy_http_v3.HttpConnectionManager_Tracing if cfg.ListenerTracingJSON != "" {