Update assumptions around exported-service config

Given that the exported-services config entry can use wildcards, the
precedence for wildcards is handled as with intentions. The most exact
match is the match that applies for any given service. We do not take
the union of all that apply.

Another update that was made was to reflect that only one
exported-services config entry applies to any given service in a
partition. This is a pre-existing constraint that gets enforced by
the Normalize() method on that config entry type.
This commit is contained in:
freddygv 2022-05-23 10:16:39 -06:00
parent 74ca6406ea
commit 8b58fa8afe
6 changed files with 240 additions and 279 deletions

View File

@ -603,6 +603,10 @@ func validateProposedConfigEntryInServiceGraph(
wildcardEntMeta := kindName.WithWildcardNamespace()
switch kindName.Kind {
case structs.ExportedServices, structs.MeshConfig:
// Exported services and mesh config do not influence discovery chains.
return nil
case structs.ProxyDefaults:
// Check anything that has a discovery chain entry. In the future we could
// somehow omit the ones that have a default protocol configured.
@ -1414,52 +1418,6 @@ func configEntryWithOverridesTxn(
return configEntryTxn(tx, ws, kind, name, entMeta)
}
// getExportedServicesConfigEntriesTxn fetches exported-service config entries and
// filters their exported services to only those that match serviceName and entMeta.
// Because the resulting config entries may have had their exported services modified,
// they *should not* be used in subsequent writes.
func getExportedServiceConfigEntriesTxn(
tx ReadTxn,
ws memdb.WatchSet,
serviceName string,
entMeta *acl.EnterpriseMeta,
) (uint64, []*structs.ExportedServicesConfigEntry, error) {
var exportedServicesEntries []*structs.ExportedServicesConfigEntry
// slice of names to match config entries against
matchCandidates := getExportedServicesMatchServiceNames(serviceName, entMeta)
// matcher func generator for currying the matcher func over EnterpriseMeta values
// from the associated config entry
matchFunc := func(matchMeta *acl.EnterpriseMeta) func(structs.ExportedService) bool {
return func(exportedService structs.ExportedService) bool {
matchSvcName := structs.NewServiceName(exportedService.Name, matchMeta)
for _, candidate := range matchCandidates {
if candidate.Matches(matchSvcName) {
return true
}
}
return false
}
}
idx, entries, err := configEntriesByKindTxn(tx, ws, structs.ExportedServices, entMeta)
if err != nil {
return 0, nil, err
}
for _, entry := range entries {
esEntry, ok := entry.(*structs.ExportedServicesConfigEntry)
if !ok {
return 0, nil, fmt.Errorf("type %T is not a %s config entry", esEntry, structs.ExportedServices)
}
// get a copy of the config entry with Services filtered to match serviceName
newEntry := filterExportedServices(esEntry, matchFunc(entry.GetEnterpriseMeta()))
// the filter will return a new entry, so checking to see if its services is empty says that there
// were matches and that we should include it in the results
if len(newEntry.Services) > 0 {
exportedServicesEntries = append(exportedServicesEntries, newEntry)
}
}
return idx, exportedServicesEntries, nil
}
// protocolForService returns the service graph protocol associated to the
// provided service, checking all relevant config entries.
func protocolForService(
@ -1502,23 +1460,6 @@ func protocolForService(
return maxIdx, chain.Protocol, nil
}
// filterExportedServices returns the slice of ExportedService that matc ffor matching service names
// returning a copy of entry with only the services that match one of the
// services in candidates.
func filterExportedServices(
entry *structs.ExportedServicesConfigEntry,
testFunc func(structs.ExportedService) bool,
) *structs.ExportedServicesConfigEntry {
newEntry := *entry
newEntry.Services = []structs.ExportedService{}
for _, ceSvc := range entry.Services {
if testFunc(ceSvc) {
newEntry.Services = append(newEntry.Services, ceSvc)
}
}
return &newEntry
}
func newConfigEntryQuery(c structs.ConfigEntry) configentry.KindName {
return configentry.NewKindName(c.GetKind(), c.GetName(), c.GetEnterpriseMeta())
}

View File

@ -40,120 +40,124 @@ func testIndexerTableConfigEntries() map[string]indexerTestCase {
}
}
func TestStore_ExportedServices(t *testing.T) {
func TestStore_peersForService(t *testing.T) {
queryName := "foo"
type testCase struct {
name string
write []structs.ConfigEntry
query string
expect []*structs.ExportedServicesConfigEntry
write structs.ConfigEntry
expect []string
}
cases := []testCase{
{
name: "empty everything",
write: []structs.ConfigEntry{},
query: "foo",
expect: []*structs.ExportedServicesConfigEntry{},
expect: nil,
},
{
name: "no matching exported services",
write: []structs.ConfigEntry{
&structs.ProxyConfigEntry{Name: "foo"},
&structs.ProxyConfigEntry{Name: "bar"},
&structs.ExportedServicesConfigEntry{
Name: "baz",
Services: []structs.ExportedService{
{Name: "baz"},
name: "service is not exported",
write: &structs.ExportedServicesConfigEntry{
Name: "default",
Services: []structs.ExportedService{
{
Name: "not-" + queryName,
Consumers: []structs.ServiceConsumer{
{
PeerName: "zip",
},
},
},
},
},
query: "foo",
expect: []*structs.ExportedServicesConfigEntry{},
expect: nil,
},
{
name: "exact match service name",
write: []structs.ConfigEntry{
&structs.ExportedServicesConfigEntry{
Name: "foo",
Services: []structs.ExportedService{
{Name: "foo"},
name: "wildcard name matches",
write: &structs.ExportedServicesConfigEntry{
Name: "default",
Services: []structs.ExportedService{
{
Name: "not-" + queryName,
Consumers: []structs.ServiceConsumer{
{
PeerName: "zip",
},
},
},
},
&structs.ExportedServicesConfigEntry{
Name: "bar",
Services: []structs.ExportedService{
{Name: "bar"},
},
},
},
query: "bar",
expect: []*structs.ExportedServicesConfigEntry{
{
Name: "bar",
Services: []structs.ExportedService{
{Name: "bar"},
{
Name: structs.WildcardSpecifier,
Consumers: []structs.ServiceConsumer{
{
PeerName: "bar",
},
{
PeerName: "baz",
},
},
},
},
},
expect: []string{"bar", "baz"},
},
{
name: "wildcard match on service name",
write: []structs.ConfigEntry{
&structs.ExportedServicesConfigEntry{
Name: "foo",
Services: []structs.ExportedService{
{Name: "foo"},
name: "exact name takes precedence over wildcard",
write: &structs.ExportedServicesConfigEntry{
Name: "default",
Services: []structs.ExportedService{
{
Name: queryName,
Consumers: []structs.ServiceConsumer{
{
PeerName: "baz",
},
},
},
},
&structs.ExportedServicesConfigEntry{
Name: "wildcard",
Services: []structs.ExportedService{
{Name: structs.WildcardSpecifier},
},
},
},
query: "foo",
expect: []*structs.ExportedServicesConfigEntry{
{
Name: "foo",
Services: []structs.ExportedService{
{Name: "foo"},
},
},
{
Name: "wildcard",
Services: []structs.ExportedService{
{Name: structs.WildcardSpecifier},
{
Name: structs.WildcardSpecifier,
Consumers: []structs.ServiceConsumer{
{
PeerName: "zip",
},
},
},
},
},
expect: []string{"baz"},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
s := testStateStore(t)
var lastIdx uint64
// Write the entries.
for idx, entry := range tc.write {
require.NoError(t, s.EnsureConfigEntry(uint64(idx+1), entry))
// Write the entry.
if tc.write != nil {
require.NoError(t, tc.write.Normalize())
require.NoError(t, tc.write.Validate())
lastIdx++
require.NoError(t, s.EnsureConfigEntry(lastIdx, tc.write))
}
// Read the entries back.
tx := s.db.ReadTxn()
defer tx.Abort()
idx, entries, err := getExportedServiceConfigEntriesTxn(tx, nil, tc.query, acl.DefaultEnterpriseMeta())
idx, peers, err := peersForServiceTxn(tx, nil, queryName, acl.DefaultEnterpriseMeta())
require.NoError(t, err)
require.Equal(t, uint64(len(tc.write)), idx)
// This is a little weird, but when there are no results, the index returned should be the max index for the
// config entries table so that the caller can watch for changes to it
if len(peers) == 0 {
require.Equal(t, maxIndexTxn(tx, tableConfigEntries), idx)
} else {
require.Equal(t, lastIdx, idx)
}
// Verify the result.
require.Len(t, entries, len(tc.expect))
for idx, got := range entries {
// ignore raft fields
got.ModifyIndex = 0
got.CreateIndex = 0
require.Equal(t, tc.expect[idx], got)
}
require.Len(t, peers, len(tc.expect))
require.Equal(t, tc.expect, peers)
})
}
}

View File

@ -439,35 +439,37 @@ func (s *Store) exportedServicesForPeerTxn(ws memdb.WatchSet, tx ReadTxn, peerin
// PeeringsForService returns the list of peerings that are associated with the service name provided in the query.
// This is used to configure connect proxies for a given service. The result is generated by querying for exported
// service config entries and filtering for those that match the given service.
//
// TODO(peering): this implementation does all of the work on read to materialize this list of peerings, we should explore
// writing to a separate index that has service peerings prepared ahead of time should this become a performance bottleneck.
func (s *Store) PeeringsForService(ws memdb.WatchSet, serviceName string, entMeta acl.EnterpriseMeta) (uint64, []*pbpeering.Peering, error) {
tx := s.db.ReadTxn()
defer tx.Abort()
// short-circuit if the service does not exist in the context of the query -- this prevents "leaking" services
// Short-circuit if the service does not exist in the context of the query -- this prevents "leaking" services
// when there are wildcard rules in place.
if svcIdx, svcExists, err := serviceExists(tx, ws, serviceName, &entMeta, ""); err != nil {
return 0, nil, fmt.Errorf("failed to check if service exists: %w", err)
} else if !svcExists {
// if the service does not exist, return the max index for the services table so caller can watch for changes
// If the service does not exist, return the max index for the services table so caller can watch for changes.
return svcIdx, nil, nil
}
// config entries must be defined in the default namespace, so we only need the partition here
meta := structs.DefaultEnterpriseMetaInPartition(entMeta.PartitionOrDefault())
// return the idx of the config entry that was last modified so caller can watch for changes
idx, peeredServices, err := readPeeredServicesFromConfigEntriesTxn(tx, ws, serviceName, meta)
// Return the idx of the config entry so the caller can watch for changes.
idx, peerNames, err := peersForServiceTxn(tx, ws, serviceName, &entMeta)
if err != nil {
return 0, nil, fmt.Errorf("failed to read peered services for service name: %w", err)
return 0, nil, fmt.Errorf("failed to read peers for service name %q: %w", serviceName, err)
}
var peerings []*pbpeering.Peering
// lookup the peering for each matching peered service
for _, peeredService := range peeredServices {
// Lookup and return the peering corresponding to each name.
for _, name := range peerNames {
readQuery := Query{
Value: peeredService.PeerName,
EnterpriseMeta: peeredService.Name.EnterpriseMeta,
Value: name,
EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(entMeta.PartitionOrDefault()),
}
_, peering, err := peeringReadTxn(tx, ws, readQuery)
if err != nil {
@ -478,7 +480,6 @@ func (s *Store) PeeringsForService(ws memdb.WatchSet, serviceName string, entMet
}
peerings = append(peerings, peering)
}
// see note above about idx
return idx, peerings, nil
}
@ -597,50 +598,80 @@ func (r *Restore) PeeringTrustBundle(ptb *pbpeering.PeeringTrustBundle) error {
return nil
}
// readPeeredServicesFromConfigEntriesTxn queries exported-service config entries to return peers for serviceName
// in the form of a []structs.PeeredService.
func readPeeredServicesFromConfigEntriesTxn(
// peersForServiceTxn returns the names of all peers that a service is exported to.
func peersForServiceTxn(
tx ReadTxn,
ws memdb.WatchSet,
serviceName string,
entMeta *acl.EnterpriseMeta,
) (uint64, []structs.PeeredService, error) {
var results []structs.PeeredService
) (uint64, []string, error) {
// Exported service config entries are scoped to partitions so they are in the default namespace.
partitionMeta := structs.DefaultEnterpriseMetaInPartition(entMeta.PartitionOrDefault())
// Get all exported-service config entries for that have exports for serviceName. This assumes the result
// has exported services filtered to only those matching serviceName so no futher filtering is needed.
idx, exportedServicesEntries, err := getExportedServiceConfigEntriesTxn(tx, ws, serviceName, entMeta)
idx, rawEntry, err := configEntryTxn(tx, ws, structs.ExportedServices, partitionMeta.PartitionOrDefault(), partitionMeta)
if err != nil {
return 0, nil, err
}
if rawEntry == nil {
return idx, nil, err
}
// dedupe results by peer name
resultSet := make(map[string]struct{})
// filter entries to only those that have a peer consumer defined
for _, entry := range exportedServicesEntries {
for _, service := range entry.Services {
// entries must have consumers
if service.Consumers == nil || len(service.Consumers) == 0 {
continue
}
for _, consumer := range service.Consumers {
// and consumers must have a peer
if consumer.PeerName == "" {
continue
}
// if we get here, we have a peer consumer, but we should dedupe peer names, so skip if it's already in the set
if _, ok := resultSet[consumer.PeerName]; ok {
continue
}
entry, ok := rawEntry.(*structs.ExportedServicesConfigEntry)
if !ok {
return 0, nil, fmt.Errorf("unexpected type %T for pbpeering.Peering index", rawEntry)
}
// if we got here, we can add to the result set
resultSet[consumer.PeerName] = struct{}{}
result := structs.PeeredService{
Name: structs.NewServiceName(serviceName, entry.GetEnterpriseMeta()),
PeerName: consumer.PeerName,
}
results = append(results, result)
}
var (
wildcardNamespaceIdx = -1
wildcardServiceIdx = -1
exactMatchIdx = -1
)
// Ensure the metadata is defaulted since we make assertions against potentially empty values below.
// In OSS this is a no-op.
if entMeta == nil {
entMeta = acl.DefaultEnterpriseMeta()
}
entMeta.Normalize()
// Services can be exported via wildcards or by their exact name:
// Namespace: *, Service: *
// Namespace: Exact, Service: *
// Namespace: Exact, Service: Exact
for i, service := range entry.Services {
switch {
case service.Namespace == structs.WildcardSpecifier:
wildcardNamespaceIdx = i
case service.Name == structs.WildcardSpecifier && service.Namespace == entMeta.NamespaceOrEmpty():
wildcardServiceIdx = i
case service.Name == serviceName && service.Namespace == entMeta.NamespaceOrEmpty():
exactMatchIdx = i
}
}
var results []string
// Prefer the exact match over the wildcard match. This matches how we handle intention precedence.
var targetIdx int
switch {
case exactMatchIdx >= 0:
targetIdx = exactMatchIdx
case wildcardServiceIdx >= 0:
targetIdx = wildcardServiceIdx
case wildcardNamespaceIdx >= 0:
targetIdx = wildcardNamespaceIdx
default:
return idx, results, nil
}
for _, c := range entry.Services[targetIdx].Consumers {
if c.PeerName != "" {
results = append(results, c.PeerName)
}
}
return idx, results, nil

View File

@ -907,7 +907,7 @@ func TestStateStore_PeeringsForService(t *testing.T) {
name string
services []structs.ServiceName
peerings []*pbpeering.Peering
entries []*structs.ExportedServicesConfigEntry
entry *structs.ExportedServicesConfigEntry
query []string
expect [][]*pbpeering.Peering
expectIdx uint64
@ -945,9 +945,10 @@ func TestStateStore_PeeringsForService(t *testing.T) {
}
// Write the config entries.
for _, entry := range tc.entries {
if tc.entry != nil {
lastIdx++
require.NoError(t, s.EnsureConfigEntry(lastIdx, entry))
require.NoError(t, tc.entry.Normalize())
require.NoError(t, s.EnsureConfigEntry(lastIdx, tc.entry))
}
// Query for peers.
@ -976,7 +977,7 @@ func TestStateStore_PeeringsForService(t *testing.T) {
{Name: "foo"},
},
peerings: []*pbpeering.Peering{},
entries: []*structs.ExportedServicesConfigEntry{},
entry: nil,
query: []string{"foo"},
expect: [][]*pbpeering.Peering{{}},
},
@ -986,7 +987,7 @@ func TestStateStore_PeeringsForService(t *testing.T) {
{Name: "foo"},
},
peerings: []*pbpeering.Peering{},
entries: []*structs.ExportedServicesConfigEntry{},
entry: nil,
query: []string{"bar"},
expect: [][]*pbpeering.Peering{{}},
expectIdx: uint64(2), // catalog services max index
@ -1001,24 +1002,22 @@ func TestStateStore_PeeringsForService(t *testing.T) {
{Name: "peer1", State: pbpeering.PeeringState_INITIAL},
{Name: "peer2", State: pbpeering.PeeringState_INITIAL},
},
entries: []*structs.ExportedServicesConfigEntry{
{
Name: "ce1",
Services: []structs.ExportedService{
{
Name: "foo",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer1",
},
entry: &structs.ExportedServicesConfigEntry{
Name: "default",
Services: []structs.ExportedService{
{
Name: "foo",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer1",
},
},
{
Name: "bar",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer2",
},
},
{
Name: "bar",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer2",
},
},
},
@ -1046,27 +1045,25 @@ func TestStateStore_PeeringsForService(t *testing.T) {
{Name: "peer2", State: pbpeering.PeeringState_INITIAL},
{Name: "peer3", State: pbpeering.PeeringState_INITIAL},
},
entries: []*structs.ExportedServicesConfigEntry{
{
Name: "ce1",
Services: []structs.ExportedService{
{
Name: "*",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer1",
},
{
PeerName: "peer2",
},
entry: &structs.ExportedServicesConfigEntry{
Name: "default",
Services: []structs.ExportedService{
{
Name: "*",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer1",
},
{
PeerName: "peer2",
},
},
{
Name: "bar",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer3",
},
},
{
Name: "bar",
Consumers: []structs.ServiceConsumer{
{
PeerName: "peer3",
},
},
},
@ -1079,8 +1076,6 @@ func TestStateStore_PeeringsForService(t *testing.T) {
{Name: "peer2", State: pbpeering.PeeringState_INITIAL},
},
{
{Name: "peer1", State: pbpeering.PeeringState_INITIAL},
{Name: "peer2", State: pbpeering.PeeringState_INITIAL},
{Name: "peer3", State: pbpeering.PeeringState_INITIAL},
},
},

View File

@ -359,24 +359,22 @@ func TestPeeringService_TrustBundleRead(t *testing.T) {
}
func TestPeeringService_TrustBundleListByService(t *testing.T) {
// test executes the following scenario:
// 0 - initial setup test server, state store, RPC client, verify empty results
// 1 - create a service, verify results still empty
// 2 - create a peering, verify results still empty
// 3 - create a config entry, verify results still empty
// 4 - create trust bundles, verify bundles are returned
// 5 - delete the config entry, verify results empty
// 6 - restore config entry, verify bundles are returned
// 7 - add peering, trust bundles, wildcard config entry, verify updated results are present
// 8 - delete first config entry, verify bundles are returned
// 9 - delete the service, verify results empty
// Test executes the following scenario:
// 0 - Initial setup test server, state store, RPC client, verify empty results
// 1 - Create a service, verify results still empty
// 2 - Create a peering, verify results still empty
// 3 - Create a config entry, verify results still empty
// 4 - Create trust bundles, verify bundles are returned
// 5 - Delete the config entry, verify results empty
// 6 - Restore config entry, verify bundles are returned
// 7 - Add a second peering that the test service is not exported to
// 8 - Export the service to the new peering
// 9 - Delete the service
// Note: these steps are dependent on each other by design so that we can verify that
// combinations of services, peerings, trust bundles, and config entries all affect results
// fixed for the test
nodeName := "test-node"
// keep track of index across steps
var lastIdx uint64
// Create test server
@ -445,6 +443,7 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
// Write any config entries
for _, entry := range deps.entries {
idx++
require.NoError(t, entry.Normalize())
require.NoError(t, store.EnsureConfigEntry(idx, entry))
}
@ -460,6 +459,8 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
// TODO(peering): see note on newTestServer, once we have a better server mock,
// we should add functionality here to verify errors from backend
verify := func(t *testing.T, tc *testCase) {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
@ -478,7 +479,7 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
// Execute scenario steps
// ----------------------
// 0 - initial empty state
// 0 - Initial empty state.
// -----------------------
verify(t, &testCase{
req: &pbpeering.TrustBundleListByServiceRequest{
@ -489,7 +490,7 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
},
})
// 1 - create a service, verify results still empty
// 1 - Create a service, verify results still empty.
// ------------------------------------------------
lastIdx = setup(t, lastIdx, testDeps{services: []string{"foo"}})
verify(t, &testCase{
@ -501,7 +502,7 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
},
})
// 2 - create a peering, verify results still empty
// 2 - Create a peering, verify results still empty.
// ------------------------------------------------
lastIdx = setup(t, lastIdx, testDeps{
peerings: []*pbpeering.Peering{
@ -522,12 +523,12 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
},
})
// 3 - create a config entry, verify results still empty
// 3 - Create a config entry, verify results still empty.
// -----------------------------------------------------
lastIdx = setup(t, lastIdx, testDeps{
entries: []*structs.ExportedServicesConfigEntry{
{
Name: "export-foo",
Name: "default",
Services: []structs.ExportedService{
{
Name: "foo",
@ -550,7 +551,7 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
},
})
// 4 - create trust bundles, verify bundles are returned
// 4 - Create trust bundles, verify bundles are returned.
// -----------------------------------------------------
lastIdx = setup(t, lastIdx, testDeps{
bundles: []*pbpeering.PeeringTrustBundle{
@ -576,10 +577,10 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
},
})
// 5 - delete the config entry, verify results empty
// 5 - Delete the config entry, verify results empty.
// -------------------------------------------------
lastIdx++
require.NoError(t, store.DeleteConfigEntry(lastIdx, structs.ExportedServices, "export-foo", nil))
require.NoError(t, store.DeleteConfigEntry(lastIdx, structs.ExportedServices, "default", nil))
verify(t, &testCase{
req: &pbpeering.TrustBundleListByServiceRequest{
ServiceName: "foo",
@ -589,12 +590,12 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
},
})
// 6 - restore config entry, verify bundles are returned
// 6 - Restore config entry, verify bundles are returned.
// -----------------------------------------------------
lastIdx = setup(t, lastIdx, testDeps{
entries: []*structs.ExportedServicesConfigEntry{
{
Name: "export-foo",
Name: "default",
Services: []structs.ExportedService{
{
Name: "foo",
@ -621,10 +622,9 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
},
})
// 7 - add peering, trust bundles, wildcard config entry, verify updated results are present
// 7 - Add new peer and trust bundle. It should be ignored because foo is not exported to it.
// -----------------------------------------------------------------------------------------
lastIdx = setup(t, lastIdx, testDeps{
services: []string{"bar"},
peerings: []*pbpeering.Peering{
{
Name: "peer2",
@ -633,20 +633,6 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
PeerServerAddresses: []string{"peer2-addr"},
},
},
entries: []*structs.ExportedServicesConfigEntry{
{
Name: "export-all",
Services: []structs.ExportedService{
{
Name: structs.WildcardSpecifier,
Consumers: []structs.ServiceConsumer{
{PeerName: "peer1"},
{PeerName: "peer2"},
},
},
},
},
},
bundles: []*pbpeering.PeeringTrustBundle{
{
TrustDomain: "peer2.com",
@ -666,18 +652,28 @@ func TestPeeringService_TrustBundleListByService(t *testing.T) {
PeerName: "peer1",
RootPEMs: []string{"peer1-root-1"},
},
{
TrustDomain: "peer2.com",
PeerName: "peer2",
RootPEMs: []string{"peer2-root-1"},
},
},
},
})
// 8 - delete first config entry, verify bundles are returned
lastIdx++
require.NoError(t, store.DeleteConfigEntry(lastIdx, structs.ExportedServices, "export-foo", nil))
// 8 - Replace config entry to export all services to both peers
// -----------------------------------------------------------------------------------------
lastIdx = setup(t, lastIdx, testDeps{
entries: []*structs.ExportedServicesConfigEntry{
{
Name: "default",
Services: []structs.ExportedService{
{
Name: structs.WildcardSpecifier,
Consumers: []structs.ServiceConsumer{
{PeerName: "peer1"},
{PeerName: "peer2"},
},
},
},
},
},
})
verify(t, &testCase{
req: &pbpeering.TrustBundleListByServiceRequest{
ServiceName: "foo",

View File

@ -8,12 +8,6 @@ type PeeringToken struct {
PeerID string
}
// PeeredService is a service that has been configured with an exported-service config entry to be exported to a peer.
type PeeredService struct {
Name ServiceName
PeerName string
}
// NOTE: this is not serialized via msgpack so it can be changed without concern.
type ExportedServiceList struct {
// Services is a list of exported services that apply to both standard