Add Upstream Service Targeting to Property Override Extension (#17517)
* add upstream service targeting to property override extension * Also add baseline goldens for service specific property override extension. * Refactor the extension framework to put more logic into the templates. * fix up the golden tests
This commit is contained in:
parent
e5cdb702e5
commit
bbf0b70b52
|
@ -72,16 +72,19 @@ func (a *awsLambda) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
||||||
|
|
||||||
// PatchRoute modifies the routing configuration for a service of kind TerminatingGateway. If the kind is
|
// PatchRoute modifies the routing configuration for a service of kind TerminatingGateway. If the kind is
|
||||||
// not TerminatingGateway, then it can not be modified.
|
// not TerminatingGateway, then it can not be modified.
|
||||||
func (a *awsLambda) PatchRoute(r *extensioncommon.RuntimeConfig, route *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
func (a *awsLambda) PatchRoute(p extensioncommon.RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||||
if r.Kind != api.ServiceKindTerminatingGateway {
|
cfg := p.RuntimeConfig
|
||||||
return route, false, nil
|
if cfg.Kind != api.ServiceKindTerminatingGateway {
|
||||||
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only patch outbound routes.
|
// Only patch outbound routes.
|
||||||
if extensioncommon.IsRouteToLocalAppCluster(route) {
|
if p.IsInbound() {
|
||||||
return route, false, nil
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
route := p.Message
|
||||||
|
|
||||||
for _, virtualHost := range route.VirtualHosts {
|
for _, virtualHost := range route.VirtualHosts {
|
||||||
for _, route := range virtualHost.Routes {
|
for _, route := range virtualHost.Routes {
|
||||||
action, ok := route.Action.(*envoy_route_v3.Route_Route)
|
action, ok := route.Action.(*envoy_route_v3.Route_Route)
|
||||||
|
@ -101,16 +104,18 @@ func (a *awsLambda) PatchRoute(r *extensioncommon.RuntimeConfig, route *envoy_ro
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchCluster patches the provided envoy cluster with data required to support an AWS lambda function
|
// PatchCluster patches the provided envoy cluster with data required to support an AWS lambda function
|
||||||
func (a *awsLambda) PatchCluster(_ *extensioncommon.RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
func (a *awsLambda) PatchCluster(p extensioncommon.ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||||
// Only patch outbound clusters.
|
// Only patch outbound clusters.
|
||||||
if extensioncommon.IsLocalAppCluster(c) {
|
if p.IsInbound() {
|
||||||
return c, false, nil
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
transportSocket, err := extensioncommon.MakeUpstreamTLSTransportSocket(&envoy_tls_v3.UpstreamTlsContext{
|
transportSocket, err := extensioncommon.MakeUpstreamTLSTransportSocket(&envoy_tls_v3.UpstreamTlsContext{
|
||||||
Sni: "*.amazonaws.com",
|
Sni: "*.amazonaws.com",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
c := p.Message
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c, false, fmt.Errorf("failed to make transport socket: %w", err)
|
return c, false, fmt.Errorf("failed to make transport socket: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -168,9 +173,11 @@ func (a *awsLambda) PatchCluster(_ *extensioncommon.RuntimeConfig, c *envoy_clus
|
||||||
|
|
||||||
// PatchFilter patches the provided envoy filter with an inserted lambda filter being careful not to
|
// PatchFilter patches the provided envoy filter with an inserted lambda filter being careful not to
|
||||||
// overwrite the http filters.
|
// overwrite the http filters.
|
||||||
func (a *awsLambda) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error) {
|
func (a *awsLambda) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||||
|
filter := p.Message
|
||||||
|
|
||||||
// Only patch outbound filters.
|
// Only patch outbound filters.
|
||||||
if isInboundListener {
|
if p.IsInbound() {
|
||||||
return filter, false, nil
|
return filter, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,7 +202,10 @@ func TestPatchCluster(t *testing.T) {
|
||||||
|
|
||||||
// Test patching the cluster
|
// Test patching the cluster
|
||||||
rc := extensioncommon.RuntimeConfig{}
|
rc := extensioncommon.RuntimeConfig{}
|
||||||
patchedCluster, patchSuccess, err := tc.lambda.PatchCluster(&rc, tc.input)
|
patchedCluster, patchSuccess, err := tc.lambda.PatchCluster(extensioncommon.ClusterPayload{
|
||||||
|
RuntimeConfig: &rc,
|
||||||
|
Message: tc.input,
|
||||||
|
})
|
||||||
if tc.isErrExpected {
|
if tc.isErrExpected {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.False(t, patchSuccess)
|
assert.False(t, patchSuccess)
|
||||||
|
@ -307,7 +310,10 @@ func TestPatchRoute(t *testing.T) {
|
||||||
for name, tc := range tests {
|
for name, tc := range tests {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
l := awsLambda{}
|
l := awsLambda{}
|
||||||
r, ok, err := l.PatchRoute(tc.conf, tc.route)
|
r, ok, err := l.PatchRoute(extensioncommon.RoutePayload{
|
||||||
|
RuntimeConfig: tc.conf,
|
||||||
|
Message: tc.route,
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tc.expectRoute, r)
|
require.Equal(t, tc.expectRoute, r)
|
||||||
require.Equal(t, tc.expectBool, ok)
|
require.Equal(t, tc.expectBool, ok)
|
||||||
|
@ -456,7 +462,14 @@ func TestPatchFilter(t *testing.T) {
|
||||||
PayloadPassthrough: true,
|
PayloadPassthrough: true,
|
||||||
InvocationMode: "asynchronous",
|
InvocationMode: "asynchronous",
|
||||||
}
|
}
|
||||||
f, ok, err := l.PatchFilter(nil, tc.filter, tc.isInboundFilter)
|
d := extensioncommon.TrafficDirectionOutbound
|
||||||
|
if tc.isInboundFilter {
|
||||||
|
d = extensioncommon.TrafficDirectionInbound
|
||||||
|
}
|
||||||
|
f, ok, err := l.PatchFilter(extensioncommon.FilterPayload{
|
||||||
|
Message: tc.filter,
|
||||||
|
TrafficDirection: d,
|
||||||
|
})
|
||||||
require.Equal(t, tc.expectBool, ok)
|
require.Equal(t, tc.expectBool, ok)
|
||||||
if tc.expectErr == "" {
|
if tc.expectErr == "" {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -601,7 +601,7 @@ func (t Target) clusterName(cfg *cmn.RuntimeConfig) (string, error) {
|
||||||
|
|
||||||
for service, upstream := range cfg.Upstreams {
|
for service, upstream := range cfg.Upstreams {
|
||||||
if service == t.Service {
|
if service == t.Service {
|
||||||
for sni := range upstream.SNI {
|
for sni := range upstream.SNIs {
|
||||||
return sni, nil
|
return sni, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,10 +102,11 @@ func (p *ratelimit) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
||||||
|
|
||||||
// PatchFilter inserts a http local rate_limit filter at the head of
|
// PatchFilter inserts a http local rate_limit filter at the head of
|
||||||
// envoy.filters.network.http_connection_manager filters
|
// envoy.filters.network.http_connection_manager filters
|
||||||
func (p ratelimit) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error) {
|
func (r ratelimit) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||||
|
filter := p.Message
|
||||||
// rate limit is only applied to the inbound listener of the service itself
|
// rate limit is only applied to the inbound listener of the service itself
|
||||||
// since the limit is aggregated from all downstream connections.
|
// since the limit is aggregated from all downstream connections.
|
||||||
if !isInboundListener {
|
if !p.IsInbound() {
|
||||||
return filter, false, nil
|
return filter, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,34 +124,34 @@ func (p ratelimit) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_l
|
||||||
|
|
||||||
tokenBucket := envoy_type_v3.TokenBucket{}
|
tokenBucket := envoy_type_v3.TokenBucket{}
|
||||||
|
|
||||||
if p.TokensPerFill != nil {
|
if r.TokensPerFill != nil {
|
||||||
tokenBucket.TokensPerFill = &wrappers.UInt32Value{
|
tokenBucket.TokensPerFill = &wrappers.UInt32Value{
|
||||||
Value: uint32(*p.TokensPerFill),
|
Value: uint32(*r.TokensPerFill),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.MaxTokens != nil {
|
if r.MaxTokens != nil {
|
||||||
tokenBucket.MaxTokens = uint32(*p.MaxTokens)
|
tokenBucket.MaxTokens = uint32(*r.MaxTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.FillInterval != nil {
|
if r.FillInterval != nil {
|
||||||
tokenBucket.FillInterval = durationpb.New(time.Duration(*p.FillInterval) * time.Second)
|
tokenBucket.FillInterval = durationpb.New(time.Duration(*r.FillInterval) * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
var FilterEnabledDefault *envoy_core_v3.RuntimeFractionalPercent
|
var FilterEnabledDefault *envoy_core_v3.RuntimeFractionalPercent
|
||||||
if p.FilterEnabled != nil {
|
if r.FilterEnabled != nil {
|
||||||
FilterEnabledDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
FilterEnabledDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
||||||
DefaultValue: &envoy_type_v3.FractionalPercent{
|
DefaultValue: &envoy_type_v3.FractionalPercent{
|
||||||
Numerator: *p.FilterEnabled,
|
Numerator: *r.FilterEnabled,
|
||||||
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var FilterEnforcedDefault *envoy_core_v3.RuntimeFractionalPercent
|
var FilterEnforcedDefault *envoy_core_v3.RuntimeFractionalPercent
|
||||||
if p.FilterEnforced != nil {
|
if r.FilterEnforced != nil {
|
||||||
FilterEnforcedDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
FilterEnforcedDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
||||||
DefaultValue: &envoy_type_v3.FractionalPercent{
|
DefaultValue: &envoy_type_v3.FractionalPercent{
|
||||||
Numerator: *p.FilterEnforced,
|
Numerator: *r.FilterEnforced,
|
||||||
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,14 +67,16 @@ func (l *lua) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
||||||
return string(config.Kind) == l.ProxyType
|
return string(config.Kind) == l.ProxyType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lua) matchesListenerDirection(isInboundListener bool) bool {
|
func (l *lua) matchesListenerDirection(p extensioncommon.FilterPayload) bool {
|
||||||
|
isInboundListener := p.IsInbound()
|
||||||
return (!isInboundListener && l.Listener == "outbound") || (isInboundListener && l.Listener == "inbound")
|
return (!isInboundListener && l.Listener == "outbound") || (isInboundListener && l.Listener == "inbound")
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchFilter inserts a lua filter directly prior to envoy.filters.http.router.
|
// PatchFilter inserts a lua filter directly prior to envoy.filters.http.router.
|
||||||
func (l *lua) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error) {
|
func (l *lua) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||||
|
filter := p.Message
|
||||||
// Make sure filter matches extension config.
|
// Make sure filter matches extension config.
|
||||||
if !l.matchesListenerDirection(isInboundListener) {
|
if !l.matchesListenerDirection(p) {
|
||||||
return filter, false, nil
|
return filter, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package propertyoverride
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
||||||
envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||||
|
@ -14,14 +13,10 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||||
"github.com/hashicorp/consul/lib/maps"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type stringSet map[string]struct{}
|
|
||||||
|
|
||||||
type propertyOverride struct {
|
type propertyOverride struct {
|
||||||
extensioncommon.BasicExtensionAdapter
|
extensioncommon.BasicExtensionAdapter
|
||||||
|
|
||||||
// Patches are an array of Patch operations to be applied to the target resource(s).
|
// Patches are an array of Patch operations to be applied to the target resource(s).
|
||||||
Patches []Patch
|
Patches []Patch
|
||||||
// Debug controls error messages when Path matching fails.
|
// Debug controls error messages when Path matching fails.
|
||||||
|
@ -43,7 +38,42 @@ type ResourceFilter struct {
|
||||||
// TrafficDirection determines whether the patch will be applied to a service's inbound
|
// TrafficDirection determines whether the patch will be applied to a service's inbound
|
||||||
// or outbound resources.
|
// or outbound resources.
|
||||||
// This field is required.
|
// This field is required.
|
||||||
TrafficDirection TrafficDirection
|
TrafficDirection extensioncommon.TrafficDirection
|
||||||
|
|
||||||
|
// Services indicates which upstream services will have corresponding Envoy resources patched.
|
||||||
|
// This includes directly targeted and discovery chain services. If Services is omitted or
|
||||||
|
// empty, all resources matching the filter will be targeted (including TProxy, which
|
||||||
|
// implicitly corresponds to any number of upstreams). Services must be omitted unless
|
||||||
|
// TrafficDirection is set to outbound.
|
||||||
|
Services []*ServiceName
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchesResourceFilter[K proto.Message](rf ResourceFilter, resourceType ResourceType, payload extensioncommon.Payload[K]) bool {
|
||||||
|
if resourceType != rf.ResourceType {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if payload.TrafficDirection != rf.TrafficDirection {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rf.Services) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range rf.Services {
|
||||||
|
if payload.ServiceName == nil || s.CompoundServiceName != *payload.ServiceName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceName struct {
|
||||||
|
api.CompoundServiceName
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceType is the type of Envoy resource being patched.
|
// ResourceType is the type of Envoy resource being patched.
|
||||||
|
@ -56,23 +86,13 @@ const (
|
||||||
ResourceTypeRoute ResourceType = "route"
|
ResourceTypeRoute ResourceType = "route"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ResourceTypes = stringSet{
|
var ResourceTypes = extensioncommon.StringSet{
|
||||||
string(ResourceTypeCluster): {},
|
string(ResourceTypeCluster): {},
|
||||||
string(ResourceTypeClusterLoadAssignment): {},
|
string(ResourceTypeClusterLoadAssignment): {},
|
||||||
string(ResourceTypeListener): {},
|
|
||||||
string(ResourceTypeRoute): {},
|
string(ResourceTypeRoute): {},
|
||||||
|
string(ResourceTypeListener): {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrafficDirection determines whether inbound or outbound Envoy resources will be patched.
|
|
||||||
type TrafficDirection string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TrafficDirectionInbound TrafficDirection = "inbound"
|
|
||||||
TrafficDirectionOutbound TrafficDirection = "outbound"
|
|
||||||
)
|
|
||||||
|
|
||||||
var TrafficDirections = stringSet{string(TrafficDirectionInbound): {}, string(TrafficDirectionOutbound): {}}
|
|
||||||
|
|
||||||
// Op is the type of JSON Patch operation being applied.
|
// Op is the type of JSON Patch operation being applied.
|
||||||
type Op string
|
type Op string
|
||||||
|
|
||||||
|
@ -81,10 +101,10 @@ const (
|
||||||
OpRemove Op = "remove"
|
OpRemove Op = "remove"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Ops = stringSet{string(OpAdd): {}, string(OpRemove): {}}
|
var Ops = extensioncommon.StringSet{string(OpAdd): {}, string(OpRemove): {}}
|
||||||
|
|
||||||
// validProxyTypes is the set of supported proxy types for this extension.
|
// validProxyTypes is the set of supported proxy types for this extension.
|
||||||
var validProxyTypes = stringSet{
|
var validProxyTypes = extensioncommon.StringSet{
|
||||||
string(api.ServiceKindConnectProxy): struct{}{},
|
string(api.ServiceKindConnectProxy): struct{}{},
|
||||||
string(api.ServiceKindTerminatingGateway): struct{}{},
|
string(api.ServiceKindTerminatingGateway): struct{}{},
|
||||||
}
|
}
|
||||||
|
@ -139,27 +159,58 @@ type Patch struct {
|
||||||
|
|
||||||
var _ extensioncommon.BasicExtension = (*propertyOverride)(nil)
|
var _ extensioncommon.BasicExtension = (*propertyOverride)(nil)
|
||||||
|
|
||||||
func (c *stringSet) checkRequired(v, fieldName string) error {
|
func (f *ResourceFilter) isEmpty() bool {
|
||||||
if _, ok := (*c)[v]; !ok {
|
if f == nil {
|
||||||
if v == "" {
|
return true
|
||||||
return fmt.Errorf("field %s is required", fieldName)
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("invalid %s '%q'; supported values: %s",
|
|
||||||
fieldName, v, strings.Join(maps.SliceOfKeys(*c), ", "))
|
if len(f.Services) > 0 {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
if string(f.TrafficDirection) != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(f.ResourceType) != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ResourceFilter) validate() error {
|
func (f *ResourceFilter) validate() error {
|
||||||
if f == nil || *f == (ResourceFilter{}) {
|
if f == nil || f.isEmpty() {
|
||||||
return fmt.Errorf("field ResourceFilter is required")
|
return fmt.Errorf("field ResourceFilter is required")
|
||||||
}
|
}
|
||||||
if err := ResourceTypes.checkRequired(string(f.ResourceType), "ResourceType"); err != nil {
|
if err := ResourceTypes.CheckRequired(string(f.ResourceType), "ResourceType"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := TrafficDirections.checkRequired(string(f.TrafficDirection), "TrafficDirection"); err != nil {
|
if err := extensioncommon.TrafficDirections.CheckRequired(string(f.TrafficDirection), "TrafficDirection"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := range f.Services {
|
||||||
|
sn := f.Services[i]
|
||||||
|
sn.normalize()
|
||||||
|
|
||||||
|
if err := sn.validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sn *ServiceName) normalize() {
|
||||||
|
extensioncommon.NormalizeServiceName(&sn.CompoundServiceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sn *ServiceName) validate() error {
|
||||||
|
if sn.Name == "" {
|
||||||
|
return fmt.Errorf("service name is required")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +220,7 @@ func (p *Patch) validate(debug bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := Ops.checkRequired(string(p.Op), "Op"); err != nil {
|
if err := Ops.CheckRequired(string(p.Op), "Op"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +260,7 @@ func (p *propertyOverride) validate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validProxyTypes.checkRequired(string(p.ProxyType), "ProxyType"); err != nil {
|
if err := validProxyTypes.CheckRequired(string(p.ProxyType), "ProxyType"); err != nil {
|
||||||
resultErr = multierror.Append(resultErr, err)
|
resultErr = multierror.Append(resultErr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,57 +294,35 @@ func (p *propertyOverride) CanApply(config *extensioncommon.RuntimeConfig) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchRoute patches the provided Envoy Route with any applicable `route` ResourceType patches.
|
// PatchRoute patches the provided Envoy Route with any applicable `route` ResourceType patches.
|
||||||
func (p *propertyOverride) PatchRoute(_ *extensioncommon.RuntimeConfig, r *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
func (p *propertyOverride) PatchRoute(payload extensioncommon.RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||||
d := TrafficDirectionOutbound
|
return patchResourceType[*envoy_route_v3.RouteConfiguration](p, ResourceTypeRoute, payload, &defaultStructPatcher[*envoy_route_v3.RouteConfiguration]{})
|
||||||
if extensioncommon.IsRouteToLocalAppCluster(r) {
|
|
||||||
d = TrafficDirectionInbound
|
|
||||||
}
|
|
||||||
return patchResourceType[*envoy_route_v3.RouteConfiguration](r, p, ResourceTypeRoute, d, &defaultStructPatcher[*envoy_route_v3.RouteConfiguration]{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchCluster patches the provided Envoy Cluster with any applicable `cluster` ResourceType patches.
|
// PatchCluster patches the provided Envoy Cluster with any applicable `cluster` ResourceType patches.
|
||||||
func (p *propertyOverride) PatchCluster(_ *extensioncommon.RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
func (p *propertyOverride) PatchCluster(payload extensioncommon.ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||||
d := TrafficDirectionOutbound
|
return patchResourceType[*envoy_cluster_v3.Cluster](p, ResourceTypeCluster, payload, &defaultStructPatcher[*envoy_cluster_v3.Cluster]{})
|
||||||
if extensioncommon.IsLocalAppCluster(c) {
|
|
||||||
d = TrafficDirectionInbound
|
|
||||||
}
|
|
||||||
return patchResourceType[*envoy_cluster_v3.Cluster](c, p, ResourceTypeCluster, d, &defaultStructPatcher[*envoy_cluster_v3.Cluster]{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchClusterLoadAssignment patches the provided Envoy ClusterLoadAssignment with any applicable `cluster-load-assignment` ResourceType patches.
|
// PatchClusterLoadAssignment patches the provided Envoy ClusterLoadAssignment with any applicable `cluster-load-assignment` ResourceType patches.
|
||||||
func (p *propertyOverride) PatchClusterLoadAssignment(_ *extensioncommon.RuntimeConfig, c *envoy_endpoint_v3.ClusterLoadAssignment) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
func (p *propertyOverride) PatchClusterLoadAssignment(payload extensioncommon.ClusterLoadAssignmentPayload) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
||||||
d := TrafficDirectionOutbound
|
return patchResourceType[*envoy_endpoint_v3.ClusterLoadAssignment](p, ResourceTypeClusterLoadAssignment, payload, &defaultStructPatcher[*envoy_endpoint_v3.ClusterLoadAssignment]{})
|
||||||
if extensioncommon.IsLocalAppClusterLoadAssignment(c) {
|
|
||||||
d = TrafficDirectionInbound
|
|
||||||
}
|
|
||||||
return patchResourceType[*envoy_endpoint_v3.ClusterLoadAssignment](c, p, ResourceTypeClusterLoadAssignment, d, &defaultStructPatcher[*envoy_endpoint_v3.ClusterLoadAssignment]{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchListener patches the provided Envoy Listener with any applicable `listener` ResourceType patches.
|
// PatchListener patches the provided Envoy Listener with any applicable `listener` ResourceType patches.
|
||||||
func (p *propertyOverride) PatchListener(_ *extensioncommon.RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, bool, error) {
|
func (p *propertyOverride) PatchListener(payload extensioncommon.ListenerPayload) (*envoy_listener_v3.Listener, bool, error) {
|
||||||
d := TrafficDirectionOutbound
|
return patchResourceType[*envoy_listener_v3.Listener](p, ResourceTypeListener, payload, &defaultStructPatcher[*envoy_listener_v3.Listener]{})
|
||||||
if extensioncommon.IsInboundPublicListener(l) {
|
|
||||||
d = TrafficDirectionInbound
|
|
||||||
}
|
|
||||||
return patchResourceType[*envoy_listener_v3.Listener](l, p, ResourceTypeListener, d, &defaultStructPatcher[*envoy_listener_v3.Listener]{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// PatchFilter does nothing as this extension does not target Filters directly.
|
|
||||||
func (p *propertyOverride) PatchFilter(_ *extensioncommon.RuntimeConfig, f *envoy_listener_v3.Filter, _ bool) (*envoy_listener_v3.Filter, bool, error) {
|
|
||||||
return f, false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// patchResourceType applies Patches matching the given ResourceType to the target K.
|
// patchResourceType applies Patches matching the given ResourceType to the target K.
|
||||||
// This helper simplifies implementation of the above per-type patch methods defined by BasicExtension.
|
// This helper simplifies implementation of the above per-type patch methods defined by BasicExtension.
|
||||||
func patchResourceType[K proto.Message](k K, p *propertyOverride, t ResourceType, d TrafficDirection, patcher structPatcher[K]) (K, bool, error) {
|
func patchResourceType[K proto.Message](p *propertyOverride, resourceType ResourceType, payload extensioncommon.Payload[K], patcher structPatcher[K]) (K, bool, error) {
|
||||||
resultPatched := false
|
resultPatched := false
|
||||||
var resultErr error
|
var resultErr error
|
||||||
|
|
||||||
|
k := payload.Message
|
||||||
|
|
||||||
for _, patch := range p.Patches {
|
for _, patch := range p.Patches {
|
||||||
if patch.ResourceFilter.ResourceType != t {
|
if !matchesResourceFilter(patch.ResourceFilter, resourceType, payload) {
|
||||||
continue
|
|
||||||
}
|
|
||||||
if patch.ResourceFilter.TrafficDirection != d {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newK, err := patcher.applyPatch(k, patch, p.Debug)
|
newK, err := patcher.applyPatch(k, patch, p.Debug)
|
||||||
|
|
|
@ -2,11 +2,13 @@ package propertyoverride
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
||||||
|
endpointv3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||||
|
listenerv3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||||
|
routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -32,7 +34,7 @@ func TestConstructor(t *testing.T) {
|
||||||
makeResourceFilter := func(overrides map[string]any) map[string]any {
|
makeResourceFilter := func(overrides map[string]any) map[string]any {
|
||||||
f := map[string]any{
|
f := map[string]any{
|
||||||
"ResourceType": ResourceTypeRoute,
|
"ResourceType": ResourceTypeRoute,
|
||||||
"TrafficDirection": TrafficDirectionOutbound,
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
}
|
}
|
||||||
return applyOverrides(f, overrides)
|
return applyOverrides(f, overrides)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +65,7 @@ func TestConstructor(t *testing.T) {
|
||||||
errMsg string
|
errMsg string
|
||||||
}
|
}
|
||||||
|
|
||||||
validTestCase := func(o Op, d TrafficDirection, t ResourceType) testCase {
|
validTestCase := func(o Op, d extensioncommon.TrafficDirection, t ResourceType) testCase {
|
||||||
var v any = "foo"
|
var v any = "foo"
|
||||||
if o != OpAdd {
|
if o != OpAdd {
|
||||||
v = nil
|
v = nil
|
||||||
|
@ -214,6 +216,19 @@ func TestConstructor(t *testing.T) {
|
||||||
ok: false,
|
ok: false,
|
||||||
errMsg: fmt.Sprintf("field Value is not supported for %s operation", OpRemove),
|
errMsg: fmt.Sprintf("field Value is not supported for %s operation", OpRemove),
|
||||||
},
|
},
|
||||||
|
"empty service name": {
|
||||||
|
arguments: makeArguments(map[string]any{"Patches": []map[string]any{
|
||||||
|
makePatch(map[string]any{
|
||||||
|
"ResourceFilter": makeResourceFilter(map[string]any{
|
||||||
|
"Services": []ServiceName{
|
||||||
|
{CompoundServiceName: api.CompoundServiceName{}},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}}),
|
||||||
|
ok: false,
|
||||||
|
errMsg: "service name is required",
|
||||||
|
},
|
||||||
// See decode.HookWeakDecodeFromSlice for more details. In practice, we can end up
|
// See decode.HookWeakDecodeFromSlice for more details. In practice, we can end up
|
||||||
// with a "Patches" field decoded to the single "Patch" value contained in the
|
// with a "Patches" field decoded to the single "Patch" value contained in the
|
||||||
// serialized slice (raised from the containing slice). Using WeakDecode solves
|
// serialized slice (raised from the containing slice). Using WeakDecode solves
|
||||||
|
@ -222,7 +237,7 @@ func TestConstructor(t *testing.T) {
|
||||||
// by WeakDecode as it is a more-permissive version of the default behavior.
|
// by WeakDecode as it is a more-permissive version of the default behavior.
|
||||||
"single value Patches decoded as map construction succeeds": {
|
"single value Patches decoded as map construction succeeds": {
|
||||||
arguments: makeArguments(map[string]any{"Patches": makePatch(map[string]any{})}),
|
arguments: makeArguments(map[string]any{"Patches": makePatch(map[string]any{})}),
|
||||||
expected: validTestCase(OpAdd, TrafficDirectionOutbound, ResourceTypeRoute).expected,
|
expected: validTestCase(OpAdd, extensioncommon.TrafficDirectionOutbound, ResourceTypeRoute).expected,
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
"invalid ProxyType": {
|
"invalid ProxyType": {
|
||||||
|
@ -248,10 +263,10 @@ func TestConstructor(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for o := range Ops {
|
for o := range Ops {
|
||||||
for d := range TrafficDirections {
|
for d := range extensioncommon.TrafficDirections {
|
||||||
for t := range ResourceTypes {
|
for t := range ResourceTypes {
|
||||||
cases["valid everything: "+strings.Join([]string{o, d, t}, ",")] =
|
cases["valid everything: "+strings.Join([]string{o, d, t}, ",")] =
|
||||||
validTestCase(Op(o), TrafficDirection(d), ResourceType(t))
|
validTestCase(Op(o), extensioncommon.TrafficDirection(d), ResourceType(t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,32 +309,62 @@ func Test_patchResourceType(t *testing.T) {
|
||||||
Patches: patches,
|
Patches: patches,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
makePatchWithPath := func(t ResourceType, d TrafficDirection, p string) Patch {
|
makePatchWithPath := func(filter ResourceFilter, p string) Patch {
|
||||||
return Patch{
|
return Patch{
|
||||||
ResourceFilter: ResourceFilter{
|
ResourceFilter: filter,
|
||||||
ResourceType: t,
|
|
||||||
TrafficDirection: d,
|
|
||||||
},
|
|
||||||
Op: OpAdd,
|
Op: OpAdd,
|
||||||
Path: p,
|
Path: p,
|
||||||
Value: 1,
|
Value: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
makePatch := func(t ResourceType, d TrafficDirection) Patch {
|
makePatch := func(filter ResourceFilter) Patch {
|
||||||
return makePatchWithPath(t, d, "/foo")
|
return makePatchWithPath(filter, "/foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterOutbound := makePatch(ResourceTypeCluster, TrafficDirectionOutbound)
|
svc1 := ServiceName{
|
||||||
clusterInbound := makePatch(ResourceTypeCluster, TrafficDirectionInbound)
|
CompoundServiceName: api.CompoundServiceName{Name: "svc1"},
|
||||||
routeOutbound := makePatch(ResourceTypeRoute, TrafficDirectionOutbound)
|
}
|
||||||
routeOutbound2 := makePatchWithPath(ResourceTypeRoute, TrafficDirectionOutbound, "/bar")
|
svc2 := ServiceName{
|
||||||
routeInbound := makePatch(ResourceTypeRoute, TrafficDirectionInbound)
|
CompoundServiceName: api.CompoundServiceName{Name: "svc2"},
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterOutbound := makePatch(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeCluster,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
})
|
||||||
|
clusterInbound := makePatch(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeCluster,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||||
|
})
|
||||||
|
listenerOutbound := makePatch(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeListener,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
})
|
||||||
|
listenerOutbound2 := makePatchWithPath(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeListener,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
}, "/bar")
|
||||||
|
listenerInbound := makePatch(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeListener,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||||
|
})
|
||||||
|
routeOutbound := makePatch(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeRoute,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
})
|
||||||
|
routeOutbound2 := makePatchWithPath(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeRoute,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
}, "/bar")
|
||||||
|
routeInbound := makePatch(ResourceFilter{
|
||||||
|
ResourceType: ResourceTypeRoute,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||||
|
})
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
d TrafficDirection
|
resourceType ResourceType
|
||||||
k proto.Message
|
payload extensioncommon.Payload[proto.Message]
|
||||||
p *propertyOverride
|
p *propertyOverride
|
||||||
t ResourceType
|
|
||||||
}
|
}
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
args args
|
args args
|
||||||
|
@ -329,79 +374,179 @@ func Test_patchResourceType(t *testing.T) {
|
||||||
cases := map[string]testCase{
|
cases := map[string]testCase{
|
||||||
"outbound gets matching patch": {
|
"outbound gets matching patch": {
|
||||||
args: args{
|
args: args{
|
||||||
d: TrafficDirectionOutbound,
|
resourceType: ResourceTypeCluster,
|
||||||
k: &clusterv3.Cluster{},
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
Message: &clusterv3.Cluster{},
|
||||||
|
},
|
||||||
p: makeExtension(clusterOutbound),
|
p: makeExtension(clusterOutbound),
|
||||||
t: ResourceTypeCluster,
|
|
||||||
},
|
},
|
||||||
expectPatched: true,
|
expectPatched: true,
|
||||||
wantApplied: []Patch{clusterOutbound},
|
wantApplied: []Patch{clusterOutbound},
|
||||||
},
|
},
|
||||||
"inbound gets matching patch": {
|
"inbound gets matching patch": {
|
||||||
args: args{
|
args: args{
|
||||||
d: TrafficDirectionInbound,
|
resourceType: ResourceTypeCluster,
|
||||||
k: &clusterv3.Cluster{},
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||||
|
Message: &clusterv3.Cluster{},
|
||||||
|
},
|
||||||
p: makeExtension(clusterInbound),
|
p: makeExtension(clusterInbound),
|
||||||
t: ResourceTypeCluster,
|
|
||||||
},
|
},
|
||||||
expectPatched: true,
|
expectPatched: true,
|
||||||
wantApplied: []Patch{clusterInbound},
|
wantApplied: []Patch{clusterInbound},
|
||||||
},
|
},
|
||||||
"multiple resources same direction only gets matching resource": {
|
"multiple resources same direction only gets matching resource": {
|
||||||
args: args{
|
args: args{
|
||||||
d: TrafficDirectionOutbound,
|
resourceType: ResourceTypeCluster,
|
||||||
k: &clusterv3.Cluster{},
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
p: makeExtension(clusterOutbound, routeOutbound),
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
t: ResourceTypeCluster,
|
Message: &clusterv3.Cluster{},
|
||||||
|
},
|
||||||
|
p: makeExtension(clusterOutbound, listenerOutbound),
|
||||||
},
|
},
|
||||||
expectPatched: true,
|
expectPatched: true,
|
||||||
wantApplied: []Patch{clusterOutbound},
|
wantApplied: []Patch{clusterOutbound},
|
||||||
},
|
},
|
||||||
"multiple directions same resource only gets matching direction": {
|
"multiple directions same resource only gets matching direction": {
|
||||||
args: args{
|
args: args{
|
||||||
d: TrafficDirectionOutbound,
|
resourceType: ResourceTypeCluster,
|
||||||
k: &clusterv3.Cluster{},
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
Message: &clusterv3.Cluster{},
|
||||||
|
},
|
||||||
p: makeExtension(clusterOutbound, clusterInbound),
|
p: makeExtension(clusterOutbound, clusterInbound),
|
||||||
t: ResourceTypeCluster,
|
|
||||||
},
|
},
|
||||||
expectPatched: true,
|
expectPatched: true,
|
||||||
wantApplied: []Patch{clusterOutbound},
|
wantApplied: []Patch{clusterOutbound},
|
||||||
},
|
},
|
||||||
"multiple directions and resources only gets matching patch": {
|
"multiple directions and resources only gets matching patch": {
|
||||||
args: args{
|
args: args{
|
||||||
d: TrafficDirectionInbound,
|
resourceType: ResourceTypeRoute,
|
||||||
k: &routev3.RouteConfiguration{},
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
p: makeExtension(clusterOutbound, clusterInbound, routeOutbound, routeInbound),
|
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||||
t: ResourceTypeRoute,
|
Message: &routev3.RouteConfiguration{},
|
||||||
|
},
|
||||||
|
p: makeExtension(clusterOutbound, clusterInbound, listenerOutbound, listenerInbound, routeOutbound, routeOutbound2, routeInbound),
|
||||||
},
|
},
|
||||||
expectPatched: true,
|
expectPatched: true,
|
||||||
wantApplied: []Patch{routeInbound},
|
wantApplied: []Patch{routeInbound},
|
||||||
},
|
},
|
||||||
"multiple directions and resources multiple matches gets all matching patches": {
|
"multiple directions and resources multiple matches gets all matching patches": {
|
||||||
args: args{
|
args: args{
|
||||||
d: TrafficDirectionOutbound,
|
resourceType: ResourceTypeRoute,
|
||||||
k: &routev3.RouteConfiguration{},
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
p: makeExtension(clusterOutbound, clusterInbound, routeOutbound, routeInbound, routeOutbound2),
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
t: ResourceTypeRoute,
|
Message: &routev3.RouteConfiguration{},
|
||||||
|
},
|
||||||
|
p: makeExtension(clusterOutbound, clusterInbound, listenerOutbound, listenerInbound, listenerOutbound2, routeOutbound, routeOutbound2, routeInbound),
|
||||||
},
|
},
|
||||||
expectPatched: true,
|
expectPatched: true,
|
||||||
wantApplied: []Patch{routeOutbound, routeOutbound2},
|
wantApplied: []Patch{routeOutbound, routeOutbound2},
|
||||||
},
|
},
|
||||||
"multiple directions and resources no matches gets no patches": {
|
"multiple directions and resources no matches gets no patches": {
|
||||||
args: args{
|
args: args{
|
||||||
d: TrafficDirectionOutbound,
|
resourceType: ResourceTypeCluster,
|
||||||
k: &routev3.RouteConfiguration{},
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
p: makeExtension(clusterInbound, routeOutbound, routeInbound, routeOutbound2),
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
t: ResourceTypeCluster,
|
Message: &clusterv3.Cluster{},
|
||||||
|
},
|
||||||
|
p: makeExtension(clusterInbound, listenerOutbound, listenerInbound, listenerOutbound2, routeInbound, routeOutbound),
|
||||||
},
|
},
|
||||||
expectPatched: false,
|
expectPatched: false,
|
||||||
wantApplied: nil,
|
wantApplied: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type resourceTypeServiceMatch struct {
|
||||||
|
resourceType ResourceType
|
||||||
|
message proto.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceTypeCases := []resourceTypeServiceMatch{
|
||||||
|
{
|
||||||
|
resourceType: ResourceTypeCluster,
|
||||||
|
message: &clusterv3.Cluster{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resourceType: ResourceTypeListener,
|
||||||
|
message: &listenerv3.Listener{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resourceType: ResourceTypeRoute,
|
||||||
|
message: &routev3.RouteConfiguration{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resourceType: ResourceTypeClusterLoadAssignment,
|
||||||
|
message: &endpointv3.ClusterLoadAssignment{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range resourceTypeCases {
|
||||||
|
{
|
||||||
|
patch := makePatch(ResourceFilter{
|
||||||
|
ResourceType: tc.resourceType,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
Services: []*ServiceName{
|
||||||
|
{CompoundServiceName: svc2.CompoundServiceName},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
cases[fmt.Sprintf("%s - no match", tc.resourceType)] = testCase{
|
||||||
|
args: args{
|
||||||
|
resourceType: tc.resourceType,
|
||||||
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
ServiceName: &svc1.CompoundServiceName,
|
||||||
|
Message: tc.message,
|
||||||
|
RuntimeConfig: &extensioncommon.RuntimeConfig{
|
||||||
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
|
svc1.CompoundServiceName: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
p: makeExtension(patch),
|
||||||
|
},
|
||||||
|
expectPatched: false,
|
||||||
|
wantApplied: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
patch := makePatch(ResourceFilter{
|
||||||
|
ResourceType: tc.resourceType,
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
Services: []*ServiceName{
|
||||||
|
{CompoundServiceName: svc2.CompoundServiceName},
|
||||||
|
{CompoundServiceName: svc1.CompoundServiceName},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
cases[fmt.Sprintf("%s - match", tc.resourceType)] = testCase{
|
||||||
|
args: args{
|
||||||
|
resourceType: tc.resourceType,
|
||||||
|
payload: extensioncommon.Payload[proto.Message]{
|
||||||
|
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||||
|
ServiceName: &svc1.CompoundServiceName,
|
||||||
|
Message: tc.message,
|
||||||
|
RuntimeConfig: &extensioncommon.RuntimeConfig{
|
||||||
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
|
svc1.CompoundServiceName: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
p: makeExtension(patch),
|
||||||
|
},
|
||||||
|
expectPatched: true,
|
||||||
|
wantApplied: []Patch{patch},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for n, tc := range cases {
|
for n, tc := range cases {
|
||||||
t.Run(n, func(t *testing.T) {
|
t.Run(n, func(t *testing.T) {
|
||||||
mockPatcher := MockPatcher[proto.Message]{}
|
mockPatcher := MockPatcher[proto.Message]{}
|
||||||
_, patched, err := patchResourceType[proto.Message](tc.args.k, tc.args.p, tc.args.t, tc.args.d, &mockPatcher)
|
_, patched, err := patchResourceType[proto.Message](tc.args.p, tc.args.resourceType, tc.args.payload, &mockPatcher)
|
||||||
|
|
||||||
require.NoError(t, err, "unexpected error from mock")
|
require.NoError(t, err, "unexpected error from mock")
|
||||||
require.Equal(t, tc.expectPatched, patched)
|
require.Equal(t, tc.expectPatched, patched)
|
||||||
|
|
|
@ -195,7 +195,7 @@ func (p *pluginConfig) asyncDataSource(rtCfg *extensioncommon.RuntimeConfig) (*e
|
||||||
clusterSNI := ""
|
clusterSNI := ""
|
||||||
for service, upstream := range rtCfg.Upstreams {
|
for service, upstream := range rtCfg.Upstreams {
|
||||||
if service == remote.HttpURI.Service {
|
if service == remote.HttpURI.Service {
|
||||||
for sni := range upstream.SNI {
|
for sni := range upstream.SNIs {
|
||||||
clusterSNI = sni
|
clusterSNI = sni
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -609,7 +609,7 @@ func makeTestRuntimeConfig(protocol string, enterprise bool) *extensioncommon.Ru
|
||||||
Namespace: acl.NamespaceOrDefault(ns),
|
Namespace: acl.NamespaceOrDefault(ns),
|
||||||
Partition: acl.PartitionOrDefault(ap),
|
Partition: acl.PartitionOrDefault(ap),
|
||||||
}: {
|
}: {
|
||||||
SNI: map[string]struct{}{"test-file-server": {}},
|
SNIs: map[string]struct{}{"test-file-server": {}},
|
||||||
EnvoyID: "test-file-server",
|
EnvoyID: "test-file-server",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,7 +34,6 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
meshGatewayExportedClusterNamePrefix = "exported~"
|
meshGatewayExportedClusterNamePrefix = "exported~"
|
||||||
failoverClusterNamePrefix = "failover-target~"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// clustersFromSnapshot returns the xDS API representation of the "clusters" in the snapshot.
|
// clustersFromSnapshot returns the xDS API representation of the "clusters" in the snapshot.
|
||||||
|
@ -1915,7 +1914,7 @@ func (s *ResourceGenerator) getTargetClusterName(upstreamsSnapshot *proxycfg.Con
|
||||||
}
|
}
|
||||||
clusterName = CustomizeClusterName(clusterName, chain)
|
clusterName = CustomizeClusterName(clusterName, chain)
|
||||||
if failover {
|
if failover {
|
||||||
clusterName = failoverClusterNamePrefix + clusterName
|
clusterName = xdscommon.FailoverClusterNamePrefix + clusterName
|
||||||
}
|
}
|
||||||
if forMeshGateway {
|
if forMeshGateway {
|
||||||
clusterName = meshGatewayExportedClusterNamePrefix + clusterName
|
clusterName = meshGatewayExportedClusterNamePrefix + clusterName
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
"github.com/hashicorp/consul/agent/xds/extensionruntime"
|
"github.com/hashicorp/consul/agent/xds/extensionruntime"
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
|
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||||
"github.com/hashicorp/consul/sdk/testutil"
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
)
|
)
|
||||||
|
@ -110,7 +111,7 @@ end`,
|
||||||
{
|
{
|
||||||
"ResourceFilter": map[string]interface{}{
|
"ResourceFilter": map[string]interface{}{
|
||||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
},
|
},
|
||||||
"Op": "add",
|
"Op": "add",
|
||||||
"Path": "/outlier_detection/success_rate_minimum_hosts",
|
"Path": "/outlier_detection/success_rate_minimum_hosts",
|
||||||
|
@ -125,7 +126,7 @@ end`,
|
||||||
{
|
{
|
||||||
"ResourceFilter": map[string]interface{}{
|
"ResourceFilter": map[string]interface{}{
|
||||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
},
|
},
|
||||||
"Op": "add",
|
"Op": "add",
|
||||||
"Path": "/outlier_detection",
|
"Path": "/outlier_detection",
|
||||||
|
@ -143,7 +144,7 @@ end`,
|
||||||
{
|
{
|
||||||
"ResourceFilter": map[string]interface{}{
|
"ResourceFilter": map[string]interface{}{
|
||||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
},
|
},
|
||||||
"Op": "remove",
|
"Op": "remove",
|
||||||
"Path": "/outlier_detection",
|
"Path": "/outlier_detection",
|
||||||
|
@ -157,7 +158,7 @@ end`,
|
||||||
{
|
{
|
||||||
"ResourceFilter": map[string]interface{}{
|
"ResourceFilter": map[string]interface{}{
|
||||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
},
|
},
|
||||||
"Op": "add",
|
"Op": "add",
|
||||||
"Path": "/upstream_connection_options/tcp_keepalive/keepalive_probes",
|
"Path": "/upstream_connection_options/tcp_keepalive/keepalive_probes",
|
||||||
|
@ -172,7 +173,7 @@ end`,
|
||||||
{
|
{
|
||||||
"ResourceFilter": map[string]interface{}{
|
"ResourceFilter": map[string]interface{}{
|
||||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
},
|
},
|
||||||
"Op": "add",
|
"Op": "add",
|
||||||
"Path": "/round_robin_lb_config",
|
"Path": "/round_robin_lb_config",
|
||||||
|
@ -181,6 +182,169 @@ end`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
propertyOverrideServiceDefaultsClusterLoadAssignmentOutboundAdd := makePropOverrideNsFunc(
|
||||||
|
map[string]interface{}{
|
||||||
|
"Patches": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeClusterLoadAssignment,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/policy/overprovisioning_factor",
|
||||||
|
"Value": 123,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
propertyOverrideServiceDefaultsClusterLoadAssignmentInboundAdd := makePropOverrideNsFunc(
|
||||||
|
map[string]interface{}{
|
||||||
|
"Patches": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeClusterLoadAssignment,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/policy/overprovisioning_factor",
|
||||||
|
"Value": 123,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
propertyOverrideServiceDefaultsListenerInboundAdd := makePropOverrideNsFunc(
|
||||||
|
map[string]interface{}{
|
||||||
|
"Patches": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/stat_prefix",
|
||||||
|
"Value": "custom.stats",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
propertyOverrideServiceDefaultsListenerOutboundAdd := makePropOverrideNsFunc(
|
||||||
|
map[string]interface{}{
|
||||||
|
"Patches": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/stat_prefix",
|
||||||
|
"Value": "custom.stats",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
propertyOverrideServiceDefaultsListenerOutboundDoesntApplyToInbound := makePropOverrideNsFunc(
|
||||||
|
map[string]interface{}{
|
||||||
|
"Patches": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/stat_prefix",
|
||||||
|
"Value": "custom.stats.inbound.only",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/stat_prefix",
|
||||||
|
"Value": "custom.stats.outbound.only",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Reverse order of above patches, to prove order is inconsequential
|
||||||
|
propertyOverrideServiceDefaultsListenerInboundDoesntApplyToOutbound := makePropOverrideNsFunc(
|
||||||
|
map[string]interface{}{
|
||||||
|
"Patches": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/stat_prefix",
|
||||||
|
"Value": "custom.stats.outbound.only",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/stat_prefix",
|
||||||
|
"Value": "custom.stats.inbound.only",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
propertyOverridePatchSpecificUpstreamService := makePropOverrideNsFunc(
|
||||||
|
map[string]interface{}{
|
||||||
|
"Patches": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
"Services": []propertyoverride.ServiceName{
|
||||||
|
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/stat_prefix",
|
||||||
|
"Value": "custom.stats.outbound.only",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeRoute,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
"Services": []propertyoverride.ServiceName{
|
||||||
|
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/most_specific_header_mutations_wins",
|
||||||
|
"Value": true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
"Services": []propertyoverride.ServiceName{
|
||||||
|
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/outlier_detection/success_rate_minimum_hosts",
|
||||||
|
"Value": 1234,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ResourceFilter": map[string]interface{}{
|
||||||
|
"ResourceType": propertyoverride.ResourceTypeClusterLoadAssignment,
|
||||||
|
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||||
|
"Services": []propertyoverride.ServiceName{
|
||||||
|
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Op": "add",
|
||||||
|
"Path": "/policy/overprovisioning_factor",
|
||||||
|
"Value": 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
create func(t testinf.T) *proxycfg.ConfigSnapshot
|
create func(t testinf.T) *proxycfg.ConfigSnapshot
|
||||||
|
@ -215,6 +379,54 @@ end`,
|
||||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsRemoveOutlierDetection, nil)
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsRemoveOutlierDetection, nil)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-cluster-load-assignment-outbound-add",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsClusterLoadAssignmentOutboundAdd, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-cluster-load-assignment-inbound-add",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsClusterLoadAssignmentInboundAdd, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-listener-outbound-add",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerOutboundAdd, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-listener-inbound-add",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerInboundAdd, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-outbound-doesnt-apply-to-inbound",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerOutboundDoesntApplyToInbound, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-inbound-doesnt-apply-to-outbound",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerInboundDoesntApplyToOutbound, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-patch-specific-upstream-service-splitter",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", false, propertyOverridePatchSpecificUpstreamService, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "propertyoverride-patch-specific-upstream-service-failover",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", false, propertyOverridePatchSpecificUpstreamService, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "lambda-connect-proxy",
|
name: "lambda-connect-proxy",
|
||||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
|
|
@ -56,19 +56,27 @@ func GetRuntimeConfigurations(cfgSnap *proxycfg.ConfigSnapshot) map[api.Compound
|
||||||
|
|
||||||
// TODO(peering): consider PeerUpstreamEndpoints in addition to DiscoveryChain
|
// TODO(peering): consider PeerUpstreamEndpoints in addition to DiscoveryChain
|
||||||
// These are the discovery chains for upstreams which have the Envoy Extensions applied to the local service.
|
// These are the discovery chains for upstreams which have the Envoy Extensions applied to the local service.
|
||||||
for uid, dc := range cfgSnap.ConnectProxy.DiscoveryChain {
|
for uid, chain := range cfgSnap.ConnectProxy.DiscoveryChain {
|
||||||
compoundServiceName := upstreamIDToCompoundServiceName(uid)
|
compoundServiceName := upstreamIDToCompoundServiceName(uid)
|
||||||
extensionsMap[compoundServiceName] = convertEnvoyExtensions(dc.EnvoyExtensions)
|
extensionsMap[compoundServiceName] = convertEnvoyExtensions(chain.EnvoyExtensions)
|
||||||
|
|
||||||
|
primarySNI := connect.ServiceSNI(uid.Name, "", chain.Namespace, chain.Partition, cfgSnap.Datacenter, trustDomain)
|
||||||
|
snis := make(map[string]struct{})
|
||||||
|
for _, t := range chain.Targets {
|
||||||
|
// SNI isn't set for peered services. We don't support peered services yet.
|
||||||
|
if t.SNI != "" {
|
||||||
|
snis[t.SNI] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
meta := uid.EnterpriseMeta
|
|
||||||
sni := connect.ServiceSNI(uid.Name, "", meta.NamespaceOrDefault(), meta.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain)
|
|
||||||
outgoingKind, ok := outgoingKindByService[compoundServiceName]
|
outgoingKind, ok := outgoingKindByService[compoundServiceName]
|
||||||
if !ok {
|
if !ok {
|
||||||
outgoingKind = api.ServiceKindConnectProxy
|
outgoingKind = api.ServiceKindConnectProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
upstreamMap[compoundServiceName] = &extensioncommon.UpstreamData{
|
upstreamMap[compoundServiceName] = &extensioncommon.UpstreamData{
|
||||||
SNI: map[string]struct{}{sni: {}},
|
PrimarySNI: primarySNI,
|
||||||
|
SNIs: snis,
|
||||||
VIP: vipForService[compoundServiceName],
|
VIP: vipForService[compoundServiceName],
|
||||||
EnvoyID: uid.EnvoyID(),
|
EnvoyID: uid.EnvoyID(),
|
||||||
OutgoingProxyKind: outgoingKind,
|
OutgoingProxyKind: outgoingKind,
|
||||||
|
@ -101,10 +109,10 @@ func GetRuntimeConfigurations(cfgSnap *proxycfg.ConfigSnapshot) map[api.Compound
|
||||||
compoundServiceName := serviceNameToCompoundServiceName(svc)
|
compoundServiceName := serviceNameToCompoundServiceName(svc)
|
||||||
extensionsMap[compoundServiceName] = convertEnvoyExtensions(c.EnvoyExtensions)
|
extensionsMap[compoundServiceName] = convertEnvoyExtensions(c.EnvoyExtensions)
|
||||||
|
|
||||||
sni := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain)
|
primarySNI := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain)
|
||||||
envoyID := proxycfg.NewUpstreamIDFromServiceName(svc)
|
envoyID := proxycfg.NewUpstreamIDFromServiceName(svc)
|
||||||
|
|
||||||
snis := map[string]struct{}{sni: {}}
|
snis := map[string]struct{}{primarySNI: {}}
|
||||||
|
|
||||||
resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc]
|
resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc]
|
||||||
if hasResolver {
|
if hasResolver {
|
||||||
|
@ -115,7 +123,8 @@ func GetRuntimeConfigurations(cfgSnap *proxycfg.ConfigSnapshot) map[api.Compound
|
||||||
}
|
}
|
||||||
|
|
||||||
upstreamMap[compoundServiceName] = &extensioncommon.UpstreamData{
|
upstreamMap[compoundServiceName] = &extensioncommon.UpstreamData{
|
||||||
SNI: snis,
|
PrimarySNI: primarySNI,
|
||||||
|
SNIs: snis,
|
||||||
EnvoyID: envoyID.EnvoyID(),
|
EnvoyID: envoyID.EnvoyID(),
|
||||||
OutgoingProxyKind: api.ServiceKindTerminatingGateway,
|
OutgoingProxyKind: api.ServiceKindTerminatingGateway,
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,28 +58,32 @@ func TestGetRuntimeConfigurations_TerminatingGateway(t *testing.T) {
|
||||||
IsSourcedFromUpstream: true,
|
IsSourcedFromUpstream: true,
|
||||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
apiService: {
|
apiService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "api.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"api.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"api.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
},
|
},
|
||||||
EnvoyID: "api",
|
EnvoyID: "api",
|
||||||
OutgoingProxyKind: "terminating-gateway",
|
OutgoingProxyKind: "terminating-gateway",
|
||||||
},
|
},
|
||||||
cacheService: {
|
cacheService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "cache.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"cache.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"cache.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
},
|
},
|
||||||
EnvoyID: "cache",
|
EnvoyID: "cache",
|
||||||
OutgoingProxyKind: "terminating-gateway",
|
OutgoingProxyKind: "terminating-gateway",
|
||||||
},
|
},
|
||||||
dbService: {
|
dbService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
},
|
},
|
||||||
EnvoyID: "db",
|
EnvoyID: "db",
|
||||||
OutgoingProxyKind: "terminating-gateway",
|
OutgoingProxyKind: "terminating-gateway",
|
||||||
},
|
},
|
||||||
webService: {
|
webService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"canary1.web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"canary1.web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
"canary2.web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"canary2.web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
"web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
|
@ -134,10 +138,25 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
||||||
EnvoyExtensions: envoyExtensions,
|
EnvoyExtensions: envoyExtensions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serviceDefaultsV2 := &structs.ServiceConfigEntry{
|
||||||
|
Kind: structs.ServiceDefaults,
|
||||||
|
Name: "db-v2",
|
||||||
|
Protocol: "http",
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceSplitter := &structs.ServiceSplitterConfigEntry{
|
||||||
|
Kind: structs.ServiceSplitter,
|
||||||
|
Name: "db",
|
||||||
|
Splits: []structs.ServiceSplit{
|
||||||
|
{Weight: 50},
|
||||||
|
{Weight: 50, Service: "db-v2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Setup a snapshot where the db upstream is on a connect proxy.
|
// Setup a snapshot where the db upstream is on a connect proxy.
|
||||||
snapConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, serviceDefaults)
|
snapConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, serviceDefaults, serviceDefaultsV2, serviceSplitter)
|
||||||
// Setup a snapshot where the db upstream is on a terminating gateway.
|
// Setup a snapshot where the db upstream is on a terminating gateway.
|
||||||
snapTermGw := proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", false, nil, nil, serviceDefaults)
|
snapTermGw := proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", false, nil, nil, serviceDefaults, serviceDefaultsV2, serviceSplitter)
|
||||||
// Setup a snapshot with the local service web has extensions.
|
// Setup a snapshot with the local service web has extensions.
|
||||||
snapWebConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, func(ns *structs.NodeService) {
|
snapWebConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, func(ns *structs.NodeService) {
|
||||||
ns.Proxy.EnvoyExtensions = envoyExtensions
|
ns.Proxy.EnvoyExtensions = envoyExtensions
|
||||||
|
@ -164,8 +183,10 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
||||||
IsSourcedFromUpstream: true,
|
IsSourcedFromUpstream: true,
|
||||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
dbService: {
|
dbService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
|
"db-v2.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
},
|
},
|
||||||
EnvoyID: "db",
|
EnvoyID: "db",
|
||||||
OutgoingProxyKind: "connect-proxy",
|
OutgoingProxyKind: "connect-proxy",
|
||||||
|
@ -193,8 +214,10 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
||||||
IsSourcedFromUpstream: true,
|
IsSourcedFromUpstream: true,
|
||||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
dbService: {
|
dbService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
|
"db-v2.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
},
|
},
|
||||||
EnvoyID: "db",
|
EnvoyID: "db",
|
||||||
OutgoingProxyKind: "terminating-gateway",
|
OutgoingProxyKind: "terminating-gateway",
|
||||||
|
@ -224,7 +247,8 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
||||||
IsSourcedFromUpstream: false,
|
IsSourcedFromUpstream: false,
|
||||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
dbService: {
|
dbService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
},
|
},
|
||||||
EnvoyID: "db",
|
EnvoyID: "db",
|
||||||
|
@ -245,7 +269,8 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
||||||
IsSourcedFromUpstream: false,
|
IsSourcedFromUpstream: false,
|
||||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
dbService: {
|
dbService: {
|
||||||
SNI: map[string]struct{}{
|
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
SNIs: map[string]struct{}{
|
||||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||||
},
|
},
|
||||||
EnvoyID: "db",
|
EnvoyID: "db",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/hashicorp/consul/agent/connect"
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
"github.com/hashicorp/consul/agent/proxycfg"
|
"github.com/hashicorp/consul/agent/proxycfg"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||||
)
|
)
|
||||||
|
|
||||||
type discoChainTargets struct {
|
type discoChainTargets struct {
|
||||||
|
@ -149,7 +150,7 @@ func (ft discoChainTargets) sequential() ([]discoChainTargetGroup, error) {
|
||||||
var targetGroups []discoChainTargetGroup
|
var targetGroups []discoChainTargetGroup
|
||||||
for i, t := range ft.targets {
|
for i, t := range ft.targets {
|
||||||
targetGroups = append(targetGroups, discoChainTargetGroup{
|
targetGroups = append(targetGroups, discoChainTargetGroup{
|
||||||
ClusterName: fmt.Sprintf("%s%d~%s", failoverClusterNamePrefix, i, ft.baseClusterName),
|
ClusterName: fmt.Sprintf("%s%d~%s", xdscommon.FailoverClusterNamePrefix, i, ft.baseClusterName),
|
||||||
Targets: []targetInfo{t},
|
Targets: []targetInfo{t},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"clusterType": {
|
||||||
|
"name": "envoy.clusters.aggregate",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.clusters.aggregate.v3.ClusterConfig",
|
||||||
|
"clusters": [
|
||||||
|
"failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "33s",
|
||||||
|
"lbPolicy": "CLUSTER_PROVIDED",
|
||||||
|
"outlierDetection": {
|
||||||
|
"successRateMinimumHosts": 1234
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "33s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {
|
||||||
|
"successRateMinimumHosts": 1234
|
||||||
|
},
|
||||||
|
"commonLbConfig": {
|
||||||
|
"healthyPanicThreshold": {}
|
||||||
|
},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/db"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "33s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {
|
||||||
|
"successRateMinimumHosts": 1234
|
||||||
|
},
|
||||||
|
"commonLbConfig": {
|
||||||
|
"healthyPanicThreshold": {}
|
||||||
|
},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/fail"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "fail.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/geo-cache-target"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "local_app",
|
||||||
|
"type": "STATIC",
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"loadAssignment": {
|
||||||
|
"clusterName": "local_app",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/geo-cache-target"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "local_app",
|
||||||
|
"type": "STATIC",
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"loadAssignment": {
|
||||||
|
"clusterName": "local_app",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {
|
||||||
|
"successRateMinimumHosts": 1234
|
||||||
|
},
|
||||||
|
"commonLbConfig": {
|
||||||
|
"healthyPanicThreshold": {}
|
||||||
|
},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/db"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {
|
||||||
|
"successRateMinimumHosts": 1234
|
||||||
|
},
|
||||||
|
"commonLbConfig": {
|
||||||
|
"healthyPanicThreshold": {}
|
||||||
|
},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/db"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"clusterType": {
|
||||||
|
"name": "envoy.clusters.aggregate",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.clusters.aggregate.v3.ClusterConfig",
|
||||||
|
"clusters": [
|
||||||
|
"failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "33s",
|
||||||
|
"lbPolicy": "CLUSTER_PROVIDED"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "33s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {},
|
||||||
|
"commonLbConfig": {
|
||||||
|
"healthyPanicThreshold": {}
|
||||||
|
},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/db"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"altStatName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "33s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {},
|
||||||
|
"commonLbConfig": {
|
||||||
|
"healthyPanicThreshold": {}
|
||||||
|
},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/fail"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "fail.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"type": "EDS",
|
||||||
|
"edsClusterConfig": {
|
||||||
|
"edsConfig": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"circuitBreakers": {},
|
||||||
|
"outlierDetection": {},
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"matchSubjectAltNames": [
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/geo-cache-target"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"name": "local_app",
|
||||||
|
"type": "STATIC",
|
||||||
|
"connectTimeout": "5s",
|
||||||
|
"loadAssignment": {
|
||||||
|
"clusterName": "local_app",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policy": {
|
||||||
|
"overprovisioningFactor": 1234
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policy": {
|
||||||
|
"overprovisioningFactor": 1234
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policy": {
|
||||||
|
"overprovisioningFactor": 1234
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policy": {
|
||||||
|
"overprovisioningFactor": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"lbEndpoints": [
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.10.1.1",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "10.20.1.2",
|
||||||
|
"portValue": 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"healthStatus": "HEALTHY",
|
||||||
|
"loadBalancingWeight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,235 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "db:127.0.0.1:9191",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 9191
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statPrefix": "custom.stats.outbound.only",
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.db.default.default.dc1",
|
||||||
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.10.10.10",
|
||||||
|
"portValue": 8181
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||||
|
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "public_listener:0.0.0.0:9999",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"portValue": 9999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.http_connection_manager",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||||
|
"statPrefix": "public_listener",
|
||||||
|
"routeConfig": {
|
||||||
|
"name": "public_listener",
|
||||||
|
"virtualHosts": [
|
||||||
|
{
|
||||||
|
"name": "public_listener",
|
||||||
|
"domains": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "local_app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"httpFilters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.rbac",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
|
||||||
|
"rules": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.header_to_metadata",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config",
|
||||||
|
"requestRules": [
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "trust-domain",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "partition",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "namespace",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "datacenter",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "service",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.router",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tracing": {
|
||||||
|
"randomSampling": {}
|
||||||
|
},
|
||||||
|
"forwardClientCertDetails": "APPEND_FORWARD",
|
||||||
|
"setCurrentClientCertDetails": {
|
||||||
|
"subject": true,
|
||||||
|
"cert": true,
|
||||||
|
"chain": true,
|
||||||
|
"dns": true,
|
||||||
|
"uri": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"alpnProtocols": [
|
||||||
|
"http/1.1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"requireClientCertificate": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "INBOUND"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,252 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "db:127.0.0.1:9191",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 9191
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statPrefix": "custom.stats.outbound.only",
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.http_connection_manager",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||||
|
"statPrefix": "upstream.db.default.default.dc1",
|
||||||
|
"rds": {
|
||||||
|
"configSource": {
|
||||||
|
"ads": {},
|
||||||
|
"resourceApiVersion": "V3"
|
||||||
|
},
|
||||||
|
"routeConfigName": "db"
|
||||||
|
},
|
||||||
|
"httpFilters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.router",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tracing": {
|
||||||
|
"randomSampling": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.10.10.10",
|
||||||
|
"portValue": 8181
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||||
|
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "public_listener:0.0.0.0:9999",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"portValue": 9999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.http_connection_manager",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||||
|
"statPrefix": "public_listener",
|
||||||
|
"routeConfig": {
|
||||||
|
"name": "public_listener",
|
||||||
|
"virtualHosts": [
|
||||||
|
{
|
||||||
|
"name": "public_listener",
|
||||||
|
"domains": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "local_app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"httpFilters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.rbac",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
|
||||||
|
"rules": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.header_to_metadata",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config",
|
||||||
|
"requestRules": [
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "trust-domain",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "partition",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "namespace",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "datacenter",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "service",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.router",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tracing": {
|
||||||
|
"randomSampling": {}
|
||||||
|
},
|
||||||
|
"forwardClientCertDetails": "APPEND_FORWARD",
|
||||||
|
"setCurrentClientCertDetails": {
|
||||||
|
"subject": true,
|
||||||
|
"cert": true,
|
||||||
|
"chain": true,
|
||||||
|
"dns": true,
|
||||||
|
"uri": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"alpnProtocols": [
|
||||||
|
"http/1.1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"requireClientCertificate": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "INBOUND"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,234 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "db:127.0.0.1:9191",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 9191
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.db.default.default.dc1",
|
||||||
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.10.10.10",
|
||||||
|
"portValue": 8181
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||||
|
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "public_listener:0.0.0.0:9999",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"portValue": 9999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.http_connection_manager",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||||
|
"statPrefix": "public_listener",
|
||||||
|
"routeConfig": {
|
||||||
|
"name": "public_listener",
|
||||||
|
"virtualHosts": [
|
||||||
|
{
|
||||||
|
"name": "public_listener",
|
||||||
|
"domains": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "local_app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"httpFilters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.rbac",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
|
||||||
|
"rules": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.header_to_metadata",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config",
|
||||||
|
"requestRules": [
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "trust-domain",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "partition",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "namespace",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "datacenter",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "x-forwarded-client-cert",
|
||||||
|
"onHeaderPresent": {
|
||||||
|
"metadataNamespace": "consul",
|
||||||
|
"key": "service",
|
||||||
|
"regexValueRewrite": {
|
||||||
|
"pattern": {
|
||||||
|
"googleRe2": {},
|
||||||
|
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||||
|
},
|
||||||
|
"substitution": "\\5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.http.router",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tracing": {
|
||||||
|
"randomSampling": {}
|
||||||
|
},
|
||||||
|
"forwardClientCertDetails": "APPEND_FORWARD",
|
||||||
|
"setCurrentClientCertDetails": {
|
||||||
|
"subject": true,
|
||||||
|
"cert": true,
|
||||||
|
"chain": true,
|
||||||
|
"dns": true,
|
||||||
|
"uri": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"alpnProtocols": [
|
||||||
|
"http/1.1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"requireClientCertificate": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "INBOUND"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||||
|
"name": "db",
|
||||||
|
"virtualHosts": [
|
||||||
|
{
|
||||||
|
"name": "db",
|
||||||
|
"domains": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"timeout": "33s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mostSpecificHeaderMutationsWins": true,
|
||||||
|
"validateClusters": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||||
|
"name": "db",
|
||||||
|
"virtualHosts": [
|
||||||
|
{
|
||||||
|
"name": "db",
|
||||||
|
"domains": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"weightedClusters": {
|
||||||
|
"clusters": [
|
||||||
|
{
|
||||||
|
"name": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"weight": 5000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"weight": 5000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalWeight": 10000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mostSpecificHeaderMutationsWins": true,
|
||||||
|
"validateClusters": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||||
|
"name": "db",
|
||||||
|
"virtualHosts": [
|
||||||
|
{
|
||||||
|
"name": "db",
|
||||||
|
"domains": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"timeout": "33s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validateClusters": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ type BasicExtension interface {
|
||||||
// PatchRoute patches a route to include the custom Envoy configuration
|
// PatchRoute patches a route to include the custom Envoy configuration
|
||||||
// required to integrate with the built in extension template.
|
// required to integrate with the built in extension template.
|
||||||
// See also PatchRoutes.
|
// See also PatchRoutes.
|
||||||
PatchRoute(*RuntimeConfig, *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error)
|
PatchRoute(RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error)
|
||||||
|
|
||||||
// PatchRoutes patches routes to include the custom Envoy configuration
|
// PatchRoutes patches routes to include the custom Envoy configuration
|
||||||
// required to integrate with the built in extension template.
|
// required to integrate with the built in extension template.
|
||||||
|
@ -51,7 +51,7 @@ type BasicExtension interface {
|
||||||
// PatchCluster patches a cluster to include the custom Envoy configuration
|
// PatchCluster patches a cluster to include the custom Envoy configuration
|
||||||
// required to integrate with the built in extension template.
|
// required to integrate with the built in extension template.
|
||||||
// See also PatchClusters.
|
// See also PatchClusters.
|
||||||
PatchCluster(*RuntimeConfig, *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error)
|
PatchCluster(ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error)
|
||||||
|
|
||||||
// PatchClusters patches clusters to include the custom Envoy configuration
|
// PatchClusters patches clusters to include the custom Envoy configuration
|
||||||
// required to integrate with the built in extension template.
|
// required to integrate with the built in extension template.
|
||||||
|
@ -63,12 +63,12 @@ type BasicExtension interface {
|
||||||
|
|
||||||
// PatchClusterLoadAssignment patches a cluster load assignment to include the custom Envoy configuration
|
// PatchClusterLoadAssignment patches a cluster load assignment to include the custom Envoy configuration
|
||||||
// required to integrate with the built in extension template.
|
// required to integrate with the built in extension template.
|
||||||
PatchClusterLoadAssignment(*RuntimeConfig, *envoy_endpoint_v3.ClusterLoadAssignment) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error)
|
PatchClusterLoadAssignment(ClusterLoadAssignmentPayload) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error)
|
||||||
|
|
||||||
// PatchListener patches a listener to include the custom Envoy configuration
|
// PatchListener patches a listener to include the custom Envoy configuration
|
||||||
// required to integrate with the built in extension template.
|
// required to integrate with the built in extension template.
|
||||||
// See also PatchListeners.
|
// See also PatchListeners.
|
||||||
PatchListener(*RuntimeConfig, *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, bool, error)
|
PatchListener(ListenerPayload) (*envoy_listener_v3.Listener, bool, error)
|
||||||
|
|
||||||
// PatchListeners patches listeners to include the custom Envoy configuration
|
// PatchListeners patches listeners to include the custom Envoy configuration
|
||||||
// required to integrate with the built in extension template.
|
// required to integrate with the built in extension template.
|
||||||
|
@ -81,7 +81,7 @@ type BasicExtension interface {
|
||||||
// PatchFilter patches an Envoy filter to include the custom Envoy
|
// PatchFilter patches an Envoy filter to include the custom Envoy
|
||||||
// configuration required to integrate with the built in extension template.
|
// configuration required to integrate with the built in extension template.
|
||||||
// See also PatchFilters.
|
// See also PatchFilters.
|
||||||
PatchFilter(cfg *RuntimeConfig, f *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error)
|
PatchFilter(FilterPayload) (*envoy_listener_v3.Filter, bool, error)
|
||||||
|
|
||||||
// PatchFilters patches Envoy filters to include the custom Envoy
|
// PatchFilters patches Envoy filters to include the custom Envoy
|
||||||
// configuration required to integrate with the built in extension template.
|
// configuration required to integrate with the built in extension template.
|
||||||
|
@ -197,7 +197,7 @@ func (b *BasicEnvoyExtender) patchClusters(config *RuntimeConfig, clusters Clust
|
||||||
return clusters, fmt.Errorf("error patching clusters: %w", err)
|
return clusters, fmt.Errorf("error patching clusters: %w", err)
|
||||||
}
|
}
|
||||||
for nameOrSNI, cluster := range clusters {
|
for nameOrSNI, cluster := range clusters {
|
||||||
patchedCluster, patched, err := b.Extension.PatchCluster(config, cluster)
|
patchedCluster, patched, err := b.Extension.PatchCluster(config.GetClusterPayload(cluster))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster %q: %w", nameOrSNI, err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster %q: %w", nameOrSNI, err))
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ func (b *BasicEnvoyExtender) patchClusters(config *RuntimeConfig, clusters Clust
|
||||||
// We patch cluster load assignments directly above for EDS, but also here for CDS,
|
// We patch cluster load assignments directly above for EDS, but also here for CDS,
|
||||||
// since updates can come from either.
|
// since updates can come from either.
|
||||||
if patchedCluster.LoadAssignment != nil {
|
if patchedCluster.LoadAssignment != nil {
|
||||||
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config, patchedCluster.LoadAssignment)
|
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config.GetClusterLoadAssignmentPayload(patchedCluster.LoadAssignment))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching load assignment for cluster %q: %w", nameOrSNI, err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching load assignment for cluster %q: %w", nameOrSNI, err))
|
||||||
} else if patched {
|
} else if patched {
|
||||||
|
@ -225,7 +225,7 @@ func (b *BasicEnvoyExtender) patchClusterLoadAssignments(config *RuntimeConfig,
|
||||||
var resultErr error
|
var resultErr error
|
||||||
|
|
||||||
for nameOrSNI, clusterLoadAssignment := range clusterLoadAssignments {
|
for nameOrSNI, clusterLoadAssignment := range clusterLoadAssignments {
|
||||||
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config, clusterLoadAssignment)
|
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config.GetClusterLoadAssignmentPayload(clusterLoadAssignment))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster load assignment %q: %w", nameOrSNI, err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster load assignment %q: %w", nameOrSNI, err))
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,7 @@ func (b *BasicEnvoyExtender) patchRoutes(config *RuntimeConfig, routes RouteMap)
|
||||||
return routes, fmt.Errorf("error patching routes: %w", err)
|
return routes, fmt.Errorf("error patching routes: %w", err)
|
||||||
}
|
}
|
||||||
for nameOrSNI, route := range patchedRoutes {
|
for nameOrSNI, route := range patchedRoutes {
|
||||||
patchedRoute, patched, err := b.Extension.PatchRoute(config, route)
|
patchedRoute, patched, err := b.Extension.PatchRoute(config.GetRoutePayload(route))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching route %q: %w", nameOrSNI, err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching route %q: %w", nameOrSNI, err))
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ func (b *BasicEnvoyExtender) patchListeners(config *RuntimeConfig, listeners Lis
|
||||||
return listeners, fmt.Errorf("error patching listeners: %w", err)
|
return listeners, fmt.Errorf("error patching listeners: %w", err)
|
||||||
}
|
}
|
||||||
for nameOrSNI, listener := range listeners {
|
for nameOrSNI, listener := range listeners {
|
||||||
patchedListener, patched, err := b.Extension.PatchListener(config, listener)
|
patchedListener, patched, err := b.Extension.PatchListener(config.GetListenerPayload(listener))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener %q: %w", nameOrSNI, err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener %q: %w", nameOrSNI, err))
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ func (b *BasicEnvoyExtender) patchListenerFilterChains(config *RuntimeConfig, l
|
||||||
func (b *BasicEnvoyExtender) patchTerminatingGatewayListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener, nameOrSNI string) (*envoy_listener_v3.Listener, error) {
|
func (b *BasicEnvoyExtender) patchTerminatingGatewayListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener, nameOrSNI string) (*envoy_listener_v3.Listener, error) {
|
||||||
var resultErr error
|
var resultErr error
|
||||||
for idx, filterChain := range l.FilterChains {
|
for idx, filterChain := range l.FilterChains {
|
||||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, IsInboundPublicListener(l)); err == nil {
|
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, l); err == nil {
|
||||||
l.FilterChains[idx] = patchedFilterChain
|
l.FilterChains[idx] = patchedFilterChain
|
||||||
} else {
|
} else {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain of terminating gateway listener %q: %w", nameOrSNI, err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain of terminating gateway listener %q: %w", nameOrSNI, err))
|
||||||
|
@ -330,10 +330,8 @@ func (b *BasicEnvoyExtender) patchConnectProxyListenerFilterChains(config *Runti
|
||||||
func (b *BasicEnvoyExtender) patchNonTProxyConnectProxyListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, error) {
|
func (b *BasicEnvoyExtender) patchNonTProxyConnectProxyListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, error) {
|
||||||
var resultErr error
|
var resultErr error
|
||||||
|
|
||||||
inbound := IsInboundPublicListener(l)
|
|
||||||
|
|
||||||
for idx, filterChain := range l.FilterChains {
|
for idx, filterChain := range l.FilterChains {
|
||||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, inbound); err == nil {
|
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, l); err == nil {
|
||||||
l.FilterChains[idx] = patchedFilterChain
|
l.FilterChains[idx] = patchedFilterChain
|
||||||
} else {
|
} else {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain: %w", err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain: %w", err))
|
||||||
|
@ -346,7 +344,6 @@ func (b *BasicEnvoyExtender) patchTProxyListenerFilterChains(config *RuntimeConf
|
||||||
var resultErr error
|
var resultErr error
|
||||||
|
|
||||||
vip := config.Upstreams[config.ServiceName].VIP
|
vip := config.Upstreams[config.ServiceName].VIP
|
||||||
inbound := IsInboundPublicListener(l)
|
|
||||||
|
|
||||||
for idx, filterChain := range l.FilterChains {
|
for idx, filterChain := range l.FilterChains {
|
||||||
match := filterChainTProxyMatch(vip, filterChain)
|
match := filterChainTProxyMatch(vip, filterChain)
|
||||||
|
@ -354,7 +351,7 @@ func (b *BasicEnvoyExtender) patchTProxyListenerFilterChains(config *RuntimeConf
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, inbound); err == nil {
|
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, l); err == nil {
|
||||||
l.FilterChains[idx] = patchedFilterChain
|
l.FilterChains[idx] = patchedFilterChain
|
||||||
} else {
|
} else {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain for %q: %w", vip, err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain for %q: %w", vip, err))
|
||||||
|
@ -364,14 +361,15 @@ func (b *BasicEnvoyExtender) patchTProxyListenerFilterChains(config *RuntimeConf
|
||||||
return l, resultErr
|
return l, resultErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasicEnvoyExtender) patchFilterChain(config *RuntimeConfig, filterChain *envoy_listener_v3.FilterChain, isInboundListener bool) (*envoy_listener_v3.FilterChain, error) {
|
func (b *BasicEnvoyExtender) patchFilterChain(config *RuntimeConfig, filterChain *envoy_listener_v3.FilterChain, l *envoy_listener_v3.Listener) (*envoy_listener_v3.FilterChain, error) {
|
||||||
var resultErr error
|
var resultErr error
|
||||||
patchedFilters, err := b.Extension.PatchFilters(config, filterChain.Filters, isInboundListener)
|
inbound := IsInboundPublicListener(l)
|
||||||
|
patchedFilters, err := b.Extension.PatchFilters(config, filterChain.Filters, inbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return filterChain, fmt.Errorf("error patching filters: %w", err)
|
return filterChain, fmt.Errorf("error patching filters: %w", err)
|
||||||
}
|
}
|
||||||
for idx, filter := range patchedFilters {
|
for idx, filter := range patchedFilters {
|
||||||
patchedFilter, patched, err := b.Extension.PatchFilter(config, filter, isInboundListener)
|
patchedFilter, patched, err := b.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter: %w", err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter: %w", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@ type BasicExtensionAdapter struct{}
|
||||||
func (BasicExtensionAdapter) CanApply(_ *RuntimeConfig) bool { return false }
|
func (BasicExtensionAdapter) CanApply(_ *RuntimeConfig) bool { return false }
|
||||||
|
|
||||||
// PatchCluster provides a default implementation of the PatchCluster interface that does nothing.
|
// PatchCluster provides a default implementation of the PatchCluster interface that does nothing.
|
||||||
func (BasicExtensionAdapter) PatchCluster(_ *RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
func (BasicExtensionAdapter) PatchCluster(p ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||||
return c, false, nil
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchClusters provides a default implementation of the PatchClusters interface that does nothing.
|
// PatchClusters provides a default implementation of the PatchClusters interface that does nothing.
|
||||||
|
@ -30,13 +30,13 @@ func (BasicExtensionAdapter) PatchClusters(_ *RuntimeConfig, c ClusterMap) (Clus
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchClusterLoadAssignment provides a default implementation of the PatchClusterLoadAssignment interface that does nothing.
|
// PatchClusterLoadAssignment provides a default implementation of the PatchClusterLoadAssignment interface that does nothing.
|
||||||
func (BasicExtensionAdapter) PatchClusterLoadAssignment(_ *RuntimeConfig, c *envoy_endpoint_v3.ClusterLoadAssignment) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
func (BasicExtensionAdapter) PatchClusterLoadAssignment(p ClusterLoadAssignmentPayload) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
||||||
return c, false, nil
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchListener provides a default implementation of the PatchListener interface that does nothing.
|
// PatchListener provides a default implementation of the PatchListener interface that does nothing.
|
||||||
func (BasicExtensionAdapter) PatchListener(_ *RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, bool, error) {
|
func (BasicExtensionAdapter) PatchListener(p ListenerPayload) (*envoy_listener_v3.Listener, bool, error) {
|
||||||
return l, false, nil
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchListeners provides a default implementation of the PatchListeners interface that does nothing.
|
// PatchListeners provides a default implementation of the PatchListeners interface that does nothing.
|
||||||
|
@ -45,8 +45,8 @@ func (BasicExtensionAdapter) PatchListeners(_ *RuntimeConfig, l ListenerMap) (Li
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchFilter provides a default implementation of the PatchFilter interface that does nothing.
|
// PatchFilter provides a default implementation of the PatchFilter interface that does nothing.
|
||||||
func (BasicExtensionAdapter) PatchFilter(_ *RuntimeConfig, f *envoy_listener_v3.Filter, _ bool) (*envoy_listener_v3.Filter, bool, error) {
|
func (BasicExtensionAdapter) PatchFilter(p FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||||
return f, false, nil
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchFilters provides a default implementation of the PatchFilters interface that does nothing.
|
// PatchFilters provides a default implementation of the PatchFilters interface that does nothing.
|
||||||
|
@ -55,8 +55,8 @@ func (BasicExtensionAdapter) PatchFilters(_ *RuntimeConfig, f []*envoy_listener_
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchRoute provides a default implementation of the PatchRoute interface that does nothing.
|
// PatchRoute provides a default implementation of the PatchRoute interface that does nothing.
|
||||||
func (BasicExtensionAdapter) PatchRoute(_ *RuntimeConfig, r *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
func (BasicExtensionAdapter) PatchRoute(p RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||||
return r, false, nil
|
return p.Message, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchRoutes provides a default implementation of the PatchRoutes interface that does nothing.
|
// PatchRoutes provides a default implementation of the PatchRoutes interface that does nothing.
|
||||||
|
|
|
@ -17,9 +17,11 @@ import (
|
||||||
envoy_tcp_proxy_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
|
envoy_tcp_proxy_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
|
||||||
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||||
envoy_resource_v3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
|
envoy_resource_v3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
|
||||||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/api"
|
||||||
|
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeUpstreamTLSTransportSocket generates an Envoy transport socket for the given TLS context.
|
// MakeUpstreamTLSTransportSocket generates an Envoy transport socket for the given TLS context.
|
||||||
|
@ -70,6 +72,206 @@ func MakeFilter(name string, cfg proto.Message) (*envoy_listener_v3.Filter, erro
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TrafficDirection determines whether inbound or outbound Envoy resources will be patched.
|
||||||
|
type TrafficDirection string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TrafficDirectionInbound TrafficDirection = "inbound"
|
||||||
|
TrafficDirectionOutbound TrafficDirection = "outbound"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TrafficDirections = StringSet{string(TrafficDirectionInbound): {}, string(TrafficDirectionOutbound): {}}
|
||||||
|
|
||||||
|
type StringSet map[string]struct{}
|
||||||
|
|
||||||
|
func (c *StringSet) CheckRequired(v, fieldName string) error {
|
||||||
|
if _, ok := (*c)[v]; !ok {
|
||||||
|
if v == "" {
|
||||||
|
return fmt.Errorf("field %s is required", fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
for k := range *c {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("invalid %s '%q'; supported values: %s",
|
||||||
|
fieldName, v, strings.Join(keys, ", "))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NormalizeEmptyToDefault(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func NormalizeServiceName(sn *api.CompoundServiceName) {
|
||||||
|
sn.Namespace = NormalizeEmptyToDefault(sn.Namespace)
|
||||||
|
sn.Partition = NormalizeEmptyToDefault(sn.Partition)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payload represents a single Envoy resource to be modified by extensions.
|
||||||
|
// It associates the RuntimeConfig of the local proxy, the TrafficDirection
|
||||||
|
// of the resource, and the CompoundServiceName and UpstreamData (if outbound)
|
||||||
|
// of a service the Envoy resource corresponds to.
|
||||||
|
type Payload[K proto.Message] struct {
|
||||||
|
RuntimeConfig *RuntimeConfig
|
||||||
|
ServiceName *api.CompoundServiceName
|
||||||
|
Upstream *UpstreamData
|
||||||
|
TrafficDirection TrafficDirection
|
||||||
|
Message K
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Payload[K]) IsInbound() bool {
|
||||||
|
return p.TrafficDirection == TrafficDirectionInbound
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClusterPayload = Payload[*envoy_cluster_v3.Cluster]
|
||||||
|
type ClusterLoadAssignmentPayload = Payload[*envoy_endpoint_v3.ClusterLoadAssignment]
|
||||||
|
type ListenerPayload = Payload[*envoy_listener_v3.Listener]
|
||||||
|
type FilterPayload = Payload[*envoy_listener_v3.Filter]
|
||||||
|
type RoutePayload = Payload[*envoy_route_v3.RouteConfiguration]
|
||||||
|
|
||||||
|
func (cfg *RuntimeConfig) GetClusterPayload(c *envoy_cluster_v3.Cluster) ClusterPayload {
|
||||||
|
d := TrafficDirectionOutbound
|
||||||
|
var u *UpstreamData
|
||||||
|
var sn *api.CompoundServiceName
|
||||||
|
|
||||||
|
if IsLocalAppCluster(c) {
|
||||||
|
d = TrafficDirectionInbound
|
||||||
|
} else {
|
||||||
|
u, sn = cfg.findUpstreamBySNI(c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClusterPayload{
|
||||||
|
RuntimeConfig: cfg,
|
||||||
|
ServiceName: sn,
|
||||||
|
Upstream: u,
|
||||||
|
TrafficDirection: d,
|
||||||
|
Message: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeConfig) GetListenerPayload(l *envoy_listener_v3.Listener) ListenerPayload {
|
||||||
|
d := TrafficDirectionOutbound
|
||||||
|
var u *UpstreamData
|
||||||
|
var sn *api.CompoundServiceName
|
||||||
|
|
||||||
|
if IsInboundPublicListener(l) {
|
||||||
|
d = TrafficDirectionInbound
|
||||||
|
} else {
|
||||||
|
u, sn = c.findUpstreamByEnvoyID(GetListenerEnvoyID(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListenerPayload{
|
||||||
|
RuntimeConfig: c,
|
||||||
|
ServiceName: sn,
|
||||||
|
Upstream: u,
|
||||||
|
TrafficDirection: d,
|
||||||
|
Message: l,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeConfig) GetFilterPayload(f *envoy_listener_v3.Filter, l *envoy_listener_v3.Listener) FilterPayload {
|
||||||
|
d := TrafficDirectionOutbound
|
||||||
|
var u *UpstreamData
|
||||||
|
var sn *api.CompoundServiceName
|
||||||
|
|
||||||
|
if IsInboundPublicListener(l) {
|
||||||
|
d = TrafficDirectionInbound
|
||||||
|
} else {
|
||||||
|
u, sn = c.findUpstreamByEnvoyID(GetListenerEnvoyID(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilterPayload{
|
||||||
|
RuntimeConfig: c,
|
||||||
|
ServiceName: sn,
|
||||||
|
Upstream: u,
|
||||||
|
TrafficDirection: d,
|
||||||
|
Message: f,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeConfig) GetRoutePayload(r *envoy_route_v3.RouteConfiguration) RoutePayload {
|
||||||
|
d := TrafficDirectionOutbound
|
||||||
|
var u *UpstreamData
|
||||||
|
var sn *api.CompoundServiceName
|
||||||
|
|
||||||
|
if IsRouteToLocalAppCluster(r) {
|
||||||
|
d = TrafficDirectionInbound
|
||||||
|
} else {
|
||||||
|
u, sn = c.findUpstreamByEnvoyID(r.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return RoutePayload{
|
||||||
|
RuntimeConfig: c,
|
||||||
|
ServiceName: sn,
|
||||||
|
Upstream: u,
|
||||||
|
TrafficDirection: d,
|
||||||
|
Message: r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *RuntimeConfig) GetClusterLoadAssignmentPayload(c *envoy_endpoint_v3.ClusterLoadAssignment) ClusterLoadAssignmentPayload {
|
||||||
|
d := TrafficDirectionOutbound
|
||||||
|
var u *UpstreamData
|
||||||
|
var sn *api.CompoundServiceName
|
||||||
|
|
||||||
|
if IsLocalAppClusterLoadAssignment(c) {
|
||||||
|
d = TrafficDirectionInbound
|
||||||
|
} else {
|
||||||
|
u, sn = cfg.findUpstreamBySNI(c.ClusterName)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClusterLoadAssignmentPayload{
|
||||||
|
RuntimeConfig: cfg,
|
||||||
|
ServiceName: sn,
|
||||||
|
Upstream: u,
|
||||||
|
TrafficDirection: d,
|
||||||
|
Message: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeConfig) findUpstreamByEnvoyID(envoyID string) (*UpstreamData, *api.CompoundServiceName) {
|
||||||
|
for sn, u := range c.Upstreams {
|
||||||
|
if u.EnvoyID == envoyID {
|
||||||
|
return u, &sn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeConfig) findUpstreamBySNI(sni string) (*UpstreamData, *api.CompoundServiceName) {
|
||||||
|
for sn, u := range c.Upstreams {
|
||||||
|
_, ok := u.SNIs[sni]
|
||||||
|
if ok {
|
||||||
|
return u, &sn
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(sni, xdscommon.FailoverClusterNamePrefix) {
|
||||||
|
parts := strings.Split(sni, "~")
|
||||||
|
|
||||||
|
if len(parts) != 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
id := parts[2]
|
||||||
|
_, ok := u.SNIs[id]
|
||||||
|
if ok {
|
||||||
|
return u, &sn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetListenerEnvoyID returns the Envoy ID string parsed from the name of the given Listener. If none is found, it
|
// GetListenerEnvoyID returns the Envoy ID string parsed from the name of the given Listener. If none is found, it
|
||||||
// returns the empty string.
|
// returns the empty string.
|
||||||
func GetListenerEnvoyID(l *envoy_listener_v3.Listener) string {
|
func GetListenerEnvoyID(l *envoy_listener_v3.Listener) string {
|
||||||
|
|
|
@ -8,8 +8,11 @@ import "github.com/hashicorp/consul/api"
|
||||||
// UpstreamData has the SNI, EnvoyID, and OutgoingProxyKind of the upstream services for the local proxy and this data
|
// UpstreamData has the SNI, EnvoyID, and OutgoingProxyKind of the upstream services for the local proxy and this data
|
||||||
// is used to choose which Envoy resources to patch.
|
// is used to choose which Envoy resources to patch.
|
||||||
type UpstreamData struct {
|
type UpstreamData struct {
|
||||||
// SNI is the SNI header used to reach an upstream service.
|
// This is the SNI for the upstream service without accounting for any discovery chain magic.
|
||||||
SNI map[string]struct{}
|
PrimarySNI string
|
||||||
|
|
||||||
|
// SNIs is the SNIs header used to reach an upstream service.
|
||||||
|
SNIs map[string]struct{}
|
||||||
|
|
||||||
// EnvoyID is the envoy ID of an upstream service, structured <service> or <partition>/<ns>/<service> when using a
|
// EnvoyID is the envoy ID of an upstream service, structured <service> or <partition>/<ns>/<service> when using a
|
||||||
// non-default namespace or partition.
|
// non-default namespace or partition.
|
||||||
|
@ -68,7 +71,7 @@ type RuntimeConfig struct {
|
||||||
// Only used when IsSourcedFromUpstream is true.
|
// Only used when IsSourcedFromUpstream is true.
|
||||||
func (c RuntimeConfig) MatchesUpstreamServiceSNI(sni string) bool {
|
func (c RuntimeConfig) MatchesUpstreamServiceSNI(sni string) bool {
|
||||||
u := c.Upstreams[c.ServiceName]
|
u := c.Upstreams[c.ServiceName]
|
||||||
_, match := u.SNI[sni]
|
_, match := u.SNIs[sni]
|
||||||
return match
|
return match
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ func makeTestRuntimeConfig() RuntimeConfig {
|
||||||
sn: {
|
sn: {
|
||||||
EnvoyID: "eid",
|
EnvoyID: "eid",
|
||||||
OutgoingProxyKind: api.ServiceKindTerminatingGateway,
|
OutgoingProxyKind: api.ServiceKindTerminatingGateway,
|
||||||
SNI: map[string]struct{}{
|
SNIs: map[string]struct{}{
|
||||||
"sni1": {},
|
"sni1": {},
|
||||||
"sni2": {},
|
"sni2": {},
|
||||||
},
|
},
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (ext *UpstreamEnvoyExtender) Extend(resources *xdscommon.IndexedResources,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
newCluster, patched, err := ext.Extension.PatchCluster(config, resource)
|
newCluster, patched, err := ext.Extension.PatchCluster(config.GetClusterPayload(resource))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster: %w", err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster: %w", err))
|
||||||
continue
|
continue
|
||||||
|
@ -101,7 +101,7 @@ func (ext *UpstreamEnvoyExtender) Extend(resources *xdscommon.IndexedResources,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
newRoute, patched, err := ext.Extension.PatchRoute(config, resource)
|
newRoute, patched, err := ext.Extension.PatchRoute(config.GetRoutePayload(resource))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching route: %w", err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching route: %w", err))
|
||||||
continue
|
continue
|
||||||
|
@ -146,7 +146,7 @@ func (ext *UpstreamEnvoyExtender) patchTerminatingGatewayListener(config *Runtim
|
||||||
var filters []*envoy_listener_v3.Filter
|
var filters []*envoy_listener_v3.Filter
|
||||||
|
|
||||||
for _, filter := range filterChain.Filters {
|
for _, filter := range filterChain.Filters {
|
||||||
newFilter, ok, err := ext.Extension.PatchFilter(config, filter, IsInboundPublicListener(l))
|
newFilter, ok, err := ext.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
||||||
|
@ -190,7 +190,7 @@ func (ext *UpstreamEnvoyExtender) patchConnectProxyListener(config *RuntimeConfi
|
||||||
var filters []*envoy_listener_v3.Filter
|
var filters []*envoy_listener_v3.Filter
|
||||||
|
|
||||||
for _, filter := range filterChain.Filters {
|
for _, filter := range filterChain.Filters {
|
||||||
newFilter, ok, err := ext.Extension.PatchFilter(config, filter, IsInboundPublicListener(l))
|
newFilter, ok, err := ext.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
||||||
filters = append(filters, filter)
|
filters = append(filters, filter)
|
||||||
|
@ -225,7 +225,7 @@ func (ext *UpstreamEnvoyExtender) patchTProxyListener(config *RuntimeConfig, l *
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filter := range filterChain.Filters {
|
for _, filter := range filterChain.Filters {
|
||||||
newFilter, ok, err := ext.Extension.PatchFilter(config, filter, IsInboundPublicListener(l))
|
newFilter, ok, err := ext.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
||||||
filters = append(filters, filter)
|
filters = append(filters, filter)
|
||||||
|
|
|
@ -52,6 +52,8 @@ const (
|
||||||
|
|
||||||
// SecretType is the TypeURL for Secret discovery responses.
|
// SecretType is the TypeURL for Secret discovery responses.
|
||||||
SecretType = apiTypePrefix + "envoy.extensions.transport_sockets.tls.v3.Secret"
|
SecretType = apiTypePrefix + "envoy.extensions.transport_sockets.tls.v3.Secret"
|
||||||
|
|
||||||
|
FailoverClusterNamePrefix = "failover-target~"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexedResources struct {
|
type IndexedResources struct {
|
||||||
|
|
|
@ -87,7 +87,7 @@ func Validate(indexedResources *xdscommon.IndexedResources, envoyID string, vip
|
||||||
// the cluster SNIs configured on this proxy, not just the upstream being validated. This means the
|
// the cluster SNIs configured on this proxy, not just the upstream being validated. This means the
|
||||||
// PatchCluster function in the Validate plugin will be run on all clusters, but errors will only
|
// PatchCluster function in the Validate plugin will be run on all clusters, but errors will only
|
||||||
// surface for clusters related to the upstream being validated.
|
// surface for clusters related to the upstream being validated.
|
||||||
SNI: snis,
|
SNIs: snis,
|
||||||
EnvoyID: envoyID,
|
EnvoyID: envoyID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -92,10 +92,10 @@ func MakeValidate(ext extensioncommon.RuntimeConfig) (extensioncommon.BasicExten
|
||||||
upstream, ok := ext.Upstreams[ext.ServiceName]
|
upstream, ok := ext.Upstreams[ext.ServiceName]
|
||||||
if ok {
|
if ok {
|
||||||
vip = upstream.VIP
|
vip = upstream.VIP
|
||||||
if upstream.SNI == nil || len(upstream.SNI) == 0 {
|
if upstream.SNIs == nil || len(upstream.SNIs) == 0 {
|
||||||
return nil, fmt.Errorf("no SNIs were set, unable to validate Envoy clusters")
|
return nil, fmt.Errorf("no SNIs were set, unable to validate Envoy clusters")
|
||||||
}
|
}
|
||||||
snis = upstream.SNI
|
snis = upstream.SNIs
|
||||||
}
|
}
|
||||||
if mainEnvoyID == "" && vip == "" {
|
if mainEnvoyID == "" && vip == "" {
|
||||||
return nil, fmt.Errorf("envoyID or virtual IP is required")
|
return nil, fmt.Errorf("envoyID or virtual IP is required")
|
||||||
|
@ -306,84 +306,87 @@ func (p *Validate) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Validate) PatchRoute(config *extensioncommon.RuntimeConfig, route *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
func (v *Validate) PatchRoute(p extensioncommon.RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||||
|
route := p.Message
|
||||||
// Route name on connect proxies will be the envoy ID. We are only validating routes for the specific upstream with
|
// Route name on connect proxies will be the envoy ID. We are only validating routes for the specific upstream with
|
||||||
// the envoyID configured.
|
// the envoyID configured.
|
||||||
if route.Name != p.envoyID {
|
if route.Name != p.Upstream.EnvoyID {
|
||||||
return route, false, nil
|
return route, false, nil
|
||||||
}
|
}
|
||||||
p.route = true
|
v.route = true
|
||||||
for sni := range extensioncommon.RouteClusterNames(route) {
|
for sni := range extensioncommon.RouteClusterNames(route) {
|
||||||
if _, ok := p.resources[sni]; ok {
|
if _, ok := v.resources[sni]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.resources[sni] = &resource{required: true}
|
v.resources[sni] = &resource{required: true}
|
||||||
}
|
}
|
||||||
return route, false, nil
|
return route, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Validate) PatchCluster(config *extensioncommon.RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
func (v *Validate) PatchCluster(p extensioncommon.ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||||
v, ok := p.resources[c.Name]
|
c := p.Message
|
||||||
|
val, ok := v.resources[c.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
v = &resource{}
|
val = &resource{}
|
||||||
p.resources[c.Name] = v
|
v.resources[c.Name] = val
|
||||||
}
|
}
|
||||||
v.cluster = true
|
val.cluster = true
|
||||||
|
|
||||||
// If it's an aggregate cluster, add the child clusters to p.resources if they are not already there.
|
// If it's an aggregate cluster, add the child clusters to p.resources if they are not already there.
|
||||||
aggregateCluster, ok := isAggregateCluster(c)
|
aggregateCluster, ok := isAggregateCluster(c)
|
||||||
if ok {
|
if ok {
|
||||||
// Mark this as an aggregate cluster, so we know we do not need to validate its endpoints directly.
|
// Mark this as an aggregate cluster, so we know we do not need to validate its endpoints directly.
|
||||||
v.aggregateCluster = true
|
val.aggregateCluster = true
|
||||||
for _, clusterName := range aggregateCluster.Clusters {
|
for _, clusterName := range aggregateCluster.Clusters {
|
||||||
r, ok := p.resources[clusterName]
|
r, ok := v.resources[clusterName]
|
||||||
if !ok {
|
if !ok {
|
||||||
r = &resource{}
|
r = &resource{}
|
||||||
p.resources[clusterName] = r
|
v.resources[clusterName] = r
|
||||||
}
|
}
|
||||||
if v.aggregateClusterChildren == nil {
|
if val.aggregateClusterChildren == nil {
|
||||||
v.aggregateClusterChildren = []string{}
|
val.aggregateClusterChildren = []string{}
|
||||||
}
|
}
|
||||||
// On the parent cluster, add the children.
|
// On the parent cluster, add the children.
|
||||||
v.aggregateClusterChildren = append(v.aggregateClusterChildren, clusterName)
|
val.aggregateClusterChildren = append(val.aggregateClusterChildren, clusterName)
|
||||||
// On the child cluster, set the parent.
|
// On the child cluster, set the parent.
|
||||||
r.parentCluster = c.Name
|
r.parentCluster = c.Name
|
||||||
// The child clusters of an aggregate cluster will be required if the parent cluster is.
|
// The child clusters of an aggregate cluster will be required if the parent cluster is.
|
||||||
r.required = v.required
|
r.required = val.required
|
||||||
}
|
}
|
||||||
return c, false, nil
|
return c, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.EdsClusterConfig != nil {
|
if c.EdsClusterConfig != nil {
|
||||||
v.usesEDS = true
|
val.usesEDS = true
|
||||||
} else {
|
} else {
|
||||||
la := c.LoadAssignment
|
la := c.LoadAssignment
|
||||||
if la == nil {
|
if la == nil {
|
||||||
return c, false, nil
|
return c, false, nil
|
||||||
}
|
}
|
||||||
v.endpoints = len(la.Endpoints) + len(la.NamedEndpoints)
|
val.endpoints = len(la.Endpoints) + len(la.NamedEndpoints)
|
||||||
}
|
}
|
||||||
return c, false, nil
|
return c, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Validate) PatchFilter(config *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, _ bool) (*envoy_listener_v3.Filter, bool, error) {
|
func (v *Validate) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||||
|
filter := p.Message
|
||||||
// If a single filter exists for a listener we say it exists.
|
// If a single filter exists for a listener we say it exists.
|
||||||
p.listener = true
|
v.listener = true
|
||||||
|
|
||||||
if httpConfig := envoy_resource_v3.GetHTTPConnectionManager(filter); httpConfig != nil {
|
if httpConfig := envoy_resource_v3.GetHTTPConnectionManager(filter); httpConfig != nil {
|
||||||
// If the http filter uses RDS, then the clusters we need to validate exist in the route, and there's nothing
|
// If the http filter uses RDS, then the clusters we need to validate exist in the route, and there's nothing
|
||||||
// else we need to do with the filter.
|
// else we need to do with the filter.
|
||||||
if httpConfig.GetRds() != nil {
|
if httpConfig.GetRds() != nil {
|
||||||
p.usesRDS = true
|
v.usesRDS = true
|
||||||
|
|
||||||
// Edit the runtime configuration to add an envoy ID based on the route name in the filter. This is because
|
// Edit the runtime configuration to add an envoy ID based on the route name in the filter. This is because
|
||||||
// routes are matched by envoyID and in the transparent proxy case, we only have the VIP set in the
|
// routes are matched by envoyID and in the transparent proxy case, we only have the VIP set in the
|
||||||
// RuntimeConfig.
|
// RuntimeConfig.
|
||||||
p.envoyID = httpConfig.GetRds().RouteConfigName
|
v.envoyID = httpConfig.GetRds().RouteConfigName
|
||||||
emptyServiceKey := api.CompoundServiceName{}
|
emptyServiceKey := api.CompoundServiceName{}
|
||||||
upstream, ok := config.Upstreams[emptyServiceKey]
|
upstream, ok := p.RuntimeConfig.Upstreams[emptyServiceKey]
|
||||||
if ok {
|
if ok {
|
||||||
upstream.EnvoyID = p.envoyID
|
upstream.EnvoyID = v.envoyID
|
||||||
}
|
}
|
||||||
return filter, true, nil
|
return filter, true, nil
|
||||||
}
|
}
|
||||||
|
@ -392,10 +395,10 @@ func (p *Validate) PatchFilter(config *extensioncommon.RuntimeConfig, filter *en
|
||||||
// FilterClusterNames handles the filter being an http or tcp filter.
|
// FilterClusterNames handles the filter being an http or tcp filter.
|
||||||
for sni := range extensioncommon.FilterClusterNames(filter) {
|
for sni := range extensioncommon.FilterClusterNames(filter) {
|
||||||
// Mark any clusters we see as required resources.
|
// Mark any clusters we see as required resources.
|
||||||
if r, ok := p.resources[sni]; ok {
|
if r, ok := v.resources[sni]; ok {
|
||||||
r.required = true
|
r.required = true
|
||||||
} else {
|
} else {
|
||||||
p.resources[sni] = &resource{required: true}
|
v.resources[sni] = &resource{required: true}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -349,7 +349,7 @@ func TestMakeValidate(t *testing.T) {
|
||||||
},
|
},
|
||||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||||
svc: {
|
svc: {
|
||||||
SNI: tc.snis,
|
SNIs: tc.snis,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue