Support for connect native services in topology view. (#12098)
This commit is contained in:
parent
3984d82e90
commit
895da50986
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
ui: Support connect-native services in the Topology view.
|
||||
```
|
|
@ -3461,6 +3461,7 @@ func (s *Store) ServiceTopology(
|
|||
err error
|
||||
fullyTransparent bool
|
||||
hasTransparent bool
|
||||
connectNative bool
|
||||
)
|
||||
switch kind {
|
||||
case structs.ServiceKindIngressGateway:
|
||||
|
@ -3505,6 +3506,9 @@ func (s *Store) ServiceTopology(
|
|||
// transparent proxy mode. If ANY instance isn't in the right mode then the warming applies.
|
||||
fullyTransparent = false
|
||||
}
|
||||
if proxy.ServiceConnect.Native {
|
||||
connectNative = true
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -3526,8 +3530,8 @@ func (s *Store) ServiceTopology(
|
|||
|
||||
upstreamDecisions := make(map[string]structs.IntentionDecisionSummary)
|
||||
|
||||
// Only transparent proxies have upstreams from intentions
|
||||
if hasTransparent {
|
||||
// Only transparent proxies / connect native services have upstreams from intentions
|
||||
if hasTransparent || connectNative {
|
||||
idx, intentionUpstreams, err := s.intentionTopologyTxn(tx, ws, sn, false, defaultAllow)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
|
@ -3607,8 +3611,8 @@ func (s *Store) ServiceTopology(
|
|||
sn = structs.NewServiceName(upstream.Service.Proxy.DestinationServiceName, &upstream.Service.EnterpriseMeta)
|
||||
}
|
||||
|
||||
// Avoid returning upstreams from intentions when none of the proxy instances of the target are in transparent mode.
|
||||
if !hasTransparent && upstreamSources[sn.String()] != structs.TopologySourceRegistration {
|
||||
// Avoid returning upstreams from intentions when none of the proxy instances of the target are in transparent mode or connect native.
|
||||
if !hasTransparent && !connectNative && upstreamSources[sn.String()] != structs.TopologySourceRegistration {
|
||||
continue
|
||||
}
|
||||
upstreams = append(upstreams, upstream)
|
||||
|
@ -3711,6 +3715,7 @@ func (s *Store) ServiceTopology(
|
|||
}
|
||||
|
||||
idx, unfilteredDownstreams, err := s.combinedServiceNodesTxn(tx, ws, downstreamNames)
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("failed to get downstreams for %q: %v", sn.String(), err)
|
||||
}
|
||||
|
@ -3734,8 +3739,8 @@ func (s *Store) ServiceTopology(
|
|||
if downstream.Service.Kind == structs.ServiceKindConnectProxy {
|
||||
sn = structs.NewServiceName(downstream.Service.Proxy.DestinationServiceName, &downstream.Service.EnterpriseMeta)
|
||||
}
|
||||
if _, ok := tproxyMap[sn]; !ok && downstreamSources[sn.String()] != structs.TopologySourceRegistration {
|
||||
// If downstream is not a transparent proxy, remove references
|
||||
if _, ok := tproxyMap[sn]; !ok && !downstream.Service.Connect.Native && downstreamSources[sn.String()] != structs.TopologySourceRegistration {
|
||||
// If downstream is not a transparent proxy or connect native, remove references
|
||||
delete(downstreamSources, sn.String())
|
||||
delete(downstreamDecisions, sn.String())
|
||||
continue
|
||||
|
|
|
@ -35,6 +35,7 @@ type ServiceSummary struct {
|
|||
GatewayConfig GatewayConfig
|
||||
TransparentProxy bool
|
||||
transparentProxySet bool
|
||||
ConnectNative bool
|
||||
|
||||
structs.EnterpriseMeta
|
||||
}
|
||||
|
@ -422,6 +423,7 @@ func summarizeServices(dump structs.ServiceDump, cfg *config.RuntimeConfig, dc s
|
|||
sum.Kind = svc.Kind
|
||||
sum.Datacenter = csn.Node.Datacenter
|
||||
sum.InstanceCount += 1
|
||||
sum.ConnectNative = svc.Connect.Native
|
||||
if svc.Kind == structs.ServiceKindConnectProxy {
|
||||
sn := structs.NewServiceName(svc.Proxy.DestinationServiceName, &svc.EnterpriseMeta)
|
||||
hasProxy[sn] = true
|
||||
|
|
|
@ -1281,6 +1281,142 @@ func TestUIServiceTopology(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"Node cnative": {
|
||||
Datacenter: "dc1",
|
||||
Node: "cnative",
|
||||
Address: "127.0.0.6",
|
||||
Checks: structs.HealthChecks{
|
||||
&structs.HealthCheck{
|
||||
Node: "cnative",
|
||||
CheckID: "cnative:alive",
|
||||
Name: "cnative-liveness",
|
||||
Status: api.HealthPassing,
|
||||
},
|
||||
},
|
||||
},
|
||||
"Service cbackend on cnative": {
|
||||
Datacenter: "dc1",
|
||||
Node: "cnative",
|
||||
SkipNodeUpdate: true,
|
||||
Service: &structs.NodeService{
|
||||
Kind: structs.ServiceKindTypical,
|
||||
ID: "cbackend",
|
||||
Service: "cbackend",
|
||||
Port: 8080,
|
||||
Address: "198.18.1.70",
|
||||
},
|
||||
Checks: structs.HealthChecks{
|
||||
&structs.HealthCheck{
|
||||
Node: "cnative",
|
||||
CheckID: "cnative:cbackend",
|
||||
Name: "cbackend-liveness",
|
||||
Status: api.HealthPassing,
|
||||
ServiceID: "cbackend",
|
||||
ServiceName: "cbackend",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Service cbackend-proxy on cnative": {
|
||||
Datacenter: "dc1",
|
||||
Node: "cnative",
|
||||
SkipNodeUpdate: true,
|
||||
Service: &structs.NodeService{
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "cbackend-proxy",
|
||||
Service: "cbackend-proxy",
|
||||
Port: 8443,
|
||||
Address: "198.18.1.70",
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
DestinationServiceName: "cbackend",
|
||||
},
|
||||
},
|
||||
Checks: structs.HealthChecks{
|
||||
&structs.HealthCheck{
|
||||
Node: "cnative",
|
||||
CheckID: "cnative:cbackend-proxy",
|
||||
Name: "cbackend proxy listening",
|
||||
Status: api.HealthCritical,
|
||||
ServiceID: "cbackend-proxy",
|
||||
ServiceName: "cbackend-proxy",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Service cfrontend on cnative": {
|
||||
Datacenter: "dc1",
|
||||
Node: "cnative",
|
||||
SkipNodeUpdate: true,
|
||||
Service: &structs.NodeService{
|
||||
Kind: structs.ServiceKindTypical,
|
||||
ID: "cfrontend",
|
||||
Service: "cfrontend",
|
||||
Port: 9080,
|
||||
Address: "198.18.1.70",
|
||||
},
|
||||
Checks: structs.HealthChecks{
|
||||
&structs.HealthCheck{
|
||||
Node: "cnative",
|
||||
CheckID: "cnative:cfrontend",
|
||||
Name: "cfrontend-liveness",
|
||||
Status: api.HealthPassing,
|
||||
ServiceID: "cfrontend",
|
||||
ServiceName: "cfrontend",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Service cfrontend-proxy on cnative": {
|
||||
Datacenter: "dc1",
|
||||
Node: "cnative",
|
||||
SkipNodeUpdate: true,
|
||||
Service: &structs.NodeService{
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "cfrontend-proxy",
|
||||
Service: "cfrontend-proxy",
|
||||
Port: 9443,
|
||||
Address: "198.18.1.70",
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
DestinationServiceName: "cfrontend",
|
||||
Upstreams: structs.Upstreams{
|
||||
{
|
||||
DestinationName: "cproxy",
|
||||
LocalBindPort: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Checks: structs.HealthChecks{
|
||||
&structs.HealthCheck{
|
||||
Node: "cnative",
|
||||
CheckID: "cnative:cfrontend-proxy",
|
||||
Name: "cfrontend proxy listening",
|
||||
Status: api.HealthCritical,
|
||||
ServiceID: "cfrontend-proxy",
|
||||
ServiceName: "cfrontend-proxy",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Service cproxy on cnative": {
|
||||
Datacenter: "dc1",
|
||||
Node: "cnative",
|
||||
SkipNodeUpdate: true,
|
||||
Service: &structs.NodeService{
|
||||
Kind: structs.ServiceKindTypical,
|
||||
ID: "cproxy",
|
||||
Service: "cproxy",
|
||||
Port: 1111,
|
||||
Address: "198.18.1.70",
|
||||
Connect: structs.ServiceConnect{Native: true},
|
||||
},
|
||||
Checks: structs.HealthChecks{
|
||||
&structs.HealthCheck{
|
||||
Node: "cnative",
|
||||
CheckID: "cnative:cproxy",
|
||||
Name: "cproxy-liveness",
|
||||
Status: api.HealthPassing,
|
||||
ServiceID: "cproxy",
|
||||
ServiceName: "cproxy",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, args := range registrations {
|
||||
var out struct{}
|
||||
|
@ -1292,6 +1428,8 @@ func TestUIServiceTopology(t *testing.T) {
|
|||
// wildcard deny intention
|
||||
// api -> web exact intention
|
||||
// web -> redis exact intention
|
||||
// cfrontend -> cproxy exact intention
|
||||
// cproxy -> cbackend exact intention
|
||||
{
|
||||
entries := []structs.ConfigEntryRequest{
|
||||
{
|
||||
|
@ -1391,6 +1529,32 @@ func TestUIServiceTopology(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Datacenter: "dc1",
|
||||
Entry: &structs.ServiceIntentionsConfigEntry{
|
||||
Kind: structs.ServiceIntentions,
|
||||
Name: "cproxy",
|
||||
Sources: []*structs.SourceIntention{
|
||||
{
|
||||
Action: structs.IntentionActionAllow,
|
||||
Name: "cfrontend",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Datacenter: "dc1",
|
||||
Entry: &structs.ServiceIntentionsConfigEntry{
|
||||
Kind: structs.ServiceIntentions,
|
||||
Name: "cbackend",
|
||||
Sources: []*structs.SourceIntention{
|
||||
{
|
||||
Action: structs.IntentionActionAllow,
|
||||
Name: "cproxy",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, req := range entries {
|
||||
out := false
|
||||
|
@ -1620,6 +1784,60 @@ func TestUIServiceTopology(t *testing.T) {
|
|||
FilteredByACLs: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cproxy",
|
||||
httpReq: func() *http.Request {
|
||||
req, _ := http.NewRequest("GET", "/v1/internal/ui/service-topology/cproxy?kind=", nil)
|
||||
return req
|
||||
}(),
|
||||
want: &ServiceTopology{
|
||||
Protocol: "http",
|
||||
TransparentProxy: false,
|
||||
Upstreams: []*ServiceTopologySummary{
|
||||
{
|
||||
ServiceSummary: ServiceSummary{
|
||||
Name: "cbackend",
|
||||
Datacenter: "dc1",
|
||||
Nodes: []string{"cnative"},
|
||||
InstanceCount: 1,
|
||||
ChecksPassing: 2,
|
||||
ChecksWarning: 0,
|
||||
ChecksCritical: 1,
|
||||
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||
},
|
||||
Intention: structs.IntentionDecisionSummary{
|
||||
DefaultAllow: true,
|
||||
Allowed: true,
|
||||
HasPermissions: false,
|
||||
HasExact: true,
|
||||
},
|
||||
Source: structs.TopologySourceSpecificIntention,
|
||||
},
|
||||
},
|
||||
Downstreams: []*ServiceTopologySummary{
|
||||
{
|
||||
ServiceSummary: ServiceSummary{
|
||||
Name: "cfrontend",
|
||||
Datacenter: "dc1",
|
||||
Nodes: []string{"cnative"},
|
||||
InstanceCount: 1,
|
||||
ChecksPassing: 2,
|
||||
ChecksWarning: 0,
|
||||
ChecksCritical: 1,
|
||||
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
||||
},
|
||||
Intention: structs.IntentionDecisionSummary{
|
||||
DefaultAllow: true,
|
||||
Allowed: true,
|
||||
HasPermissions: false,
|
||||
HasExact: true,
|
||||
},
|
||||
Source: structs.TopologySourceRegistration,
|
||||
},
|
||||
},
|
||||
FilteredByACLs: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
@disabled={{disabled}}
|
||||
@oncreate={{action @oncreate item @service}}
|
||||
/>
|
||||
{{else if (and (not-eq item.Datacenter '') item.Intention.Allowed (not item.TransparentProxy) (eq item.Source 'specific-intention'))}}
|
||||
{{else if (and (not-eq item.Datacenter '') item.Intention.Allowed (not item.TransparentProxy) (not item.ConnectNative) (eq item.Source 'specific-intention'))}}
|
||||
<TopologyMetrics::Popover
|
||||
@type='not-defined'
|
||||
@service={{@service}}
|
||||
|
|
|
@ -14,6 +14,7 @@ export default class Topology extends Model {
|
|||
@attr('string') Protocol;
|
||||
@attr('boolean') FilteredByACLs;
|
||||
@attr('boolean') TransparentProxy;
|
||||
@attr('boolean') ConnectNative;
|
||||
@attr() Upstreams; // Service[]
|
||||
@attr() Downstreams; // Service[],
|
||||
@attr() meta; // {}
|
||||
|
@ -25,7 +26,7 @@ export default class Topology extends Model {
|
|||
undefinedDownstream =
|
||||
this.Downstreams.filter(
|
||||
item =>
|
||||
item.Source === 'specific-intention' && !item.TransparentProxy && item.Intention.Allowed
|
||||
item.Source === 'specific-intention' && !item.TransparentProxy && !item.ConnectNative && item.Intention.Allowed
|
||||
).length !== 0;
|
||||
|
||||
return undefinedDownstream;
|
||||
|
|
Loading…
Reference in New Issue