Cluster peering failover disco chain changes (#14296)
This commit is contained in:
parent
90cdc2622d
commit
3d45306e1b
|
@ -178,20 +178,43 @@ func TestQuerySNI(t *testing.T) {
|
||||||
func TestTargetSNI(t *testing.T) {
|
func TestTargetSNI(t *testing.T) {
|
||||||
// empty namespace, empty subset
|
// empty namespace, empty subset
|
||||||
require.Equal(t, "api.default.foo."+testTrustDomainSuffix1,
|
require.Equal(t, "api.default.foo."+testTrustDomainSuffix1,
|
||||||
TargetSNI(structs.NewDiscoveryTarget("api", "", "", "default", "foo"), testTrustDomain1))
|
TargetSNI(structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "api",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "foo",
|
||||||
|
}), testTrustDomain1))
|
||||||
|
|
||||||
require.Equal(t, "api.default.foo."+testTrustDomainSuffix1,
|
require.Equal(t, "api.default.foo."+testTrustDomainSuffix1,
|
||||||
TargetSNI(structs.NewDiscoveryTarget("api", "", "", "", "foo"), testTrustDomain1))
|
TargetSNI(structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "api",
|
||||||
|
Datacenter: "foo",
|
||||||
|
}), testTrustDomain1))
|
||||||
|
|
||||||
// set namespace, empty subset
|
// set namespace, empty subset
|
||||||
require.Equal(t, "api.neighbor.foo."+testTrustDomainSuffix2,
|
require.Equal(t, "api.neighbor.foo."+testTrustDomainSuffix2,
|
||||||
TargetSNI(structs.NewDiscoveryTarget("api", "", "neighbor", "default", "foo"), testTrustDomain2))
|
TargetSNI(structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "api",
|
||||||
|
Namespace: "neighbor",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "foo",
|
||||||
|
}), testTrustDomain2))
|
||||||
|
|
||||||
// empty namespace, set subset
|
// empty namespace, set subset
|
||||||
require.Equal(t, "v2.api.default.foo."+testTrustDomainSuffix1,
|
require.Equal(t, "v2.api.default.foo."+testTrustDomainSuffix1,
|
||||||
TargetSNI(structs.NewDiscoveryTarget("api", "v2", "", "default", "foo"), testTrustDomain1))
|
TargetSNI(structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "api",
|
||||||
|
ServiceSubset: "v2",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "foo",
|
||||||
|
}), testTrustDomain1))
|
||||||
|
|
||||||
// set namespace, set subset
|
// set namespace, set subset
|
||||||
require.Equal(t, "canary.api.neighbor.foo."+testTrustDomainSuffix2,
|
require.Equal(t, "canary.api.neighbor.foo."+testTrustDomainSuffix2,
|
||||||
TargetSNI(structs.NewDiscoveryTarget("api", "canary", "neighbor", "default", "foo"), testTrustDomain2))
|
TargetSNI(structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "api",
|
||||||
|
ServiceSubset: "canary",
|
||||||
|
Namespace: "neighbor",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "foo",
|
||||||
|
}), testTrustDomain2))
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,17 @@ func TestDiscoveryChainEndpoint_Get(t *testing.T) {
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
newTarget := func(service, serviceSubset, namespace, partition, datacenter string) *structs.DiscoveryTarget {
|
newTarget := func(opts structs.DiscoveryTargetOpts) *structs.DiscoveryTarget {
|
||||||
t := structs.NewDiscoveryTarget(service, serviceSubset, namespace, partition, datacenter)
|
if opts.Namespace == "" {
|
||||||
|
opts.Namespace = "default"
|
||||||
|
}
|
||||||
|
if opts.Partition == "" {
|
||||||
|
opts.Partition = "default"
|
||||||
|
}
|
||||||
|
if opts.Datacenter == "" {
|
||||||
|
opts.Datacenter = "dc1"
|
||||||
|
}
|
||||||
|
t := structs.NewDiscoveryTarget(opts)
|
||||||
t.SNI = connect.TargetSNI(t, connect.TestClusterID+".consul")
|
t.SNI = connect.TargetSNI(t, connect.TestClusterID+".consul")
|
||||||
t.Name = t.SNI
|
t.Name = t.SNI
|
||||||
t.ConnectTimeout = 5 * time.Second // default
|
t.ConnectTimeout = 5 * time.Second // default
|
||||||
|
@ -119,7 +128,7 @@ func TestDiscoveryChainEndpoint_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"web.default.default.dc1": newTarget("web", "", "default", "default", "dc1"),
|
"web.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "web"}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -245,7 +254,7 @@ func TestDiscoveryChainEndpoint_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"web.default.default.dc1": targetWithConnectTimeout(
|
"web.default.default.dc1": targetWithConnectTimeout(
|
||||||
newTarget("web", "", "default", "default", "dc1"),
|
newTarget(structs.DiscoveryTargetOpts{Service: "web"}),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/mitchellh/hashstructure"
|
"github.com/mitchellh/hashstructure"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/acl"
|
||||||
"github.com/hashicorp/consul/agent/configentry"
|
"github.com/hashicorp/consul/agent/configentry"
|
||||||
"github.com/hashicorp/consul/agent/connect"
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
@ -576,7 +577,10 @@ func (c *compiler) assembleChain() error {
|
||||||
if router == nil {
|
if router == nil {
|
||||||
// If no router is configured, move on down the line to the next hop of
|
// If no router is configured, move on down the line to the next hop of
|
||||||
// the chain.
|
// the chain.
|
||||||
node, err := c.getSplitterOrResolverNode(c.newTarget(c.serviceName, "", "", "", ""))
|
node, err := c.getSplitterOrResolverNode(c.newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: c.serviceName,
|
||||||
|
}))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -626,11 +630,20 @@ func (c *compiler) assembleChain() error {
|
||||||
)
|
)
|
||||||
if dest.ServiceSubset == "" {
|
if dest.ServiceSubset == "" {
|
||||||
node, err = c.getSplitterOrResolverNode(
|
node, err = c.getSplitterOrResolverNode(
|
||||||
c.newTarget(svc, "", destNamespace, destPartition, ""),
|
c.newTarget(structs.DiscoveryTargetOpts{
|
||||||
)
|
Service: svc,
|
||||||
|
Namespace: destNamespace,
|
||||||
|
Partition: destPartition,
|
||||||
|
},
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
node, err = c.getResolverNode(
|
node, err = c.getResolverNode(
|
||||||
c.newTarget(svc, dest.ServiceSubset, destNamespace, destPartition, ""),
|
c.newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: svc,
|
||||||
|
ServiceSubset: dest.ServiceSubset,
|
||||||
|
Namespace: destNamespace,
|
||||||
|
Partition: destPartition,
|
||||||
|
}),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -642,7 +655,12 @@ func (c *compiler) assembleChain() error {
|
||||||
|
|
||||||
// If we have a router, we'll add a catch-all route at the end to send
|
// If we have a router, we'll add a catch-all route at the end to send
|
||||||
// unmatched traffic to the next hop in the chain.
|
// unmatched traffic to the next hop in the chain.
|
||||||
defaultDestinationNode, err := c.getSplitterOrResolverNode(c.newTarget(router.Name, "", router.NamespaceOrDefault(), router.PartitionOrDefault(), ""))
|
opts := structs.DiscoveryTargetOpts{
|
||||||
|
Service: router.Name,
|
||||||
|
Namespace: router.NamespaceOrDefault(),
|
||||||
|
Partition: router.PartitionOrDefault(),
|
||||||
|
}
|
||||||
|
defaultDestinationNode, err := c.getSplitterOrResolverNode(c.newTarget(opts))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -674,19 +692,28 @@ func newDefaultServiceRoute(serviceName, namespace, partition string) *structs.S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) newTarget(service, serviceSubset, namespace, partition, datacenter string) *structs.DiscoveryTarget {
|
func (c *compiler) newTarget(opts structs.DiscoveryTargetOpts) *structs.DiscoveryTarget {
|
||||||
if service == "" {
|
if opts.Service == "" {
|
||||||
panic("newTarget called with empty service which makes no sense")
|
panic("newTarget called with empty service which makes no sense")
|
||||||
}
|
}
|
||||||
|
|
||||||
t := structs.NewDiscoveryTarget(
|
if opts.Peer == "" {
|
||||||
service,
|
opts.Datacenter = defaultIfEmpty(opts.Datacenter, c.evaluateInDatacenter)
|
||||||
serviceSubset,
|
opts.Namespace = defaultIfEmpty(opts.Namespace, c.evaluateInNamespace)
|
||||||
defaultIfEmpty(namespace, c.evaluateInNamespace),
|
opts.Partition = defaultIfEmpty(opts.Partition, c.evaluateInPartition)
|
||||||
defaultIfEmpty(partition, c.evaluateInPartition),
|
} else {
|
||||||
defaultIfEmpty(datacenter, c.evaluateInDatacenter),
|
// Don't allow Peer and Datacenter.
|
||||||
)
|
opts.Datacenter = ""
|
||||||
|
// Peer and Partition cannot both be set.
|
||||||
|
opts.Partition = acl.PartitionOrDefault("")
|
||||||
|
// Default to "default" rather than c.evaluateInNamespace.
|
||||||
|
opts.Namespace = acl.PartitionOrDefault(opts.Namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := structs.NewDiscoveryTarget(opts)
|
||||||
|
|
||||||
|
// We don't have the peer's trust domain yet so we can't construct the SNI.
|
||||||
|
if opts.Peer == "" {
|
||||||
// Set default connect SNI. This will be overridden later if the service
|
// Set default connect SNI. This will be overridden later if the service
|
||||||
// has an explicit SNI value configured in service-defaults.
|
// has an explicit SNI value configured in service-defaults.
|
||||||
t.SNI = connect.TargetSNI(t, c.evaluateInTrustDomain)
|
t.SNI = connect.TargetSNI(t, c.evaluateInTrustDomain)
|
||||||
|
@ -694,6 +721,7 @@ func (c *compiler) newTarget(service, serviceSubset, namespace, partition, datac
|
||||||
// Use the same representation for the name. This will NOT be overridden
|
// Use the same representation for the name. This will NOT be overridden
|
||||||
// later.
|
// later.
|
||||||
t.Name = t.SNI
|
t.Name = t.SNI
|
||||||
|
}
|
||||||
|
|
||||||
prev, ok := c.loadedTargets[t.ID]
|
prev, ok := c.loadedTargets[t.ID]
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -703,34 +731,30 @@ func (c *compiler) newTarget(service, serviceSubset, namespace, partition, datac
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) rewriteTarget(t *structs.DiscoveryTarget, service, serviceSubset, partition, namespace, datacenter string) *structs.DiscoveryTarget {
|
func (c *compiler) rewriteTarget(t *structs.DiscoveryTarget, opts structs.DiscoveryTargetOpts) *structs.DiscoveryTarget {
|
||||||
var (
|
mergedOpts := t.ToDiscoveryTargetOpts()
|
||||||
service2 = t.Service
|
|
||||||
serviceSubset2 = t.ServiceSubset
|
|
||||||
partition2 = t.Partition
|
|
||||||
namespace2 = t.Namespace
|
|
||||||
datacenter2 = t.Datacenter
|
|
||||||
)
|
|
||||||
|
|
||||||
if service != "" && service != service2 {
|
if opts.Service != "" && opts.Service != mergedOpts.Service {
|
||||||
service2 = service
|
mergedOpts.Service = opts.Service
|
||||||
// Reset the chosen subset if we reference a service other than our own.
|
// Reset the chosen subset if we reference a service other than our own.
|
||||||
serviceSubset2 = ""
|
mergedOpts.ServiceSubset = ""
|
||||||
}
|
}
|
||||||
if serviceSubset != "" {
|
if opts.ServiceSubset != "" {
|
||||||
serviceSubset2 = serviceSubset
|
mergedOpts.ServiceSubset = opts.ServiceSubset
|
||||||
}
|
}
|
||||||
if partition != "" {
|
if opts.Partition != "" {
|
||||||
partition2 = partition
|
mergedOpts.Partition = opts.Partition
|
||||||
}
|
}
|
||||||
if namespace != "" {
|
// Only use explicit Namespace with Peer
|
||||||
namespace2 = namespace
|
if opts.Namespace != "" || opts.Peer != "" {
|
||||||
|
mergedOpts.Namespace = opts.Namespace
|
||||||
}
|
}
|
||||||
if datacenter != "" {
|
if opts.Datacenter != "" {
|
||||||
datacenter2 = datacenter
|
mergedOpts.Datacenter = opts.Datacenter
|
||||||
}
|
}
|
||||||
|
mergedOpts.Peer = opts.Peer
|
||||||
|
|
||||||
return c.newTarget(service2, serviceSubset2, namespace2, partition2, datacenter2)
|
return c.newTarget(mergedOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) getSplitterOrResolverNode(target *structs.DiscoveryTarget) (*structs.DiscoveryGraphNode, error) {
|
func (c *compiler) getSplitterOrResolverNode(target *structs.DiscoveryTarget) (*structs.DiscoveryGraphNode, error) {
|
||||||
|
@ -803,10 +827,13 @@ func (c *compiler) getSplitterNode(sid structs.ServiceID) (*structs.DiscoveryGra
|
||||||
// fall through to group-resolver
|
// fall through to group-resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := c.getResolverNode(
|
opts := structs.DiscoveryTargetOpts{
|
||||||
c.newTarget(splitID.ID, split.ServiceSubset, splitID.NamespaceOrDefault(), splitID.PartitionOrDefault(), ""),
|
Service: splitID.ID,
|
||||||
false,
|
ServiceSubset: split.ServiceSubset,
|
||||||
)
|
Namespace: splitID.NamespaceOrDefault(),
|
||||||
|
Partition: splitID.PartitionOrDefault(),
|
||||||
|
}
|
||||||
|
node, err := c.getResolverNode(c.newTarget(opts), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -881,11 +908,7 @@ RESOLVE_AGAIN:
|
||||||
|
|
||||||
redirectedTarget := c.rewriteTarget(
|
redirectedTarget := c.rewriteTarget(
|
||||||
target,
|
target,
|
||||||
redirect.Service,
|
redirect.ToDiscoveryTargetOpts(),
|
||||||
redirect.ServiceSubset,
|
|
||||||
redirect.Partition,
|
|
||||||
redirect.Namespace,
|
|
||||||
redirect.Datacenter,
|
|
||||||
)
|
)
|
||||||
if redirectedTarget.ID != target.ID {
|
if redirectedTarget.ID != target.ID {
|
||||||
target = redirectedTarget
|
target = redirectedTarget
|
||||||
|
@ -895,14 +918,9 @@ RESOLVE_AGAIN:
|
||||||
|
|
||||||
// Handle default subset.
|
// Handle default subset.
|
||||||
if target.ServiceSubset == "" && resolver.DefaultSubset != "" {
|
if target.ServiceSubset == "" && resolver.DefaultSubset != "" {
|
||||||
target = c.rewriteTarget(
|
target = c.rewriteTarget(target, structs.DiscoveryTargetOpts{
|
||||||
target,
|
ServiceSubset: resolver.DefaultSubset,
|
||||||
"",
|
})
|
||||||
resolver.DefaultSubset,
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
goto RESOLVE_AGAIN
|
goto RESOLVE_AGAIN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,34 +1045,33 @@ RESOLVE_AGAIN:
|
||||||
failover, ok = f["*"]
|
failover, ok = f["*"]
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok {
|
if !ok {
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Determine which failover definitions apply.
|
// Determine which failover definitions apply.
|
||||||
var failoverTargets []*structs.DiscoveryTarget
|
var failoverTargets []*structs.DiscoveryTarget
|
||||||
if len(failover.Datacenters) > 0 {
|
if len(failover.Datacenters) > 0 {
|
||||||
|
opts := failover.ToDiscoveryTargetOpts()
|
||||||
for _, dc := range failover.Datacenters {
|
for _, dc := range failover.Datacenters {
|
||||||
// Rewrite the target as per the failover policy.
|
// Rewrite the target as per the failover policy.
|
||||||
failoverTarget := c.rewriteTarget(
|
opts.Datacenter = dc
|
||||||
target,
|
failoverTarget := c.rewriteTarget(target, opts)
|
||||||
failover.Service,
|
if failoverTarget.ID != target.ID { // don't failover to yourself
|
||||||
failover.ServiceSubset,
|
failoverTargets = append(failoverTargets, failoverTarget)
|
||||||
target.Partition,
|
}
|
||||||
failover.Namespace,
|
}
|
||||||
dc,
|
} else if len(failover.Targets) > 0 {
|
||||||
)
|
for _, t := range failover.Targets {
|
||||||
|
// Rewrite the target as per the failover policy.
|
||||||
|
failoverTarget := c.rewriteTarget(target, t.ToDiscoveryTargetOpts())
|
||||||
if failoverTarget.ID != target.ID { // don't failover to yourself
|
if failoverTarget.ID != target.ID { // don't failover to yourself
|
||||||
failoverTargets = append(failoverTargets, failoverTarget)
|
failoverTargets = append(failoverTargets, failoverTarget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Rewrite the target as per the failover policy.
|
// Rewrite the target as per the failover policy.
|
||||||
failoverTarget := c.rewriteTarget(
|
failoverTarget := c.rewriteTarget(target, failover.ToDiscoveryTargetOpts())
|
||||||
target,
|
|
||||||
failover.Service,
|
|
||||||
failover.ServiceSubset,
|
|
||||||
target.Partition,
|
|
||||||
failover.Namespace,
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
if failoverTarget.ID != target.ID { // don't failover to yourself
|
if failoverTarget.ID != target.ID { // don't failover to yourself
|
||||||
failoverTargets = append(failoverTargets, failoverTarget)
|
failoverTargets = append(failoverTargets, failoverTarget)
|
||||||
}
|
}
|
||||||
|
@ -1078,7 +1095,6 @@ RESOLVE_AGAIN:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ func TestCompile(t *testing.T) {
|
||||||
"service and subset failover": testcase_ServiceAndSubsetFailover(),
|
"service and subset failover": testcase_ServiceAndSubsetFailover(),
|
||||||
"datacenter failover": testcase_DatacenterFailover(),
|
"datacenter failover": testcase_DatacenterFailover(),
|
||||||
"datacenter failover with mesh gateways": testcase_DatacenterFailover_WithMeshGateways(),
|
"datacenter failover with mesh gateways": testcase_DatacenterFailover_WithMeshGateways(),
|
||||||
|
"target failover": testcase_Failover_Targets(),
|
||||||
"noop split to resolver with default subset": testcase_NoopSplit_WithDefaultSubset(),
|
"noop split to resolver with default subset": testcase_NoopSplit_WithDefaultSubset(),
|
||||||
"resolver with default subset": testcase_Resolve_WithDefaultSubset(),
|
"resolver with default subset": testcase_Resolve_WithDefaultSubset(),
|
||||||
"default resolver with external sni": testcase_DefaultResolver_ExternalSNI(),
|
"default resolver with external sni": testcase_DefaultResolver_ExternalSNI(),
|
||||||
|
@ -182,7 +183,7 @@ func testcase_JustRouterWithDefaults() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +245,7 @@ func testcase_JustRouterWithNoDestination() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +295,7 @@ func testcase_RouterWithDefaults_NoSplit_WithResolver() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": targetWithConnectTimeout(
|
"main.default.default.dc1": targetWithConnectTimeout(
|
||||||
newTarget("main", "", "default", "default", "dc1", nil),
|
newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -361,7 +362,7 @@ func testcase_RouterWithDefaults_WithNoopSplit_DefaultResolver() compileTestCase
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +427,10 @@ func testcase_NoopSplit_DefaultResolver_ProtocolFromProxyDefaults() compileTestC
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +502,7 @@ func testcase_RouterWithDefaults_WithNoopSplit_WithResolver() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": targetWithConnectTimeout(
|
"main.default.default.dc1": targetWithConnectTimeout(
|
||||||
newTarget("main", "", "default", "default", "dc1", nil),
|
newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -584,8 +588,11 @@ func testcase_RouteBypassesSplit() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
"bypass.other.default.default.dc1": newTarget("other", "bypass", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"bypass.other.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "other",
|
||||||
|
ServiceSubset: "bypass",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == bypass",
|
Filter: "Service.Meta.version == bypass",
|
||||||
}
|
}
|
||||||
|
@ -638,7 +645,7 @@ func testcase_NoopSplit_DefaultResolver() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +701,7 @@ func testcase_NoopSplit_WithResolver() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": targetWithConnectTimeout(
|
"main.default.default.dc1": targetWithConnectTimeout(
|
||||||
newTarget("main", "", "default", "default", "dc1", nil),
|
newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -776,12 +783,19 @@ func testcase_SubsetSplit() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"v2.main.default.default.dc1": newTarget("main", "v2", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
|
||||||
|
"v2.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "v2",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 2",
|
Filter: "Service.Meta.version == 2",
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"v1.main.default.default.dc1": newTarget("main", "v1", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"v1.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "v1",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 1",
|
Filter: "Service.Meta.version == 1",
|
||||||
}
|
}
|
||||||
|
@ -855,8 +869,8 @@ func testcase_ServiceSplit() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"foo.default.default.dc1": newTarget("foo", "", "default", "default", "dc1", nil),
|
"foo.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "foo"}, nil),
|
||||||
"bar.default.default.dc1": newTarget("bar", "", "default", "default", "dc1", nil),
|
"bar.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "bar"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,7 +949,10 @@ func testcase_SplitBypassesSplit() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"bypassed.next.default.default.dc1": newTarget("next", "bypassed", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"bypassed.next.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "next",
|
||||||
|
ServiceSubset: "bypassed",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == bypass",
|
Filter: "Service.Meta.version == bypass",
|
||||||
}
|
}
|
||||||
|
@ -973,7 +990,7 @@ func testcase_ServiceRedirect() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"other.default.default.dc1": newTarget("other", "", "default", "default", "dc1", nil),
|
"other.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "other"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1019,7 +1036,10 @@ func testcase_ServiceAndSubsetRedirect() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"v2.other.default.default.dc1": newTarget("other", "v2", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"v2.other.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "other",
|
||||||
|
ServiceSubset: "v2",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 2",
|
Filter: "Service.Meta.version == 2",
|
||||||
}
|
}
|
||||||
|
@ -1055,7 +1075,10 @@ func testcase_DatacenterRedirect() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc9": newTarget("main", "", "default", "default", "dc9", nil),
|
"main.default.default.dc9": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc9",
|
||||||
|
}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect}
|
return compileTestCase{entries: entries, expect: expect}
|
||||||
|
@ -1095,7 +1118,10 @@ func testcase_DatacenterRedirect_WithMeshGateways() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc9": newTarget("main", "", "default", "default", "dc9", func(t *structs.DiscoveryTarget) {
|
"main.default.default.dc9": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc9",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.MeshGateway = structs.MeshGatewayConfig{
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
Mode: structs.MeshGatewayModeRemote,
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
}
|
}
|
||||||
|
@ -1134,8 +1160,8 @@ func testcase_ServiceFailover() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
"backup.default.default.dc1": newTarget("backup", "", "default", "default", "dc1", nil),
|
"backup.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "backup"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect}
|
return compileTestCase{entries: entries, expect: expect}
|
||||||
|
@ -1177,8 +1203,8 @@ func testcase_ServiceFailoverThroughRedirect() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
"actual.default.default.dc1": newTarget("actual", "", "default", "default", "dc1", nil),
|
"actual.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "actual"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect}
|
return compileTestCase{entries: entries, expect: expect}
|
||||||
|
@ -1220,8 +1246,8 @@ func testcase_Resolver_CircularFailover() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
"backup.default.default.dc1": newTarget("backup", "", "default", "default", "dc1", nil),
|
"backup.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "backup"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect}
|
return compileTestCase{entries: entries, expect: expect}
|
||||||
|
@ -1261,8 +1287,11 @@ func testcase_ServiceAndSubsetFailover() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
"backup.main.default.default.dc1": newTarget("main", "backup", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"backup.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "backup",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == backup",
|
Filter: "Service.Meta.version == backup",
|
||||||
}
|
}
|
||||||
|
@ -1301,9 +1330,15 @@ func testcase_DatacenterFailover() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
"main.default.default.dc2": newTarget("main", "", "default", "default", "dc2", nil),
|
"main.default.default.dc2": newTarget(structs.DiscoveryTargetOpts{
|
||||||
"main.default.default.dc4": newTarget("main", "", "default", "default", "dc4", nil),
|
Service: "main",
|
||||||
|
Datacenter: "dc2",
|
||||||
|
}, nil),
|
||||||
|
"main.default.default.dc4": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc4",
|
||||||
|
}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect}
|
return compileTestCase{entries: entries, expect: expect}
|
||||||
|
@ -1350,17 +1385,105 @@ func testcase_DatacenterFailover_WithMeshGateways() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) {
|
||||||
t.MeshGateway = structs.MeshGatewayConfig{
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
Mode: structs.MeshGatewayModeRemote,
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"main.default.default.dc2": newTarget("main", "", "default", "default", "dc2", func(t *structs.DiscoveryTarget) {
|
"main.default.default.dc2": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc2",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.MeshGateway = structs.MeshGatewayConfig{
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
Mode: structs.MeshGatewayModeRemote,
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"main.default.default.dc4": newTarget("main", "", "default", "default", "dc4", func(t *structs.DiscoveryTarget) {
|
"main.default.default.dc4": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc4",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return compileTestCase{entries: entries, expect: expect}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testcase_Failover_Targets() compileTestCase {
|
||||||
|
entries := newEntries()
|
||||||
|
|
||||||
|
entries.AddProxyDefaults(&structs.ProxyConfigEntry{
|
||||||
|
Kind: structs.ProxyDefaults,
|
||||||
|
Name: structs.ProxyConfigGlobal,
|
||||||
|
MeshGateway: structs.MeshGatewayConfig{
|
||||||
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
entries.AddResolvers(
|
||||||
|
&structs.ServiceResolverConfigEntry{
|
||||||
|
Kind: "service-resolver",
|
||||||
|
Name: "main",
|
||||||
|
Failover: map[string]structs.ServiceResolverFailover{
|
||||||
|
"*": {
|
||||||
|
Targets: []structs.ServiceResolverFailoverTarget{
|
||||||
|
{Datacenter: "dc3"},
|
||||||
|
{Service: "new-main"},
|
||||||
|
{Peer: "cluster-01"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect := &structs.CompiledDiscoveryChain{
|
||||||
|
Protocol: "tcp",
|
||||||
|
StartNode: "resolver:main.default.default.dc1",
|
||||||
|
Nodes: map[string]*structs.DiscoveryGraphNode{
|
||||||
|
"resolver:main.default.default.dc1": {
|
||||||
|
Type: structs.DiscoveryGraphNodeTypeResolver,
|
||||||
|
Name: "main.default.default.dc1",
|
||||||
|
Resolver: &structs.DiscoveryResolver{
|
||||||
|
ConnectTimeout: 5 * time.Second,
|
||||||
|
Target: "main.default.default.dc1",
|
||||||
|
Failover: &structs.DiscoveryFailover{
|
||||||
|
Targets: []string{
|
||||||
|
"main.default.default.dc3",
|
||||||
|
"new-main.default.default.dc1",
|
||||||
|
"main.default.default.external.cluster-01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) {
|
||||||
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"main.default.default.dc3": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc3",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"new-main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "new-main"}, func(t *structs.DiscoveryTarget) {
|
||||||
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"main.default.default.external.cluster-01": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Peer: "cluster-01",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
|
t.SNI = ""
|
||||||
|
t.Name = ""
|
||||||
|
t.Datacenter = ""
|
||||||
t.MeshGateway = structs.MeshGatewayConfig{
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
Mode: structs.MeshGatewayModeRemote,
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
}
|
}
|
||||||
|
@ -1422,7 +1545,10 @@ func testcase_NoopSplit_WithDefaultSubset() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"v2.main.default.default.dc1": newTarget("main", "v2", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"v2.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "v2",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 2",
|
Filter: "Service.Meta.version == 2",
|
||||||
}
|
}
|
||||||
|
@ -1452,7 +1578,7 @@ func testcase_DefaultResolver() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
// TODO-TARGET
|
// TODO-TARGET
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect}
|
return compileTestCase{entries: entries, expect: expect}
|
||||||
|
@ -1488,7 +1614,7 @@ func testcase_DefaultResolver_WithProxyDefaults() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) {
|
||||||
t.MeshGateway = structs.MeshGatewayConfig{
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
Mode: structs.MeshGatewayModeRemote,
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
}
|
}
|
||||||
|
@ -1530,7 +1656,7 @@ func testcase_ServiceMetaProjection() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1588,7 +1714,7 @@ func testcase_ServiceMetaProjectionWithRedirect() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"other.default.default.dc1": newTarget("other", "", "default", "default", "dc1", nil),
|
"other.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "other"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1623,7 +1749,7 @@ func testcase_RedirectToDefaultResolverIsNotDefaultChain() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"other.default.default.dc1": newTarget("other", "", "default", "default", "dc1", nil),
|
"other.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "other"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1658,7 +1784,10 @@ func testcase_Resolve_WithDefaultSubset() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"v2.main.default.default.dc1": newTarget("main", "v2", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"v2.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "v2",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 2",
|
Filter: "Service.Meta.version == 2",
|
||||||
}
|
}
|
||||||
|
@ -1692,7 +1821,7 @@ func testcase_DefaultResolver_ExternalSNI() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) {
|
||||||
t.SNI = "main.some.other.service.mesh"
|
t.SNI = "main.some.other.service.mesh"
|
||||||
t.External = true
|
t.External = true
|
||||||
}),
|
}),
|
||||||
|
@ -1857,11 +1986,17 @@ func testcase_MultiDatacenterCanary() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc2": targetWithConnectTimeout(
|
"main.default.default.dc2": targetWithConnectTimeout(
|
||||||
newTarget("main", "", "default", "default", "dc2", nil),
|
newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc2",
|
||||||
|
}, nil),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
"main.default.default.dc3": targetWithConnectTimeout(
|
"main.default.default.dc3": targetWithConnectTimeout(
|
||||||
newTarget("main", "", "default", "default", "dc3", nil),
|
newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Datacenter: "dc3",
|
||||||
|
}, nil),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -2155,27 +2290,42 @@ func testcase_AllBellsAndWhistles() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"prod.redirected.default.default.dc1": newTarget("redirected", "prod", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"prod.redirected.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "redirected",
|
||||||
|
ServiceSubset: "prod",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "ServiceMeta.env == prod",
|
Filter: "ServiceMeta.env == prod",
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"v1.main.default.default.dc1": newTarget("main", "v1", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"v1.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "v1",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 1",
|
Filter: "Service.Meta.version == 1",
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"v2.main.default.default.dc1": newTarget("main", "v2", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"v2.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "v2",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 2",
|
Filter: "Service.Meta.version == 2",
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"v3.main.default.default.dc1": newTarget("main", "v3", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"v3.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "v3",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{
|
t.Subset = structs.ServiceResolverSubset{
|
||||||
Filter: "Service.Meta.version == 3",
|
Filter: "Service.Meta.version == 3",
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"default-subset.main.default.default.dc1": newTarget("main", "default-subset", "default", "default", "dc1", func(t *structs.DiscoveryTarget) {
|
"default-subset.main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
ServiceSubset: "default-subset",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.Subset = structs.ServiceResolverSubset{OnlyPassing: true}
|
t.Subset = structs.ServiceResolverSubset{OnlyPassing: true}
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -2379,7 +2529,7 @@ func testcase_ResolverProtocolOverride() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
// TODO-TARGET
|
// TODO-TARGET
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect,
|
return compileTestCase{entries: entries, expect: expect,
|
||||||
|
@ -2413,7 +2563,7 @@ func testcase_ResolverProtocolOverrideIgnored() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
// TODO-TARGET
|
// TODO-TARGET
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect,
|
return compileTestCase{entries: entries, expect: expect,
|
||||||
|
@ -2451,7 +2601,7 @@ func testcase_RouterIgnored_ResolverProtocolOverride() compileTestCase {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
// TODO-TARGET
|
// TODO-TARGET
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return compileTestCase{entries: entries, expect: expect,
|
return compileTestCase{entries: entries, expect: expect,
|
||||||
|
@ -2685,9 +2835,9 @@ func testcase_LBSplitterAndResolver() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"foo.default.default.dc1": newTarget("foo", "", "default", "default", "dc1", nil),
|
"foo.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "foo"}, nil),
|
||||||
"bar.default.default.dc1": newTarget("bar", "", "default", "default", "dc1", nil),
|
"bar.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "bar"}, nil),
|
||||||
"baz.default.default.dc1": newTarget("baz", "", "default", "default", "dc1", nil),
|
"baz.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "baz"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2743,7 +2893,7 @@ func testcase_LBResolver() compileTestCase {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"main.default.default.dc1": newTarget("main", "", "default", "default", "dc1", nil),
|
"main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2791,8 +2941,17 @@ func newEntries() *configentry.DiscoveryChainSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTarget(service, serviceSubset, namespace, partition, datacenter string, modFn func(t *structs.DiscoveryTarget)) *structs.DiscoveryTarget {
|
func newTarget(opts structs.DiscoveryTargetOpts, modFn func(t *structs.DiscoveryTarget)) *structs.DiscoveryTarget {
|
||||||
t := structs.NewDiscoveryTarget(service, serviceSubset, namespace, partition, datacenter)
|
if opts.Namespace == "" {
|
||||||
|
opts.Namespace = "default"
|
||||||
|
}
|
||||||
|
if opts.Partition == "" {
|
||||||
|
opts.Partition = "default"
|
||||||
|
}
|
||||||
|
if opts.Datacenter == "" {
|
||||||
|
opts.Datacenter = "dc1"
|
||||||
|
}
|
||||||
|
t := structs.NewDiscoveryTarget(opts)
|
||||||
t.SNI = connect.TargetSNI(t, "trustdomain.consul")
|
t.SNI = connect.TargetSNI(t, "trustdomain.consul")
|
||||||
t.Name = t.SNI
|
t.Name = t.SNI
|
||||||
t.ConnectTimeout = 5 * time.Second // default
|
t.ConnectTimeout = 5 * time.Second // default
|
||||||
|
|
|
@ -1461,7 +1461,13 @@ func TestStateStore_ExportedServicesForPeer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
newTarget := func(service, serviceSubset, datacenter string) *structs.DiscoveryTarget {
|
newTarget := func(service, serviceSubset, datacenter string) *structs.DiscoveryTarget {
|
||||||
t := structs.NewDiscoveryTarget(service, serviceSubset, "default", "default", datacenter)
|
t := structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: service,
|
||||||
|
ServiceSubset: serviceSubset,
|
||||||
|
Partition: "default",
|
||||||
|
Namespace: "default",
|
||||||
|
Datacenter: datacenter,
|
||||||
|
})
|
||||||
t.SNI = connect.TargetSNI(t, connect.TestTrustDomain)
|
t.SNI = connect.TargetSNI(t, connect.TestTrustDomain)
|
||||||
t.Name = t.SNI
|
t.Name = t.SNI
|
||||||
t.ConnectTimeout = 5 * time.Second // default
|
t.ConnectTimeout = 5 * time.Second // default
|
||||||
|
|
|
@ -27,8 +27,17 @@ func TestDiscoveryChainRead(t *testing.T) {
|
||||||
defer a.Shutdown()
|
defer a.Shutdown()
|
||||||
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
newTarget := func(service, serviceSubset, namespace, partition, datacenter string) *structs.DiscoveryTarget {
|
newTarget := func(opts structs.DiscoveryTargetOpts) *structs.DiscoveryTarget {
|
||||||
t := structs.NewDiscoveryTarget(service, serviceSubset, namespace, partition, datacenter)
|
if opts.Namespace == "" {
|
||||||
|
opts.Namespace = "default"
|
||||||
|
}
|
||||||
|
if opts.Partition == "" {
|
||||||
|
opts.Partition = "default"
|
||||||
|
}
|
||||||
|
if opts.Datacenter == "" {
|
||||||
|
opts.Datacenter = "dc1"
|
||||||
|
}
|
||||||
|
t := structs.NewDiscoveryTarget(opts)
|
||||||
t.SNI = connect.TargetSNI(t, connect.TestClusterID+".consul")
|
t.SNI = connect.TargetSNI(t, connect.TestClusterID+".consul")
|
||||||
t.Name = t.SNI
|
t.Name = t.SNI
|
||||||
t.ConnectTimeout = 5 * time.Second // default
|
t.ConnectTimeout = 5 * time.Second // default
|
||||||
|
@ -99,7 +108,7 @@ func TestDiscoveryChainRead(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"web.default.default.dc1": newTarget("web", "", "default", "default", "dc1"),
|
"web.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "web"}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
require.Equal(t, expect, value.Chain)
|
require.Equal(t, expect, value.Chain)
|
||||||
|
@ -144,7 +153,7 @@ func TestDiscoveryChainRead(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"web.default.default.dc2": newTarget("web", "", "default", "default", "dc2"),
|
"web.default.default.dc2": newTarget(structs.DiscoveryTargetOpts{Service: "web", Datacenter: "dc2"}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
require.Equal(t, expect, value.Chain)
|
require.Equal(t, expect, value.Chain)
|
||||||
|
@ -198,7 +207,7 @@ func TestDiscoveryChainRead(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"web.default.default.dc1": newTarget("web", "", "default", "default", "dc1"),
|
"web.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "web"}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
require.Equal(t, expect, value.Chain)
|
require.Equal(t, expect, value.Chain)
|
||||||
|
@ -264,11 +273,11 @@ func TestDiscoveryChainRead(t *testing.T) {
|
||||||
},
|
},
|
||||||
Targets: map[string]*structs.DiscoveryTarget{
|
Targets: map[string]*structs.DiscoveryTarget{
|
||||||
"web.default.default.dc1": targetWithConnectTimeout(
|
"web.default.default.dc1": targetWithConnectTimeout(
|
||||||
newTarget("web", "", "default", "default", "dc1"),
|
newTarget(structs.DiscoveryTargetOpts{Service: "web"}),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
"web.default.default.dc2": targetWithConnectTimeout(
|
"web.default.default.dc2": targetWithConnectTimeout(
|
||||||
newTarget("web", "", "default", "default", "dc2"),
|
newTarget(structs.DiscoveryTargetOpts{Service: "web", Datacenter: "dc2"}),
|
||||||
33*time.Second,
|
33*time.Second,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -280,7 +289,7 @@ func TestDiscoveryChainRead(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
expectTarget_DC1 := targetWithConnectTimeout(
|
expectTarget_DC1 := targetWithConnectTimeout(
|
||||||
newTarget("web", "", "default", "default", "dc1"),
|
newTarget(structs.DiscoveryTargetOpts{Service: "web"}),
|
||||||
22*time.Second,
|
22*time.Second,
|
||||||
)
|
)
|
||||||
expectTarget_DC1.MeshGateway = structs.MeshGatewayConfig{
|
expectTarget_DC1.MeshGateway = structs.MeshGatewayConfig{
|
||||||
|
@ -288,7 +297,7 @@ func TestDiscoveryChainRead(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expectTarget_DC2 := targetWithConnectTimeout(
|
expectTarget_DC2 := targetWithConnectTimeout(
|
||||||
newTarget("web", "", "default", "default", "dc2"),
|
newTarget(structs.DiscoveryTargetOpts{Service: "web", Datacenter: "dc2"}),
|
||||||
22*time.Second,
|
22*time.Second,
|
||||||
)
|
)
|
||||||
expectTarget_DC2.MeshGateway = structs.MeshGatewayConfig{
|
expectTarget_DC2.MeshGateway = structs.MeshGatewayConfig{
|
||||||
|
|
|
@ -63,22 +63,29 @@ func NewUpstreamIDFromServiceID(sid structs.ServiceID) UpstreamID {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(peering): confirm we don't need peername here
|
|
||||||
func NewUpstreamIDFromTargetID(tid string) UpstreamID {
|
func NewUpstreamIDFromTargetID(tid string) UpstreamID {
|
||||||
// Drop the leading subset if one is present in the target ID.
|
var id UpstreamID
|
||||||
separators := strings.Count(tid, ".")
|
split := strings.Split(tid, ".")
|
||||||
if separators > 3 {
|
|
||||||
prefix := tid[:strings.Index(tid, ".")+1]
|
switch {
|
||||||
tid = strings.TrimPrefix(tid, prefix)
|
case split[len(split)-2] == "external":
|
||||||
|
id = UpstreamID{
|
||||||
|
Name: split[0],
|
||||||
|
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(split[2], split[1]),
|
||||||
|
Peer: split[4],
|
||||||
}
|
}
|
||||||
|
case len(split) == 5:
|
||||||
split := strings.SplitN(tid, ".", 4)
|
// Drop the leading subset if one is present in the target ID.
|
||||||
|
split = split[1:]
|
||||||
id := UpstreamID{
|
fallthrough
|
||||||
|
default:
|
||||||
|
id = UpstreamID{
|
||||||
Name: split[0],
|
Name: split[0],
|
||||||
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(split[2], split[1]),
|
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(split[2], split[1]),
|
||||||
Datacenter: split[3],
|
Datacenter: split[3],
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
id.normalize()
|
id.normalize()
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,13 @@ func TestUpstreamIDFromTargetID(t *testing.T) {
|
||||||
Datacenter: "dc2",
|
Datacenter: "dc2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"peered": {
|
||||||
|
tid: "foo.default.default.external.cluster-01",
|
||||||
|
expect: UpstreamID{
|
||||||
|
Name: "foo",
|
||||||
|
Peer: "cluster-01",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tc := range cases {
|
for name, tc := range cases {
|
||||||
|
|
|
@ -1233,6 +1233,16 @@ type ServiceResolverRedirect struct {
|
||||||
Datacenter string `json:",omitempty"`
|
Datacenter string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ServiceResolverRedirect) ToDiscoveryTargetOpts() DiscoveryTargetOpts {
|
||||||
|
return DiscoveryTargetOpts{
|
||||||
|
Service: r.Service,
|
||||||
|
ServiceSubset: r.ServiceSubset,
|
||||||
|
Namespace: r.Namespace,
|
||||||
|
Partition: r.Partition,
|
||||||
|
Datacenter: r.Datacenter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// There are some restrictions on what is allowed in here:
|
// There are some restrictions on what is allowed in here:
|
||||||
//
|
//
|
||||||
// - Service, ServiceSubset, Namespace, Datacenters, and Targets cannot all be
|
// - Service, ServiceSubset, Namespace, Datacenters, and Targets cannot all be
|
||||||
|
@ -1275,6 +1285,14 @@ type ServiceResolverFailover struct {
|
||||||
Targets []ServiceResolverFailoverTarget `json:",omitempty"`
|
Targets []ServiceResolverFailoverTarget `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *ServiceResolverFailover) ToDiscoveryTargetOpts() DiscoveryTargetOpts {
|
||||||
|
return DiscoveryTargetOpts{
|
||||||
|
Service: t.Service,
|
||||||
|
ServiceSubset: t.ServiceSubset,
|
||||||
|
Namespace: t.Namespace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *ServiceResolverFailover) isEmpty() bool {
|
func (f *ServiceResolverFailover) isEmpty() bool {
|
||||||
return f.Service == "" && f.ServiceSubset == "" && f.Namespace == "" && len(f.Datacenters) == 0 && len(f.Targets) == 0
|
return f.Service == "" && f.ServiceSubset == "" && f.Namespace == "" && len(f.Datacenters) == 0 && len(f.Targets) == 0
|
||||||
}
|
}
|
||||||
|
@ -1299,6 +1317,17 @@ type ServiceResolverFailoverTarget struct {
|
||||||
Peer string `json:",omitempty"`
|
Peer string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *ServiceResolverFailoverTarget) ToDiscoveryTargetOpts() DiscoveryTargetOpts {
|
||||||
|
return DiscoveryTargetOpts{
|
||||||
|
Service: t.Service,
|
||||||
|
ServiceSubset: t.ServiceSubset,
|
||||||
|
Namespace: t.Namespace,
|
||||||
|
Partition: t.Partition,
|
||||||
|
Datacenter: t.Datacenter,
|
||||||
|
Peer: t.Peer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LoadBalancer determines the load balancing policy and configuration for services
|
// LoadBalancer determines the load balancing policy and configuration for services
|
||||||
// issuing requests to this upstream service.
|
// issuing requests to this upstream service.
|
||||||
type LoadBalancer struct {
|
type LoadBalancer struct {
|
||||||
|
|
|
@ -56,7 +56,12 @@ type CompiledDiscoveryChain struct {
|
||||||
// ID returns an ID that encodes the service, namespace, partition, and datacenter.
|
// ID returns an ID that encodes the service, namespace, partition, and datacenter.
|
||||||
// This ID allows us to compare a discovery chain target to the chain upstream itself.
|
// This ID allows us to compare a discovery chain target to the chain upstream itself.
|
||||||
func (c *CompiledDiscoveryChain) ID() string {
|
func (c *CompiledDiscoveryChain) ID() string {
|
||||||
return chainID("", c.ServiceName, c.Namespace, c.Partition, c.Datacenter)
|
return chainID(DiscoveryTargetOpts{
|
||||||
|
Service: c.ServiceName,
|
||||||
|
Namespace: c.Namespace,
|
||||||
|
Partition: c.Partition,
|
||||||
|
Datacenter: c.Datacenter,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CompiledDiscoveryChain) CompoundServiceName() ServiceName {
|
func (c *CompiledDiscoveryChain) CompoundServiceName() ServiceName {
|
||||||
|
@ -185,6 +190,7 @@ type DiscoveryTarget struct {
|
||||||
Namespace string `json:",omitempty"`
|
Namespace string `json:",omitempty"`
|
||||||
Partition string `json:",omitempty"`
|
Partition string `json:",omitempty"`
|
||||||
Datacenter string `json:",omitempty"`
|
Datacenter string `json:",omitempty"`
|
||||||
|
Peer string `json:",omitempty"`
|
||||||
|
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty"`
|
MeshGateway MeshGatewayConfig `json:",omitempty"`
|
||||||
Subset ServiceResolverSubset `json:",omitempty"`
|
Subset ServiceResolverSubset `json:",omitempty"`
|
||||||
|
@ -240,28 +246,52 @@ func (t *DiscoveryTarget) UnmarshalJSON(data []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDiscoveryTarget(service, serviceSubset, namespace, partition, datacenter string) *DiscoveryTarget {
|
type DiscoveryTargetOpts struct {
|
||||||
|
Service string
|
||||||
|
ServiceSubset string
|
||||||
|
Namespace string
|
||||||
|
Partition string
|
||||||
|
Datacenter string
|
||||||
|
Peer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDiscoveryTarget(opts DiscoveryTargetOpts) *DiscoveryTarget {
|
||||||
t := &DiscoveryTarget{
|
t := &DiscoveryTarget{
|
||||||
Service: service,
|
Service: opts.Service,
|
||||||
ServiceSubset: serviceSubset,
|
ServiceSubset: opts.ServiceSubset,
|
||||||
Namespace: namespace,
|
Namespace: opts.Namespace,
|
||||||
Partition: partition,
|
Partition: opts.Partition,
|
||||||
Datacenter: datacenter,
|
Datacenter: opts.Datacenter,
|
||||||
|
Peer: opts.Peer,
|
||||||
}
|
}
|
||||||
t.setID()
|
t.setID()
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func chainID(subset, service, namespace, partition, dc string) string {
|
func (t *DiscoveryTarget) ToDiscoveryTargetOpts() DiscoveryTargetOpts {
|
||||||
// NOTE: this format is similar to the SNI syntax for simplicity
|
return DiscoveryTargetOpts{
|
||||||
if subset == "" {
|
Service: t.Service,
|
||||||
return fmt.Sprintf("%s.%s.%s.%s", service, namespace, partition, dc)
|
ServiceSubset: t.ServiceSubset,
|
||||||
|
Namespace: t.Namespace,
|
||||||
|
Partition: t.Partition,
|
||||||
|
Datacenter: t.Datacenter,
|
||||||
|
Peer: t.Peer,
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s.%s.%s.%s.%s", subset, service, namespace, partition, dc)
|
}
|
||||||
|
|
||||||
|
func chainID(opts DiscoveryTargetOpts) string {
|
||||||
|
// NOTE: this format is similar to the SNI syntax for simplicity
|
||||||
|
if opts.Peer != "" {
|
||||||
|
return fmt.Sprintf("%s.%s.default.external.%s", opts.Service, opts.Namespace, opts.Peer)
|
||||||
|
}
|
||||||
|
if opts.ServiceSubset == "" {
|
||||||
|
return fmt.Sprintf("%s.%s.%s.%s", opts.Service, opts.Namespace, opts.Partition, opts.Datacenter)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s.%s.%s.%s.%s", opts.ServiceSubset, opts.Service, opts.Namespace, opts.Partition, opts.Datacenter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *DiscoveryTarget) setID() {
|
func (t *DiscoveryTarget) setID() {
|
||||||
t.ID = chainID(t.ServiceSubset, t.Service, t.Namespace, t.Partition, t.Datacenter)
|
t.ID = chainID(t.ToDiscoveryTargetOpts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *DiscoveryTarget) String() string {
|
func (t *DiscoveryTarget) String() string {
|
||||||
|
|
|
@ -15,15 +15,40 @@ func TestFirstHealthyTarget(t *testing.T) {
|
||||||
warning := proxycfg.TestUpstreamNodesInStatus(t, "warning")
|
warning := proxycfg.TestUpstreamNodesInStatus(t, "warning")
|
||||||
critical := proxycfg.TestUpstreamNodesInStatus(t, "critical")
|
critical := proxycfg.TestUpstreamNodesInStatus(t, "critical")
|
||||||
|
|
||||||
warnOnlyPassingTarget := structs.NewDiscoveryTarget("all-warn", "", "default", "default", "dc1")
|
warnOnlyPassingTarget := structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "all-warn",
|
||||||
|
Namespace: "default",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
})
|
||||||
warnOnlyPassingTarget.Subset.OnlyPassing = true
|
warnOnlyPassingTarget.Subset.OnlyPassing = true
|
||||||
failOnlyPassingTarget := structs.NewDiscoveryTarget("all-fail", "", "default", "default", "dc1")
|
failOnlyPassingTarget := structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "all-fail",
|
||||||
|
Namespace: "default",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
})
|
||||||
failOnlyPassingTarget.Subset.OnlyPassing = true
|
failOnlyPassingTarget.Subset.OnlyPassing = true
|
||||||
|
|
||||||
targets := map[string]*structs.DiscoveryTarget{
|
targets := map[string]*structs.DiscoveryTarget{
|
||||||
"all-ok.default.dc1": structs.NewDiscoveryTarget("all-ok", "", "default", "default", "dc1"),
|
"all-ok.default.dc1": structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
"all-warn.default.dc1": structs.NewDiscoveryTarget("all-warn", "", "default", "default", "dc1"),
|
Service: "all-ok",
|
||||||
"all-fail.default.default.dc1": structs.NewDiscoveryTarget("all-fail", "", "default", "default", "dc1"),
|
Namespace: "default",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
}),
|
||||||
|
"all-warn.default.dc1": structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "all-warn",
|
||||||
|
Namespace: "default",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
}),
|
||||||
|
"all-fail.default.default.dc1": structs.NewDiscoveryTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "all-fail",
|
||||||
|
Namespace: "default",
|
||||||
|
Partition: "default",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
}),
|
||||||
"all-warn-onlypassing.default.dc1": warnOnlyPassingTarget,
|
"all-warn-onlypassing.default.dc1": warnOnlyPassingTarget,
|
||||||
"all-fail-onlypassing.default.dc1": failOnlyPassingTarget,
|
"all-fail-onlypassing.default.dc1": failOnlyPassingTarget,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue