Egress gtw/connect destination intentions (#13341)
* update gateway-services table with endpoints * fix failing test * remove unneeded config in test * rename "endpoint" to "destination" * more endpoint renaming to destination in tests * update isDestination based on service-defaults config entry creation * use a 3 state kind to be able to set the kind to unknown (when neither a service or a destination exist) * set unknown state to empty to avoid modifying alot of tests * fix logic to set the kind correctly on CRUD * fix failing tests * add missing tests and fix service delete * fix failing test * Apply suggestions from code review Co-authored-by: Dan Stough <dan.stough@hashicorp.com> * fix a bug with kind and add relevant test * fix compile error * fix failing tests * add kind to clone * fix failing tests * fix failing tests in catalog endpoint * fix service dump test * Apply suggestions from code review Co-authored-by: Dan Stough <dan.stough@hashicorp.com> * remove duplicate tests * first draft of destinations intention in connect proxy * remove ServiceDestinationList * fix failing tests * fix agent/consul failing tests * change to filter intentions in the state store instead of adding a field. * fix failing tests * fix comment * fix comments * store service kind destination and add relevant tests * changes based on review * filter on destinations when querying source match * Apply suggestions from code review Co-authored-by: alex <8968914+acpana@users.noreply.github.com> * fix style * Apply suggestions from code review Co-authored-by: Dan Stough <dan.stough@hashicorp.com> * rename destinationType to targetType. Co-authored-by: Dan Stough <dan.stough@hashicorp.com> Co-authored-by: alex <8968914+acpana@users.noreply.github.com> Co-authored-by: github-team-consul-core <github-team-consul-core@hashicorp.com>
This commit is contained in:
parent
dcb511e78a
commit
7602b6ebf2
|
@ -764,7 +764,7 @@ func (s *Intention) Check(args *structs.IntentionQueryRequest, reply *structs.In
|
||||||
Partition: query.SourcePartition,
|
Partition: query.SourcePartition,
|
||||||
Name: query.SourceName,
|
Name: query.SourceName,
|
||||||
}
|
}
|
||||||
_, intentions, err := store.IntentionMatchOne(nil, entry, structs.IntentionMatchSource)
|
_, intentions, err := store.IntentionMatchOne(nil, entry, structs.IntentionMatchSource, structs.IntentionTargetService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to query intentions for %s/%s", query.SourceNS, query.SourceName)
|
return fmt.Errorf("failed to query intentions for %s/%s", query.SourceNS, query.SourceName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,7 +405,7 @@ func (m *Internal) GatewayIntentions(args *structs.IntentionQueryRequest, reply
|
||||||
Partition: gs.Service.PartitionOrDefault(),
|
Partition: gs.Service.PartitionOrDefault(),
|
||||||
Name: gs.Service.Name,
|
Name: gs.Service.Name,
|
||||||
}
|
}
|
||||||
idx, intentions, err := state.IntentionMatchOne(ws, entry, structs.IntentionMatchDestination)
|
idx, intentions, err := state.IntentionMatchOne(ws, entry, structs.IntentionMatchDestination, structs.IntentionTargetService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4009,14 +4009,7 @@ func (s *Store) ServiceTopology(
|
||||||
Partition: entMeta.PartitionOrDefault(),
|
Partition: entMeta.PartitionOrDefault(),
|
||||||
Name: service,
|
Name: service,
|
||||||
}
|
}
|
||||||
_, srcIntentions, err := compatIntentionMatchOneTxn(
|
_, srcIntentions, err := compatIntentionMatchOneTxn(tx, ws, matchEntry, structs.IntentionMatchSource, structs.IntentionTargetService)
|
||||||
tx,
|
|
||||||
ws,
|
|
||||||
matchEntry,
|
|
||||||
|
|
||||||
// The given service is a source relative to its upstreams
|
|
||||||
structs.IntentionMatchSource,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String())
|
return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String())
|
||||||
}
|
}
|
||||||
|
@ -4128,14 +4121,7 @@ func (s *Store) ServiceTopology(
|
||||||
downstreamSources[svc.Name.String()] = source
|
downstreamSources[svc.Name.String()] = source
|
||||||
}
|
}
|
||||||
|
|
||||||
_, dstIntentions, err := compatIntentionMatchOneTxn(
|
_, dstIntentions, err := compatIntentionMatchOneTxn(tx, ws, matchEntry, structs.IntentionMatchDestination, structs.IntentionTargetService)
|
||||||
tx,
|
|
||||||
ws,
|
|
||||||
matchEntry,
|
|
||||||
|
|
||||||
// The given service is a destination relative to its downstreams
|
|
||||||
structs.IntentionMatchDestination,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String())
|
return 0, nil, fmt.Errorf("failed to query intentions for %s", sn.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,12 +356,16 @@ func deleteConfigEntryTxn(tx WriteTxn, idx uint64, kind, name string, entMeta *a
|
||||||
if gsKind == structs.GatewayServiceKindDestination {
|
if gsKind == structs.GatewayServiceKindDestination {
|
||||||
gsKind = structs.GatewayServiceKindUnknown
|
gsKind = structs.GatewayServiceKindUnknown
|
||||||
}
|
}
|
||||||
if err := checkGatewayWildcardsAndUpdate(tx, idx, &structs.ServiceName{Name: c.GetName(), EnterpriseMeta: *c.GetEnterpriseMeta()}, gsKind); err != nil {
|
serviceName := structs.NewServiceName(c.GetName(), c.GetEnterpriseMeta())
|
||||||
|
if err := checkGatewayWildcardsAndUpdate(tx, idx, &serviceName, gsKind); err != nil {
|
||||||
return fmt.Errorf("failed updating gateway mapping: %s", err)
|
return fmt.Errorf("failed updating gateway mapping: %s", err)
|
||||||
}
|
}
|
||||||
if err := checkGatewayAndUpdate(tx, idx, &structs.ServiceName{Name: c.GetName(), EnterpriseMeta: *c.GetEnterpriseMeta()}, gsKind); err != nil {
|
if err := checkGatewayAndUpdate(tx, idx, &serviceName, gsKind); err != nil {
|
||||||
return fmt.Errorf("failed updating gateway mapping: %s", err)
|
return fmt.Errorf("failed updating gateway mapping: %s", err)
|
||||||
}
|
}
|
||||||
|
if err := cleanupKindServiceName(tx, idx, serviceName, structs.ServiceKindDestination); err != nil {
|
||||||
|
return fmt.Errorf("failed to cleanup service name: \"%s\"; err: %v", serviceName, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +426,10 @@ func insertConfigEntryWithTxn(tx WriteTxn, idx uint64, conf structs.ConfigEntry)
|
||||||
if err := checkGatewayAndUpdate(tx, idx, &sn, gsKind); err != nil {
|
if err := checkGatewayAndUpdate(tx, idx, &sn, gsKind); err != nil {
|
||||||
return fmt.Errorf("failed updating gateway mapping: %s", err)
|
return fmt.Errorf("failed updating gateway mapping: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := upsertKindServiceName(tx, idx, structs.ServiceKindDestination, sn); err != nil {
|
||||||
|
return fmt.Errorf("failed to persist service name: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ func (s *Store) configIntentionMatchTxn(tx ReadTxn, ws memdb.WatchSet, args *str
|
||||||
// improving that in the future, the test cases shouldn't have to
|
// improving that in the future, the test cases shouldn't have to
|
||||||
// change for that.
|
// change for that.
|
||||||
|
|
||||||
index, ixns, err := configIntentionMatchOneTxn(tx, ws, entry, args.Type)
|
index, ixns, err := configIntentionMatchOneTxn(tx, ws, entry, args.Type, structs.IntentionTargetService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
@ -224,14 +224,15 @@ func (s *Store) configIntentionMatchTxn(tx ReadTxn, ws memdb.WatchSet, args *str
|
||||||
}
|
}
|
||||||
|
|
||||||
func configIntentionMatchOneTxn(
|
func configIntentionMatchOneTxn(
|
||||||
tx ReadTxn,
|
tx ReadTxn, ws memdb.WatchSet,
|
||||||
ws memdb.WatchSet,
|
|
||||||
matchEntry structs.IntentionMatchEntry,
|
matchEntry structs.IntentionMatchEntry,
|
||||||
matchType structs.IntentionMatchType,
|
matchType structs.IntentionMatchType,
|
||||||
|
targetType structs.IntentionTargetType,
|
||||||
) (uint64, structs.Intentions, error) {
|
) (uint64, structs.Intentions, error) {
|
||||||
switch matchType {
|
switch matchType {
|
||||||
|
// targetType is only relevant for Source matches as egress Destinations can only be Intention Destinations in the mesh
|
||||||
case structs.IntentionMatchSource:
|
case structs.IntentionMatchSource:
|
||||||
return readSourceIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta())
|
return readSourceIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta(), targetType)
|
||||||
case structs.IntentionMatchDestination:
|
case structs.IntentionMatchDestination:
|
||||||
return readDestinationIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta())
|
return readDestinationIntentionsFromConfigEntriesTxn(tx, ws, matchEntry.Name, matchEntry.GetEnterpriseMeta())
|
||||||
default:
|
default:
|
||||||
|
@ -239,7 +240,13 @@ func configIntentionMatchOneTxn(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSourceIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet, serviceName string, entMeta *acl.EnterpriseMeta) (uint64, structs.Intentions, error) {
|
func readSourceIntentionsFromConfigEntriesTxn(
|
||||||
|
tx ReadTxn,
|
||||||
|
ws memdb.WatchSet,
|
||||||
|
serviceName string,
|
||||||
|
entMeta *acl.EnterpriseMeta,
|
||||||
|
targetType structs.IntentionTargetType,
|
||||||
|
) (uint64, structs.Intentions, error) {
|
||||||
idx := maxIndexTxn(tx, tableConfigEntries)
|
idx := maxIndexTxn(tx, tableConfigEntries)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -249,9 +256,7 @@ func readSourceIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet, ser
|
||||||
|
|
||||||
names := getIntentionPrecedenceMatchServiceNames(serviceName, entMeta)
|
names := getIntentionPrecedenceMatchServiceNames(serviceName, entMeta)
|
||||||
for _, sn := range names {
|
for _, sn := range names {
|
||||||
results, err = readSourceIntentionsFromConfigEntriesForServiceTxn(
|
results, err = readSourceIntentionsFromConfigEntriesForServiceTxn(tx, ws, sn.Name, &sn.EnterpriseMeta, results, targetType)
|
||||||
tx, ws, sn.Name, &sn.EnterpriseMeta, results,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
@ -263,7 +268,14 @@ func readSourceIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet, ser
|
||||||
return idx, results, nil
|
return idx, results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSourceIntentionsFromConfigEntriesForServiceTxn(tx ReadTxn, ws memdb.WatchSet, serviceName string, entMeta *acl.EnterpriseMeta, results structs.Intentions) (structs.Intentions, error) {
|
func readSourceIntentionsFromConfigEntriesForServiceTxn(
|
||||||
|
tx ReadTxn,
|
||||||
|
ws memdb.WatchSet,
|
||||||
|
serviceName string,
|
||||||
|
entMeta *acl.EnterpriseMeta,
|
||||||
|
results structs.Intentions,
|
||||||
|
targetType structs.IntentionTargetType,
|
||||||
|
) (structs.Intentions, error) {
|
||||||
sn := structs.NewServiceName(serviceName, entMeta)
|
sn := structs.NewServiceName(serviceName, entMeta)
|
||||||
|
|
||||||
iter, err := tx.Get(tableConfigEntries, indexSource, sn)
|
iter, err := tx.Get(tableConfigEntries, indexSource, sn)
|
||||||
|
@ -276,7 +288,23 @@ func readSourceIntentionsFromConfigEntriesForServiceTxn(tx ReadTxn, ws memdb.Wat
|
||||||
entry := v.(*structs.ServiceIntentionsConfigEntry)
|
entry := v.(*structs.ServiceIntentionsConfigEntry)
|
||||||
for _, src := range entry.Sources {
|
for _, src := range entry.Sources {
|
||||||
if src.SourceServiceName() == sn {
|
if src.SourceServiceName() == sn {
|
||||||
results = append(results, entry.ToIntention(src))
|
entMeta := entry.DestinationServiceName().EnterpriseMeta
|
||||||
|
kind, err := GatewayServiceKind(tx, entry.DestinationServiceName().Name, &entMeta)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch targetType {
|
||||||
|
case structs.IntentionTargetService:
|
||||||
|
if kind == structs.GatewayServiceKindService || kind == structs.GatewayServiceKindUnknown {
|
||||||
|
results = append(results, entry.ToIntention(src))
|
||||||
|
}
|
||||||
|
case structs.IntentionTargetDestination:
|
||||||
|
if kind == structs.GatewayServiceKindDestination {
|
||||||
|
results = append(results, entry.ToIntention(src))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid target type")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +326,6 @@ func readDestinationIntentionsFromConfigEntriesTxn(tx ReadTxn, ws memdb.WatchSet
|
||||||
results = append(results, entry.ToIntentions()...)
|
results = append(results, entry.ToIntentions()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the results by precedence
|
// Sort the results by precedence
|
||||||
sort.Sort(structs.IntentionPrecedenceSorter(results))
|
sort.Sort(structs.IntentionPrecedenceSorter(results))
|
||||||
|
|
||||||
|
|
|
@ -355,6 +355,11 @@ func TestStore_ServiceDefaults_Kind_Destination(t *testing.T) {
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
||||||
|
|
||||||
|
_, kindServices, err := s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 1)
|
||||||
|
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
|
||||||
|
|
||||||
ws = memdb.NewWatchSet()
|
ws = memdb.NewWatchSet()
|
||||||
_, _, err = s.GatewayServices(ws, "Gtwy1", nil)
|
_, _, err = s.GatewayServices(ws, "Gtwy1", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -369,6 +374,10 @@ func TestStore_ServiceDefaults_Kind_Destination(t *testing.T) {
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindUnknown)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindUnknown)
|
||||||
|
|
||||||
|
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStore_ServiceDefaults_Kind_NotDestination(t *testing.T) {
|
func TestStore_ServiceDefaults_Kind_NotDestination(t *testing.T) {
|
||||||
|
@ -475,6 +484,11 @@ func TestStore_Service_TerminatingGateway_Kind_Service_Destination(t *testing.T)
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
|
||||||
|
|
||||||
|
_, kindServices, err := s.ServiceNamesOfKind(ws, structs.ServiceKindTypical)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 1)
|
||||||
|
require.Equal(t, kindServices[0].Kind, structs.ServiceKindTypical)
|
||||||
|
|
||||||
require.NoError(t, s.EnsureConfigEntry(0, destination))
|
require.NoError(t, s.EnsureConfigEntry(0, destination))
|
||||||
|
|
||||||
_, gatewayServices, err = s.GatewayServices(nil, "Gtwy1", nil)
|
_, gatewayServices, err = s.GatewayServices(nil, "Gtwy1", nil)
|
||||||
|
@ -482,6 +496,11 @@ func TestStore_Service_TerminatingGateway_Kind_Service_Destination(t *testing.T)
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
|
||||||
|
|
||||||
|
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindTypical)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 1)
|
||||||
|
require.Equal(t, kindServices[0].Kind, structs.ServiceKindTypical)
|
||||||
|
|
||||||
ws = memdb.NewWatchSet()
|
ws = memdb.NewWatchSet()
|
||||||
_, _, err = s.GatewayServices(ws, "Gtwy1", nil)
|
_, _, err = s.GatewayServices(ws, "Gtwy1", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -496,6 +515,11 @@ func TestStore_Service_TerminatingGateway_Kind_Service_Destination(t *testing.T)
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
||||||
|
|
||||||
|
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 1)
|
||||||
|
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T) {
|
func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T) {
|
||||||
|
@ -541,6 +565,11 @@ func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T)
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
||||||
|
|
||||||
|
_, kindServices, err := s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 1)
|
||||||
|
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
|
||||||
|
|
||||||
require.NoError(t, s.EnsureNode(0, &structs.Node{Node: "node1"}))
|
require.NoError(t, s.EnsureNode(0, &structs.Node{Node: "node1"}))
|
||||||
require.NoError(t, s.EnsureService(0, "node1", service))
|
require.NoError(t, s.EnsureService(0, "node1", service))
|
||||||
|
|
||||||
|
@ -552,6 +581,11 @@ func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T)
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindService)
|
||||||
|
|
||||||
|
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindTypical)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 1)
|
||||||
|
require.Equal(t, kindServices[0].Kind, structs.ServiceKindTypical)
|
||||||
|
|
||||||
ws = memdb.NewWatchSet()
|
ws = memdb.NewWatchSet()
|
||||||
_, _, err = s.GatewayServices(ws, "Gtwy1", nil)
|
_, _, err = s.GatewayServices(ws, "Gtwy1", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -566,6 +600,11 @@ func TestStore_Service_TerminatingGateway_Kind_Destination_Service(t *testing.T)
|
||||||
require.Len(t, gatewayServices, 1)
|
require.Len(t, gatewayServices, 1)
|
||||||
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
require.Equal(t, gatewayServices[0].ServiceKind, structs.GatewayServiceKindDestination)
|
||||||
|
|
||||||
|
_, kindServices, err = s.ServiceNamesOfKind(ws, structs.ServiceKindDestination)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, kindServices, 1)
|
||||||
|
require.Equal(t, kindServices[0].Kind, structs.ServiceKindDestination)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStore_Service_TerminatingGateway_Kind_Service(t *testing.T) {
|
func TestStore_Service_TerminatingGateway_Kind_Service(t *testing.T) {
|
||||||
|
|
|
@ -600,6 +600,7 @@ func legacyIntentionGetTxn(tx ReadTxn, ws memdb.WatchSet, id string) (uint64, *s
|
||||||
|
|
||||||
// Convert the interface{} if it is non-nil
|
// Convert the interface{} if it is non-nil
|
||||||
var result *structs.Intention
|
var result *structs.Intention
|
||||||
|
|
||||||
if intention != nil {
|
if intention != nil {
|
||||||
result = intention.(*structs.Intention)
|
result = intention.(*structs.Intention)
|
||||||
}
|
}
|
||||||
|
@ -842,11 +843,12 @@ func (s *Store) IntentionMatchOne(
|
||||||
ws memdb.WatchSet,
|
ws memdb.WatchSet,
|
||||||
entry structs.IntentionMatchEntry,
|
entry structs.IntentionMatchEntry,
|
||||||
matchType structs.IntentionMatchType,
|
matchType structs.IntentionMatchType,
|
||||||
|
destinationType structs.IntentionTargetType,
|
||||||
) (uint64, structs.Intentions, error) {
|
) (uint64, structs.Intentions, error) {
|
||||||
tx := s.db.Txn(false)
|
tx := s.db.Txn(false)
|
||||||
defer tx.Abort()
|
defer tx.Abort()
|
||||||
|
|
||||||
return compatIntentionMatchOneTxn(tx, ws, entry, matchType)
|
return compatIntentionMatchOneTxn(tx, ws, entry, matchType, destinationType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compatIntentionMatchOneTxn(
|
func compatIntentionMatchOneTxn(
|
||||||
|
@ -854,6 +856,7 @@ func compatIntentionMatchOneTxn(
|
||||||
ws memdb.WatchSet,
|
ws memdb.WatchSet,
|
||||||
entry structs.IntentionMatchEntry,
|
entry structs.IntentionMatchEntry,
|
||||||
matchType structs.IntentionMatchType,
|
matchType structs.IntentionMatchType,
|
||||||
|
destinationType structs.IntentionTargetType,
|
||||||
) (uint64, structs.Intentions, error) {
|
) (uint64, structs.Intentions, error) {
|
||||||
|
|
||||||
usingConfigEntries, err := areIntentionsInConfigEntries(tx, ws)
|
usingConfigEntries, err := areIntentionsInConfigEntries(tx, ws)
|
||||||
|
@ -863,7 +866,7 @@ func compatIntentionMatchOneTxn(
|
||||||
if !usingConfigEntries {
|
if !usingConfigEntries {
|
||||||
return legacyIntentionMatchOneTxn(tx, ws, entry, matchType)
|
return legacyIntentionMatchOneTxn(tx, ws, entry, matchType)
|
||||||
}
|
}
|
||||||
return configIntentionMatchOneTxn(tx, ws, entry, matchType)
|
return configIntentionMatchOneTxn(tx, ws, entry, matchType, destinationType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func legacyIntentionMatchOneTxn(
|
func legacyIntentionMatchOneTxn(
|
||||||
|
@ -949,8 +952,12 @@ type ServiceWithDecision struct {
|
||||||
// IntentionTopology returns the upstreams or downstreams of a service. Upstreams and downstreams are inferred from
|
// IntentionTopology returns the upstreams or downstreams of a service. Upstreams and downstreams are inferred from
|
||||||
// intentions. If intentions allow a connection from the target to some candidate service, the candidate service is considered
|
// intentions. If intentions allow a connection from the target to some candidate service, the candidate service is considered
|
||||||
// an upstream of the target.
|
// an upstream of the target.
|
||||||
func (s *Store) IntentionTopology(ws memdb.WatchSet,
|
func (s *Store) IntentionTopology(
|
||||||
target structs.ServiceName, downstreams bool, defaultDecision acl.EnforcementDecision) (uint64, structs.ServiceList, error) {
|
ws memdb.WatchSet,
|
||||||
|
target structs.ServiceName,
|
||||||
|
downstreams bool,
|
||||||
|
defaultDecision acl.EnforcementDecision,
|
||||||
|
) (uint64, structs.ServiceList, error) {
|
||||||
tx := s.db.ReadTxn()
|
tx := s.db.ReadTxn()
|
||||||
defer tx.Abort()
|
defer tx.Abort()
|
||||||
|
|
||||||
|
@ -965,13 +972,17 @@ func (s *Store) IntentionTopology(ws memdb.WatchSet,
|
||||||
|
|
||||||
resp := make(structs.ServiceList, 0)
|
resp := make(structs.ServiceList, 0)
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
resp = append(resp, svc.Name)
|
resp = append(resp, structs.ServiceName{Name: svc.Name.Name, EnterpriseMeta: svc.Name.EnterpriseMeta})
|
||||||
}
|
}
|
||||||
return idx, resp, nil
|
return idx, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet,
|
func (s *Store) intentionTopologyTxn(
|
||||||
target structs.ServiceName, downstreams bool, defaultDecision acl.EnforcementDecision) (uint64, []ServiceWithDecision, error) {
|
tx ReadTxn, ws memdb.WatchSet,
|
||||||
|
target structs.ServiceName,
|
||||||
|
downstreams bool,
|
||||||
|
defaultDecision acl.EnforcementDecision,
|
||||||
|
) (uint64, []ServiceWithDecision, error) {
|
||||||
|
|
||||||
var maxIdx uint64
|
var maxIdx uint64
|
||||||
|
|
||||||
|
@ -987,7 +998,7 @@ func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet,
|
||||||
Partition: target.PartitionOrDefault(),
|
Partition: target.PartitionOrDefault(),
|
||||||
Name: target.Name,
|
Name: target.Name,
|
||||||
}
|
}
|
||||||
index, intentions, err := compatIntentionMatchOneTxn(tx, ws, entry, intentionMatchType)
|
index, intentions, err := compatIntentionMatchOneTxn(tx, ws, entry, intentionMatchType, structs.IntentionTargetService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("failed to query intentions for %s", target.String())
|
return 0, nil, fmt.Errorf("failed to query intentions for %s", target.String())
|
||||||
}
|
}
|
||||||
|
@ -1017,6 +1028,16 @@ func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet,
|
||||||
maxIdx = index
|
maxIdx = index
|
||||||
}
|
}
|
||||||
services = append(services, ingress...)
|
services = append(services, ingress...)
|
||||||
|
} else {
|
||||||
|
// destinations can only ever be upstream, since they are only allowed as intention destination.
|
||||||
|
index, destinations, err := serviceNamesOfKindTxn(tx, ws, structs.ServiceKindDestination, *wildcardMeta)
|
||||||
|
if err != nil {
|
||||||
|
return index, nil, fmt.Errorf("failed to list destination names: %v", err)
|
||||||
|
}
|
||||||
|
if index > maxIdx {
|
||||||
|
maxIdx = index
|
||||||
|
}
|
||||||
|
services = append(services, destinations...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// When checking authorization to upstreams, the match type for the decision is `destination` because we are deciding
|
// When checking authorization to upstreams, the match type for the decision is `destination` because we are deciding
|
||||||
|
@ -1056,7 +1077,7 @@ func (s *Store) intentionTopologyTxn(tx ReadTxn, ws memdb.WatchSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, ServiceWithDecision{
|
result = append(result, ServiceWithDecision{
|
||||||
Name: candidate,
|
Name: structs.ServiceName{Name: candidate.Name, EnterpriseMeta: candidate.EnterpriseMeta},
|
||||||
Decision: decision,
|
Decision: decision,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1533,7 +1533,7 @@ func TestStore_IntentionMatchOne_table(t *testing.T) {
|
||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
Name: query,
|
Name: query,
|
||||||
}
|
}
|
||||||
_, matches, err := s.IntentionMatchOne(nil, entry, typ)
|
_, matches, err := s.IntentionMatchOne(nil, entry, typ, structs.IntentionTargetService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Verify matches
|
// Verify matches
|
||||||
|
@ -1873,7 +1873,7 @@ func TestStore_IntentionDecision(t *testing.T) {
|
||||||
Partition: acl.DefaultPartitionName,
|
Partition: acl.DefaultPartitionName,
|
||||||
Name: tc.src,
|
Name: tc.src,
|
||||||
}
|
}
|
||||||
_, intentions, err := s.IntentionMatchOne(nil, entry, structs.IntentionMatchSource)
|
_, intentions, err := s.IntentionMatchOne(nil, entry, structs.IntentionMatchSource, structs.IntentionTargetService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,6 +494,15 @@ const (
|
||||||
IntentionSourceConsul IntentionSourceType = "consul"
|
IntentionSourceConsul IntentionSourceType = "consul"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type IntentionTargetType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// IntentionTargetService is a service within the Consul catalog.
|
||||||
|
IntentionTargetService IntentionTargetType = "service"
|
||||||
|
// IntentionTargetDestination is a destination defined through a service-default config entry.
|
||||||
|
IntentionTargetDestination IntentionTargetType = "destination"
|
||||||
|
)
|
||||||
|
|
||||||
// Intentions is a list of intentions.
|
// Intentions is a list of intentions.
|
||||||
type Intentions []*Intention
|
type Intentions []*Intention
|
||||||
|
|
||||||
|
|
|
@ -1178,6 +1178,11 @@ const (
|
||||||
// This service allows external traffic to enter the mesh based on
|
// This service allows external traffic to enter the mesh based on
|
||||||
// centralized configuration.
|
// centralized configuration.
|
||||||
ServiceKindIngressGateway ServiceKind = "ingress-gateway"
|
ServiceKindIngressGateway ServiceKind = "ingress-gateway"
|
||||||
|
|
||||||
|
// ServiceKindDestination is a Destination for the Connect feature.
|
||||||
|
// This service allows external traffic to exit the mesh through a terminating gateway
|
||||||
|
//based on centralized configuration.
|
||||||
|
ServiceKindDestination ServiceKind = "destination"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type to hold a address and port of a service
|
// Type to hold a address and port of a service
|
||||||
|
|
Loading…
Reference in New Issue