add sameness group support to service resolver failover and redirects (#16664)
This commit is contained in:
parent
64f5e20793
commit
68046060ea
|
@ -10,22 +10,24 @@ import (
|
|||
//
|
||||
// None of these are defaulted.
|
||||
type DiscoveryChainSet struct {
|
||||
Routers map[structs.ServiceID]*structs.ServiceRouterConfigEntry
|
||||
Splitters map[structs.ServiceID]*structs.ServiceSplitterConfigEntry
|
||||
Resolvers map[structs.ServiceID]*structs.ServiceResolverConfigEntry
|
||||
Services map[structs.ServiceID]*structs.ServiceConfigEntry
|
||||
Peers map[string]*pbpeering.Peering
|
||||
ProxyDefaults map[string]*structs.ProxyConfigEntry
|
||||
Routers map[structs.ServiceID]*structs.ServiceRouterConfigEntry
|
||||
Splitters map[structs.ServiceID]*structs.ServiceSplitterConfigEntry
|
||||
Resolvers map[structs.ServiceID]*structs.ServiceResolverConfigEntry
|
||||
Services map[structs.ServiceID]*structs.ServiceConfigEntry
|
||||
Peers map[string]*pbpeering.Peering
|
||||
SamenessGroups map[string]*structs.SamenessGroupConfigEntry
|
||||
ProxyDefaults map[string]*structs.ProxyConfigEntry
|
||||
}
|
||||
|
||||
func NewDiscoveryChainSet() *DiscoveryChainSet {
|
||||
return &DiscoveryChainSet{
|
||||
Routers: make(map[structs.ServiceID]*structs.ServiceRouterConfigEntry),
|
||||
Splitters: make(map[structs.ServiceID]*structs.ServiceSplitterConfigEntry),
|
||||
Resolvers: make(map[structs.ServiceID]*structs.ServiceResolverConfigEntry),
|
||||
Services: make(map[structs.ServiceID]*structs.ServiceConfigEntry),
|
||||
Peers: make(map[string]*pbpeering.Peering),
|
||||
ProxyDefaults: make(map[string]*structs.ProxyConfigEntry),
|
||||
Routers: make(map[structs.ServiceID]*structs.ServiceRouterConfigEntry),
|
||||
Splitters: make(map[structs.ServiceID]*structs.ServiceSplitterConfigEntry),
|
||||
Resolvers: make(map[structs.ServiceID]*structs.ServiceResolverConfigEntry),
|
||||
Services: make(map[structs.ServiceID]*structs.ServiceConfigEntry),
|
||||
Peers: make(map[string]*pbpeering.Peering),
|
||||
ProxyDefaults: make(map[string]*structs.ProxyConfigEntry),
|
||||
SamenessGroups: make(map[string]*structs.SamenessGroupConfigEntry),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1297,10 +1297,11 @@ func readDiscoveryChainConfigEntriesTxn(
|
|||
// the end of this function to indicate "no such entry".
|
||||
|
||||
var (
|
||||
todoSplitters = make(map[structs.ServiceID]struct{})
|
||||
todoResolvers = make(map[structs.ServiceID]struct{})
|
||||
todoDefaults = make(map[structs.ServiceID]struct{})
|
||||
todoPeers = make(map[string]struct{})
|
||||
todoSplitters = make(map[structs.ServiceID]struct{})
|
||||
todoResolvers = make(map[structs.ServiceID]struct{})
|
||||
todoDefaults = make(map[structs.ServiceID]struct{})
|
||||
todoPeers = make(map[string]struct{})
|
||||
todoSamenessGroups = make(map[string]struct{})
|
||||
)
|
||||
|
||||
sid := structs.NewServiceID(serviceName, entMeta)
|
||||
|
@ -1406,6 +1407,10 @@ func readDiscoveryChainConfigEntriesTxn(
|
|||
for _, peer := range resolver.RelatedPeers() {
|
||||
todoPeers[peer] = struct{}{}
|
||||
}
|
||||
|
||||
for _, peer := range resolver.RelatedSamenessGroups() {
|
||||
todoSamenessGroups[peer] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
|
@ -1448,6 +1453,26 @@ func readDiscoveryChainConfigEntriesTxn(
|
|||
}
|
||||
|
||||
peerEntMeta := structs.DefaultEnterpriseMetaInPartition(entMeta.PartitionOrDefault())
|
||||
for sg := range todoSamenessGroups {
|
||||
idx, entry, err := getSamenessGroupConfigEntryTxn(tx, ws, sg, overrides, peerEntMeta)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if idx > maxIdx {
|
||||
maxIdx = idx
|
||||
}
|
||||
if entry == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, e := range entry.Members {
|
||||
if e.Peer != "" {
|
||||
todoPeers[e.Peer] = struct{}{}
|
||||
}
|
||||
}
|
||||
res.SamenessGroups[sg] = entry
|
||||
}
|
||||
|
||||
for peerName := range todoPeers {
|
||||
q := Query{
|
||||
Value: peerName,
|
||||
|
|
|
@ -6,6 +6,8 @@ package state
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/configentry"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
)
|
||||
|
@ -27,3 +29,19 @@ func (*SamenessGroupDefaultIndex) FromArgs(args ...interface{}) ([]byte, error)
|
|||
func checkSamenessGroup(tx ReadTxn, newConfig structs.ConfigEntry) error {
|
||||
return fmt.Errorf("sameness-groups are an enterprise-only feature")
|
||||
}
|
||||
|
||||
// getExportedServicesConfigEntryTxn is a convenience method for fetching a
|
||||
// sameness-group config entries.
|
||||
//
|
||||
// If an override KEY is present for the requested config entry, the index
|
||||
// returned will be 0. Any override VALUE (nil or otherwise) will be returned
|
||||
// if there is a KEY match.
|
||||
func getSamenessGroupConfigEntryTxn(
|
||||
tx ReadTxn,
|
||||
ws memdb.WatchSet,
|
||||
name string,
|
||||
overrides map[configentry.KindName]structs.ConfigEntry,
|
||||
entMeta *acl.EnterpriseMeta,
|
||||
) (uint64, *structs.SamenessGroupConfigEntry, error) {
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
|
|
@ -1053,6 +1053,12 @@ func (e *ServiceResolverConfigEntry) Validate() error {
|
|||
}
|
||||
|
||||
switch {
|
||||
case r.SamenessGroup != "" && r.ServiceSubset != "":
|
||||
return fmt.Errorf("Redirect.SamenessGroup cannot be set with Redirect.ServiceSubset")
|
||||
case r.SamenessGroup != "" && r.Partition != "":
|
||||
return fmt.Errorf("Redirect.Partition cannot be set with Redirect.SamenessGroup")
|
||||
case r.SamenessGroup != "" && r.Datacenter != "":
|
||||
return fmt.Errorf("Redirect.SamenessGroup cannot be set with Redirect.Datacenter")
|
||||
case r.Peer != "" && r.ServiceSubset != "":
|
||||
return fmt.Errorf("Redirect.Peer cannot be set with Redirect.ServiceSubset")
|
||||
case r.Peer != "" && r.Partition != "":
|
||||
|
@ -1116,6 +1122,17 @@ func (e *ServiceResolverConfigEntry) Validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
if f.SamenessGroup != "" {
|
||||
switch {
|
||||
case len(f.Datacenters) > 0:
|
||||
return fmt.Errorf("Bad Failover[%q]: SamenessGroup cannot be set with Datacenters", subset)
|
||||
case f.ServiceSubset != "":
|
||||
return fmt.Errorf("Bad Failover[%q]: SamenessGroup cannot be set with ServiceSubset", subset)
|
||||
case len(f.Targets) > 0:
|
||||
return fmt.Errorf("Bad Failover[%q]: SamenessGroup cannot be set with Targets", subset)
|
||||
}
|
||||
}
|
||||
|
||||
if len(f.Datacenters) != 0 && len(f.Targets) != 0 {
|
||||
return fmt.Errorf("Bad Failover[%q]: Targets cannot be set with Datacenters", subset)
|
||||
}
|
||||
|
@ -1341,6 +1358,10 @@ type ServiceResolverRedirect struct {
|
|||
// Peer is the name of the cluster peer to resolve the service from instead
|
||||
// of the current one (optional).
|
||||
Peer string `json:",omitempty"`
|
||||
|
||||
// SamenessGroup is the name of the sameness group to resolve the service from instead
|
||||
// of the local partition.
|
||||
SamenessGroup string `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (r *ServiceResolverRedirect) ToDiscoveryTargetOpts() DiscoveryTargetOpts {
|
||||
|
@ -1355,7 +1376,13 @@ func (r *ServiceResolverRedirect) ToDiscoveryTargetOpts() DiscoveryTargetOpts {
|
|||
}
|
||||
|
||||
func (r *ServiceResolverRedirect) isEmpty() bool {
|
||||
return r.Service == "" && r.ServiceSubset == "" && r.Namespace == "" && r.Partition == "" && r.Datacenter == "" && r.Peer == ""
|
||||
return r.Service == "" &&
|
||||
r.ServiceSubset == "" &&
|
||||
r.Namespace == "" &&
|
||||
r.Partition == "" &&
|
||||
r.Datacenter == "" &&
|
||||
r.Peer == "" &&
|
||||
r.SamenessGroup == ""
|
||||
}
|
||||
|
||||
// There are some restrictions on what is allowed in here:
|
||||
|
@ -1400,6 +1427,9 @@ type ServiceResolverFailover struct {
|
|||
|
||||
// Policy specifies the exact mechanism used for failover.
|
||||
Policy *ServiceResolverFailoverPolicy `json:",omitempty"`
|
||||
|
||||
// SamenessGroup specifies the sameness group to failover to.
|
||||
SamenessGroup string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ServiceResolverFailoverPolicy struct {
|
||||
|
|
|
@ -38,6 +38,10 @@ func (redir *ServiceResolverRedirect) ValidateEnterprise() error {
|
|||
return fmt.Errorf("Setting Namespace requires Consul Enterprise")
|
||||
}
|
||||
|
||||
if redir.SamenessGroup != "" {
|
||||
return fmt.Errorf("Setting SamenessGroup requires Consul Enterprise")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -54,6 +58,10 @@ func (failover *ServiceResolverFailover) ValidateEnterprise() error {
|
|||
return fmt.Errorf("Setting Namespace requires Consul Enterprise")
|
||||
}
|
||||
|
||||
if failover.SamenessGroup != "" {
|
||||
return fmt.Errorf("Setting SamenessGroup requires Consul Enterprise")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -102,3 +110,8 @@ func (f *ServiceResolverFailoverPolicy) ValidateEnterprise() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RelatedSamenessGroups doesn't return anything on open source.
|
||||
func (e *ServiceResolverConfigEntry) RelatedSamenessGroups() []string {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -21,6 +21,19 @@ func TestServiceResolverConfigEntry_OSS(t *testing.T) {
|
|||
}
|
||||
|
||||
cases := []testcase{
|
||||
{
|
||||
name: "failover with a sameness group on OSS",
|
||||
entry: &ServiceResolverConfigEntry{
|
||||
Kind: ServiceResolver,
|
||||
Name: "test",
|
||||
Failover: map[string]ServiceResolverFailover{
|
||||
"*": {
|
||||
SamenessGroup: "ns1",
|
||||
},
|
||||
},
|
||||
},
|
||||
validateErr: `Bad Failover["*"]: Setting SamenessGroup requires Consul Enterprise`,
|
||||
},
|
||||
{
|
||||
name: "failover with a namespace on OSS",
|
||||
entry: &ServiceResolverConfigEntry{
|
||||
|
@ -83,6 +96,17 @@ func TestServiceResolverConfigEntry_OSS(t *testing.T) {
|
|||
},
|
||||
validateErr: `Bad Failover["*"]: Setting failover policies requires Consul Enterprise`,
|
||||
},
|
||||
{
|
||||
name: "setting redirect SamenessGroup on OSS",
|
||||
entry: &ServiceResolverConfigEntry{
|
||||
Kind: ServiceResolver,
|
||||
Name: "test",
|
||||
Redirect: &ServiceResolverRedirect{
|
||||
SamenessGroup: "group",
|
||||
},
|
||||
},
|
||||
validateErr: `Redirect: Setting SamenessGroup requires Consul Enterprise`,
|
||||
},
|
||||
{
|
||||
name: "setting redirect Namespace on OSS",
|
||||
entry: &ServiceResolverConfigEntry{
|
||||
|
|
|
@ -234,16 +234,18 @@ type ServiceResolverRedirect struct {
|
|||
Partition string `json:",omitempty"`
|
||||
Datacenter string `json:",omitempty"`
|
||||
Peer string `json:",omitempty"`
|
||||
SamenessGroup string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ServiceResolverFailover struct {
|
||||
Service string `json:",omitempty"`
|
||||
ServiceSubset string `json:",omitempty" alias:"service_subset"`
|
||||
// Referencing other partitions is not supported.
|
||||
Namespace string `json:",omitempty"`
|
||||
Datacenters []string `json:",omitempty"`
|
||||
Targets []ServiceResolverFailoverTarget `json:",omitempty"`
|
||||
Policy *ServiceResolverFailoverPolicy `json:",omitempty"`
|
||||
Namespace string `json:",omitempty"`
|
||||
Datacenters []string `json:",omitempty"`
|
||||
Targets []ServiceResolverFailoverTarget `json:",omitempty"`
|
||||
Policy *ServiceResolverFailoverPolicy `json:",omitempty"`
|
||||
SamenessGroup string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ServiceResolverFailoverTarget struct {
|
||||
|
|
|
@ -1415,6 +1415,7 @@ func ServiceResolverFailoverToStructs(s *ServiceResolverFailover, t *structs.Ser
|
|||
ServiceResolverFailoverPolicyToStructs(s.Policy, &x)
|
||||
t.Policy = &x
|
||||
}
|
||||
t.SamenessGroup = s.SamenessGroup
|
||||
}
|
||||
func ServiceResolverFailoverFromStructs(t *structs.ServiceResolverFailover, s *ServiceResolverFailover) {
|
||||
if s == nil {
|
||||
|
@ -1439,6 +1440,7 @@ func ServiceResolverFailoverFromStructs(t *structs.ServiceResolverFailover, s *S
|
|||
ServiceResolverFailoverPolicyFromStructs(t.Policy, &x)
|
||||
s.Policy = &x
|
||||
}
|
||||
s.SamenessGroup = t.SamenessGroup
|
||||
}
|
||||
func ServiceResolverFailoverPolicyToStructs(s *ServiceResolverFailoverPolicy, t *structs.ServiceResolverFailoverPolicy) {
|
||||
if s == nil {
|
||||
|
@ -1484,6 +1486,7 @@ func ServiceResolverRedirectToStructs(s *ServiceResolverRedirect, t *structs.Ser
|
|||
t.Partition = s.Partition
|
||||
t.Datacenter = s.Datacenter
|
||||
t.Peer = s.Peer
|
||||
t.SamenessGroup = s.SamenessGroup
|
||||
}
|
||||
func ServiceResolverRedirectFromStructs(t *structs.ServiceResolverRedirect, s *ServiceResolverRedirect) {
|
||||
if s == nil {
|
||||
|
@ -1495,6 +1498,7 @@ func ServiceResolverRedirectFromStructs(t *structs.ServiceResolverRedirect, s *S
|
|||
s.Partition = t.Partition
|
||||
s.Datacenter = t.Datacenter
|
||||
s.Peer = t.Peer
|
||||
s.SamenessGroup = t.SamenessGroup
|
||||
}
|
||||
func ServiceResolverSubsetToStructs(s *ServiceResolverSubset, t *structs.ServiceResolverSubset) {
|
||||
if s == nil {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -147,6 +147,7 @@ message ServiceResolverRedirect {
|
|||
string Partition = 4;
|
||||
string Datacenter = 5;
|
||||
string Peer = 6;
|
||||
string SamenessGroup = 7;
|
||||
}
|
||||
|
||||
// mog annotation:
|
||||
|
@ -161,6 +162,7 @@ message ServiceResolverFailover {
|
|||
repeated string Datacenters = 4;
|
||||
repeated ServiceResolverFailoverTarget Targets = 5;
|
||||
ServiceResolverFailoverPolicy Policy = 6;
|
||||
string SamenessGroup = 7;
|
||||
}
|
||||
|
||||
// mog annotation:
|
||||
|
|
Loading…
Reference in New Issue