mirror of https://github.com/status-im/consul.git
Add Peer Locality to Discovery Chains (#16588)
Add peer locality to discovery chains
This commit is contained in:
parent
57e2493415
commit
e298f506a5
|
@ -2,6 +2,7 @@ package configentry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/hashicorp/consul/proto/private/pbpeering"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DiscoveryChainSet is a wrapped set of raw cross-referenced config entries
|
// DiscoveryChainSet is a wrapped set of raw cross-referenced config entries
|
||||||
|
@ -13,6 +14,7 @@ type DiscoveryChainSet struct {
|
||||||
Splitters map[structs.ServiceID]*structs.ServiceSplitterConfigEntry
|
Splitters map[structs.ServiceID]*structs.ServiceSplitterConfigEntry
|
||||||
Resolvers map[structs.ServiceID]*structs.ServiceResolverConfigEntry
|
Resolvers map[structs.ServiceID]*structs.ServiceResolverConfigEntry
|
||||||
Services map[structs.ServiceID]*structs.ServiceConfigEntry
|
Services map[structs.ServiceID]*structs.ServiceConfigEntry
|
||||||
|
Peers map[string]*pbpeering.Peering
|
||||||
ProxyDefaults map[string]*structs.ProxyConfigEntry
|
ProxyDefaults map[string]*structs.ProxyConfigEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ func NewDiscoveryChainSet() *DiscoveryChainSet {
|
||||||
Splitters: make(map[structs.ServiceID]*structs.ServiceSplitterConfigEntry),
|
Splitters: make(map[structs.ServiceID]*structs.ServiceSplitterConfigEntry),
|
||||||
Resolvers: make(map[structs.ServiceID]*structs.ServiceResolverConfigEntry),
|
Resolvers: make(map[structs.ServiceID]*structs.ServiceResolverConfigEntry),
|
||||||
Services: make(map[structs.ServiceID]*structs.ServiceConfigEntry),
|
Services: make(map[structs.ServiceID]*structs.ServiceConfigEntry),
|
||||||
|
Peers: make(map[string]*pbpeering.Peering),
|
||||||
ProxyDefaults: make(map[string]*structs.ProxyConfigEntry),
|
ProxyDefaults: make(map[string]*structs.ProxyConfigEntry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +114,16 @@ func (e *DiscoveryChainSet) AddProxyDefaults(entries ...*structs.ProxyConfigEntr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddPeers adds cluster peers. Convenience function for testing.
|
||||||
|
func (e *DiscoveryChainSet) AddPeers(entries ...*pbpeering.Peering) {
|
||||||
|
if e.Peers == nil {
|
||||||
|
e.Peers = make(map[string]*pbpeering.Peering)
|
||||||
|
}
|
||||||
|
for _, entry := range entries {
|
||||||
|
e.Peers[entry.Name] = entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddEntries adds generic configs. Convenience function for testing. Panics on
|
// AddEntries adds generic configs. Convenience function for testing. Panics on
|
||||||
// operator error.
|
// operator error.
|
||||||
func (e *DiscoveryChainSet) AddEntries(entries ...structs.ConfigEntry) {
|
func (e *DiscoveryChainSet) AddEntries(entries ...structs.ConfigEntry) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"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"
|
||||||
|
"github.com/hashicorp/consul/proto/private/pbpeering"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CompileRequest struct {
|
type CompileRequest struct {
|
||||||
|
@ -736,6 +737,11 @@ func (c *compiler) newTarget(opts structs.DiscoveryTargetOpts) *structs.Discover
|
||||||
// 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
|
||||||
|
} else {
|
||||||
|
peer := c.entries.Peers[opts.Peer]
|
||||||
|
if peer != nil && peer.Remote != nil {
|
||||||
|
t.Locality = pbpeering.LocalityToStructs(peer.Remote.Locality)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prev, ok := c.loadedTargets[t.ID]
|
prev, ok := c.loadedTargets[t.ID]
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"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"
|
||||||
|
"github.com/hashicorp/consul/proto/private/pbcommon"
|
||||||
|
"github.com/hashicorp/consul/proto/private/pbpeering"
|
||||||
)
|
)
|
||||||
|
|
||||||
type compileTestCase struct {
|
type compileTestCase struct {
|
||||||
|
@ -1578,12 +1580,25 @@ func testcase_Failover_Targets() compileTestCase {
|
||||||
{Datacenter: "dc3"},
|
{Datacenter: "dc3"},
|
||||||
{Service: "new-main"},
|
{Service: "new-main"},
|
||||||
{Peer: "cluster-01"},
|
{Peer: "cluster-01"},
|
||||||
|
{Peer: "cluster-02"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
entries.AddPeers(
|
||||||
|
&pbpeering.Peering{
|
||||||
|
Name: "cluster-01",
|
||||||
|
Remote: &pbpeering.RemoteInfo{
|
||||||
|
Locality: &pbcommon.Locality{
|
||||||
|
Region: "us-west-1",
|
||||||
|
Zone: "us-west-1a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
expect := &structs.CompiledDiscoveryChain{
|
expect := &structs.CompiledDiscoveryChain{
|
||||||
Protocol: "tcp",
|
Protocol: "tcp",
|
||||||
StartNode: "resolver:main.default.default.dc1",
|
StartNode: "resolver:main.default.default.dc1",
|
||||||
|
@ -1599,6 +1614,7 @@ func testcase_Failover_Targets() compileTestCase {
|
||||||
"main.default.default.dc3",
|
"main.default.default.dc3",
|
||||||
"new-main.default.default.dc1",
|
"new-main.default.default.dc1",
|
||||||
"main.default.default.external.cluster-01",
|
"main.default.default.external.cluster-01",
|
||||||
|
"main.default.default.external.cluster-02",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1626,6 +1642,21 @@ func testcase_Failover_Targets() compileTestCase {
|
||||||
"main.default.default.external.cluster-01": newTarget(structs.DiscoveryTargetOpts{
|
"main.default.default.external.cluster-01": newTarget(structs.DiscoveryTargetOpts{
|
||||||
Service: "main",
|
Service: "main",
|
||||||
Peer: "cluster-01",
|
Peer: "cluster-01",
|
||||||
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
|
t.SNI = ""
|
||||||
|
t.Name = ""
|
||||||
|
t.Datacenter = ""
|
||||||
|
t.MeshGateway = structs.MeshGatewayConfig{
|
||||||
|
Mode: structs.MeshGatewayModeRemote,
|
||||||
|
}
|
||||||
|
t.Locality = &structs.Locality{
|
||||||
|
Region: "us-west-1",
|
||||||
|
Zone: "us-west-1a",
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"main.default.default.external.cluster-02": newTarget(structs.DiscoveryTargetOpts{
|
||||||
|
Service: "main",
|
||||||
|
Peer: "cluster-02",
|
||||||
}, func(t *structs.DiscoveryTarget) {
|
}, func(t *structs.DiscoveryTarget) {
|
||||||
t.SNI = ""
|
t.SNI = ""
|
||||||
t.Name = ""
|
t.Name = ""
|
||||||
|
|
|
@ -1293,6 +1293,7 @@ func readDiscoveryChainConfigEntriesTxn(
|
||||||
todoSplitters = make(map[structs.ServiceID]struct{})
|
todoSplitters = make(map[structs.ServiceID]struct{})
|
||||||
todoResolvers = make(map[structs.ServiceID]struct{})
|
todoResolvers = make(map[structs.ServiceID]struct{})
|
||||||
todoDefaults = make(map[structs.ServiceID]struct{})
|
todoDefaults = make(map[structs.ServiceID]struct{})
|
||||||
|
todoPeers = make(map[string]struct{})
|
||||||
)
|
)
|
||||||
|
|
||||||
sid := structs.NewServiceID(serviceName, entMeta)
|
sid := structs.NewServiceID(serviceName, entMeta)
|
||||||
|
@ -1394,6 +1395,10 @@ func readDiscoveryChainConfigEntriesTxn(
|
||||||
for _, svc := range resolver.ListRelatedServices() {
|
for _, svc := range resolver.ListRelatedServices() {
|
||||||
todoResolvers[svc] = struct{}{}
|
todoResolvers[svc] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, peer := range resolver.RelatedPeers() {
|
||||||
|
todoPeers[peer] = struct{}{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -1435,6 +1440,23 @@ func readDiscoveryChainConfigEntriesTxn(
|
||||||
res.Services[svcID] = entry
|
res.Services[svcID] = entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peerEntMeta := structs.DefaultEnterpriseMetaInPartition(entMeta.PartitionOrDefault())
|
||||||
|
for peerName := range todoPeers {
|
||||||
|
q := Query{
|
||||||
|
Value: peerName,
|
||||||
|
EnterpriseMeta: *peerEntMeta,
|
||||||
|
}
|
||||||
|
idx, entry, err := peeringReadTxn(tx, ws, q)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if idx > maxIdx {
|
||||||
|
maxIdx = idx
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Peers[peerName] = entry
|
||||||
|
}
|
||||||
|
|
||||||
// Strip nils now that they are no longer necessary.
|
// Strip nils now that they are no longer necessary.
|
||||||
for sid, entry := range res.Routers {
|
for sid, entry := range res.Routers {
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/configentry"
|
"github.com/hashicorp/consul/agent/configentry"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/hashicorp/consul/proto/private/pbpeering"
|
||||||
|
"github.com/hashicorp/consul/proto/private/prototest"
|
||||||
"github.com/hashicorp/consul/sdk/testutil"
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2065,6 +2067,53 @@ func TestStore_ReadDiscoveryChainConfigEntries_SubsetSplit(t *testing.T) {
|
||||||
require.Len(t, entrySet.Services, 1)
|
require.Len(t, entrySet.Services, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStore_ReadDiscoveryChainConfigEntries_FetchPeers(t *testing.T) {
|
||||||
|
s := testConfigStateStore(t)
|
||||||
|
|
||||||
|
entries := []structs.ConfigEntry{
|
||||||
|
&structs.ServiceConfigEntry{
|
||||||
|
Kind: structs.ServiceDefaults,
|
||||||
|
Name: "main",
|
||||||
|
Protocol: "http",
|
||||||
|
},
|
||||||
|
&structs.ServiceResolverConfigEntry{
|
||||||
|
Kind: structs.ServiceResolver,
|
||||||
|
Name: "main",
|
||||||
|
Failover: map[string]structs.ServiceResolverFailover{
|
||||||
|
"*": {
|
||||||
|
Targets: []structs.ServiceResolverFailoverTarget{
|
||||||
|
{Peer: "cluster-01"},
|
||||||
|
{Peer: "cluster-02"}, // Non-existant
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
require.NoError(t, s.EnsureConfigEntry(0, entry))
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster01Peering := &pbpeering.Peering{
|
||||||
|
ID: testFooPeerID,
|
||||||
|
Name: "cluster-01",
|
||||||
|
}
|
||||||
|
err := s.PeeringWrite(0, &pbpeering.PeeringWriteRequest{Peering: cluster01Peering})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, entrySet, err := s.readDiscoveryChainConfigEntries(nil, "main", nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Len(t, entrySet.Routers, 0)
|
||||||
|
require.Len(t, entrySet.Splitters, 0)
|
||||||
|
require.Len(t, entrySet.Resolvers, 1)
|
||||||
|
require.Len(t, entrySet.Services, 1)
|
||||||
|
prototest.AssertDeepEqual(t, entrySet.Peers, map[string]*pbpeering.Peering{
|
||||||
|
"cluster-01": cluster01Peering,
|
||||||
|
"cluster-02": nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(rb): add ServiceIntentions tests
|
// TODO(rb): add ServiceIntentions tests
|
||||||
|
|
||||||
func TestStore_ValidateGatewayNamesCannotBeShared(t *testing.T) {
|
func TestStore_ValidateGatewayNamesCannotBeShared(t *testing.T) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/hashicorp/consul/acl"
|
"github.com/hashicorp/consul/acl"
|
||||||
"github.com/hashicorp/consul/agent/cache"
|
"github.com/hashicorp/consul/agent/cache"
|
||||||
"github.com/hashicorp/consul/lib"
|
"github.com/hashicorp/consul/lib"
|
||||||
|
"github.com/hashicorp/consul/lib/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -871,6 +872,26 @@ type ServiceResolverConfigEntry struct {
|
||||||
RaftIndex
|
RaftIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *ServiceResolverConfigEntry) RelatedPeers() []string {
|
||||||
|
peers := make(map[string]struct{})
|
||||||
|
|
||||||
|
if r := e.Redirect; r != nil && r.Peer != "" {
|
||||||
|
peers[r.Peer] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Failover != nil {
|
||||||
|
for _, f := range e.Failover {
|
||||||
|
for _, t := range f.Targets {
|
||||||
|
if t.Peer != "" {
|
||||||
|
peers[t.Peer] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maps.SliceOfKeys(peers)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *ServiceResolverConfigEntry) MarshalJSON() ([]byte, error) {
|
func (e *ServiceResolverConfigEntry) MarshalJSON() ([]byte, error) {
|
||||||
type Alias ServiceResolverConfigEntry
|
type Alias ServiceResolverConfigEntry
|
||||||
exported := &struct {
|
exported := &struct {
|
||||||
|
|
|
@ -190,12 +190,13 @@ type DiscoveryTarget struct {
|
||||||
// chain. It should be treated as a per-compile opaque string.
|
// chain. It should be treated as a per-compile opaque string.
|
||||||
ID string `json:",omitempty"`
|
ID string `json:",omitempty"`
|
||||||
|
|
||||||
Service string `json:",omitempty"`
|
Service string `json:",omitempty"`
|
||||||
ServiceSubset string `json:",omitempty"`
|
ServiceSubset string `json:",omitempty"`
|
||||||
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"`
|
Peer string `json:",omitempty"`
|
||||||
|
Locality *Locality `json:",omitempty"`
|
||||||
|
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty"`
|
MeshGateway MeshGatewayConfig `json:",omitempty"`
|
||||||
Subset ServiceResolverSubset `json:",omitempty"`
|
Subset ServiceResolverSubset `json:",omitempty"`
|
||||||
|
|
|
@ -125,6 +125,10 @@ func (o *CompiledDiscoveryChain) DeepCopy() *CompiledDiscoveryChain {
|
||||||
if v2 != nil {
|
if v2 != nil {
|
||||||
cp_Targets_v2 = new(DiscoveryTarget)
|
cp_Targets_v2 = new(DiscoveryTarget)
|
||||||
*cp_Targets_v2 = *v2
|
*cp_Targets_v2 = *v2
|
||||||
|
if v2.Locality != nil {
|
||||||
|
cp_Targets_v2.Locality = new(Locality)
|
||||||
|
*cp_Targets_v2.Locality = *v2.Locality
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cp.Targets[k2] = cp_Targets_v2
|
cp.Targets[k2] = cp_Targets_v2
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue