diff --git a/.changelog/10002.txt b/.changelog/10002.txt
new file mode 100644
index 000000000..207daf005
--- /dev/null
+++ b/.changelog/10002.txt
@@ -0,0 +1,3 @@
+```ui:enhancement
+Transparent Proxy - Service mesh visualization updates
+```
diff --git a/ui/packages/consul-ui/app/components/consul/transparent-proxy/index.hbs b/ui/packages/consul-ui/app/components/consul/transparent-proxy/index.hbs
new file mode 100644
index 000000000..0475d964f
--- /dev/null
+++ b/ui/packages/consul-ui/app/components/consul/transparent-proxy/index.hbs
@@ -0,0 +1,3 @@
+
+ {{t "components.consul.transparent-proxy"}}
+
\ No newline at end of file
diff --git a/ui/packages/consul-ui/app/components/informed-action/layout.scss b/ui/packages/consul-ui/app/components/informed-action/layout.scss
index 726eb31e4..b90fc6111 100644
--- a/ui/packages/consul-ui/app/components/informed-action/layout.scss
+++ b/ui/packages/consul-ui/app/components/informed-action/layout.scss
@@ -2,6 +2,9 @@
& {
min-width: 190px;
}
+ &.documentation {
+ min-width: 270px;
+ }
> div {
padding: 1rem;
}
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/card.hbs b/ui/packages/consul-ui/app/components/topology-metrics/card/index.hbs
similarity index 82%
rename from ui/packages/consul-ui/app/components/topology-metrics/card.hbs
rename to ui/packages/consul-ui/app/components/topology-metrics/card/index.hbs
index ed392e5f5..aaae528ad 100644
--- a/ui/packages/consul-ui/app/components/topology-metrics/card.hbs
+++ b/ui/packages/consul-ui/app/components/topology-metrics/card/index.hbs
@@ -1,4 +1,11 @@
-
+
+ {{@item.Name}}
+
+
+{{else}}
+
{{@item.Name}}
+ {{#if (eq @item.Source 'proxy-registration')}}
+
- {{#each-in (group-by "Datacenter" @topology.Upstreams) as |dc upstreams|}}
+ {{#each-in (group-by "Datacenter" this.upstreams) as |dc upstreams|}}
+ {{#if dc}}
{{dc}}
+ {{/if}}
{{#each upstreams as |item|}}
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/index.js b/ui/packages/consul-ui/app/components/topology-metrics/index.js
index 3704342e5..cb19b9e82 100644
--- a/ui/packages/consul-ui/app/components/topology-metrics/index.js
+++ b/ui/packages/consul-ui/app/components/topology-metrics/index.js
@@ -1,6 +1,6 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
-import { action } from '@ember/object';
+import { action, get } from '@ember/object';
export default class TopologyMetrics extends Component {
// =attributes
@@ -66,6 +66,24 @@ export default class TopologyMetrics extends Component {
});
}
+ get upstreams() {
+ const upstreams = get(this.args.topology, 'Upstreams') || [];
+ const items = [...upstreams];
+ const defaultAllow = get(this.args.topology, 'DefaultAllow');
+ const wildcardIntention = get(this.args.topology, 'WildcardIntention');
+ if (defaultAllow || wildcardIntention) {
+ items.push({
+ Name: '* (All Services)',
+ Datacenter: '',
+ Namespace: '',
+ Intention: {
+ Allowed: true,
+ },
+ });
+ }
+ return items;
+ }
+
// =actions
@action
setHeight(el, item) {
@@ -89,12 +107,22 @@ export default class TopologyMetrics extends Component {
// Calculate viewBox dimensions
this.downView = document.getElementById('downstream-lines').getBoundingClientRect();
- this.upView = document.getElementById('upstream-lines').getBoundingClientRect();
+ const upstreamLines = document.getElementById('upstream-lines').getBoundingClientRect();
+ const upstreamColumn = document.getElementById('upstream-column').getBoundingClientRect();
+
+ this.upView = {
+ x: upstreamLines.x,
+ y: upstreamLines.y,
+ width: upstreamLines.width,
+ height: upstreamColumn.height,
+ };
// Get Card elements positions
- const downCards = [...document.querySelectorAll('#downstream-container .card')];
+ const downCards = [
+ ...document.querySelectorAll('#downstream-container .topology-metrics-card'),
+ ];
const grafanaCard = document.querySelector('.metrics-header');
- const upCards = [...document.querySelectorAll('#upstream-column .card')];
+ const upCards = [...document.querySelectorAll('#upstream-column .topology-metrics-card')];
// Set center positioning points
this.centerDimensions = grafanaCard.getBoundingClientRect();
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/layout.scss b/ui/packages/consul-ui/app/components/topology-metrics/layout.scss
index 1bd386dac..8a2064709 100644
--- a/ui/packages/consul-ui/app/components/topology-metrics/layout.scss
+++ b/ui/packages/consul-ui/app/components/topology-metrics/layout.scss
@@ -49,44 +49,6 @@
#upstream-column #upstream-container:not(:last-child) {
margin-bottom: 8px;
}
-#upstream-container .card:not(:last-child),
-#downstream-container .card:not(:last-child) {
- margin-bottom: 8px;
-}
-#upstream-container .card,
-#downstream-container .card {
- display: block;
- color: $gray-700;
- overflow: hidden;
- p {
- padding: 12px 12px 0 12px;
- font-size: 16px;
- font-weight: 600;
- margin-bottom: 0 !important;
- }
- div {
- display: inline-flex;
- dl {
- display: inline-flex;
- margin-right: 8px;
- }
- span {
- margin-right: 8px;
- }
- span::before,
- dt::before {
- margin-right: 4px;
- }
- .nspace dt::before,
- .health dt::before {
- margin-top: 2px;
- }
- }
- .details {
- padding: 0 12px 12px 12px;
- }
-
-}
// Metrics Container
#metrics-container {
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/notice/index.hbs b/ui/packages/consul-ui/app/components/topology-metrics/notice/index.hbs
new file mode 100644
index 000000000..db8ac82bb
--- /dev/null
+++ b/ui/packages/consul-ui/app/components/topology-metrics/notice/index.hbs
@@ -0,0 +1,31 @@
+
+
+
+ {{t (concat "components.consul.topology-metrics.notice." @for ".header")}}
+
+
+
+
+ {{t (concat "components.consul.topology-metrics.notice." @for ".body")}}
+
+
+{{#if @action}}
+
+
+ {{#if @internal}}
+
+ {{t (concat "components.consul.topology-metrics.notice." @for ".footer.name")}}
+
+ {{else}}
+
+ {{t (concat "components.consul.topology-metrics.notice." @for ".footer")}}
+
+ {{/if}}
+
+
+{{/if}}
+
\ No newline at end of file
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/notice/limited-access.hbs b/ui/packages/consul-ui/app/components/topology-metrics/notice/limited-access.hbs
deleted file mode 100644
index 733418b6a..000000000
--- a/ui/packages/consul-ui/app/components/topology-metrics/notice/limited-access.hbs
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- Limited Access
-
-
-
-
- This service may have dependencies you won’t see because you don’t have access to them.
-
-
-
\ No newline at end of file
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs b/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs
index 3c11d0fdc..04e3316e9 100644
--- a/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs
+++ b/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs
@@ -4,22 +4,21 @@
>
{{#if (eq @type 'deny')}}
-
<:header>
- Connection Denied
+ {{t "components.consul.topology-metrics.popover.deny.header"}}
<:body>
{{#if @item.Intention.HasExact}}
- Change the action of this intention to allow.
+ {{t "components.consul.topology-metrics.popover.deny.body.isExact"}}
{{else}}
- Add an intention that allows these two services to connect.
+ {{t "components.consul.topology-metrics.popover.deny.body.notExact"}}
{{/if}}
@@ -31,9 +30,9 @@
type="button"
>
{{#if @item.Intention.HasExact}}
- Allow
+ {{t "components.consul.topology-metrics.popover.deny.action.isExact"}}
{{else}}
- Create
+ {{t "components.consul.topology-metrics.popover.deny.action.notExact"}}
{{/if}}
@@ -48,29 +47,57 @@
-
-{{else}}
-
+{{else if (eq @type 'not-defined')}}
<:header>
- Layer 7 permissions
+ {{t "components.consul.topology-metrics.popover.not-defined.header"}}
<:body>
- Certain HTTP request info must be identified.
+ {{t "components.consul.topology-metrics.popover.not-defined.body"}}
<:actions as |Actions|>
-
- View
+
+ {{t "components.consul.topology-metrics.popover.not-defined.action"}}
+
+
+
+
+ Close
+
+
+
+
+{{else}}
+
+ <:header>
+
+ {{t "components.consul.topology-metrics.popover.l7.header"}}
+
+
+ <:body>
+
+ {{t "components.consul.topology-metrics.popover.l7.body"}}
+
+
+ <:actions as |Actions|>
+
+
+ {{t "components.consul.topology-metrics.popover.l7.action"}}
@@ -84,7 +111,6 @@
-
{{/if}}
button::before,
+ &.not-defined .tippy-arrow::after {
+ @extend %with-alert-triangle-mask, %as-pseudo;
+ color: $yellow-500;
+ }
}
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/skin.scss b/ui/packages/consul-ui/app/components/topology-metrics/skin.scss
index 12a1f144e..32b82ac73 100644
--- a/ui/packages/consul-ui/app/components/topology-metrics/skin.scss
+++ b/ui/packages/consul-ui/app/components/topology-metrics/skin.scss
@@ -20,52 +20,6 @@
background-color: $gray-500;
}
}
-#upstream-container .card,
-#downstream-container .card {
- background-color: $white;
- border-radius: $decor-radius-100;
- border: 1px solid $gray-200;
- div {
- dd {
- color: $gray-700;
- }
- .nspace dt::before {
- @extend %with-folder-outline-mask, %as-pseudo;
- }
- .health dt::before {
- @extend %with-help-circle-outline-mask, %as-pseudo;
- }
- .nspace dt::before {
- @extend %with-folder-outline-mask, %as-pseudo;
- }
- .health dt::before {
- @extend %with-help-circle-outline-mask, %as-pseudo;
- }
- .nspace dt::before,
- .health dt::before {
- background-color: $gray-500;
- }
- .passing::before {
- @extend %with-check-circle-fill-color-mask, %as-pseudo;
- background-color: $green-500;
- }
- .warning::before {
- @extend %with-alert-triangle-color-mask, %as-pseudo;
- background-color: $orange-500;
- }
- .critical::before {
- @extend %with-cancel-square-fill-color-mask, %as-pseudo;
- background-color: $red-500;
- }
- .empty::before {
- @extend %with-minus-square-fill-mask, %as-pseudo;
- color: $gray-500;
- }
- }
- div:nth-child(3) {
- border-top: 1px solid $gray-200;
- }
-}
// Metrics Container
#metrics-container {
@@ -90,9 +44,6 @@
@extend %with-docs-mask, %as-pseudo;
}
}
- div:nth-child(3) {
- border-top: 1px solid $gray-200;
- }
}
// SVG Line styling
@@ -114,6 +65,9 @@
stroke: $gray-300;
stroke-width: 2;
}
+ path[data-permission='not-defined'] {
+ stroke-dasharray: 4;
+ }
path[data-permission='deny'] {
stroke: $red-500;
}
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/source-type/index.hbs b/ui/packages/consul-ui/app/components/topology-metrics/source-type/index.hbs
new file mode 100644
index 000000000..6ffec49aa
--- /dev/null
+++ b/ui/packages/consul-ui/app/components/topology-metrics/source-type/index.hbs
@@ -0,0 +1,6 @@
+
+ {{t "components.consul.topology-metrics.source-type.text"}}
+
\ No newline at end of file
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/source-type/index.scss b/ui/packages/consul-ui/app/components/topology-metrics/source-type/index.scss
new file mode 100644
index 000000000..578c0c1be
--- /dev/null
+++ b/ui/packages/consul-ui/app/components/topology-metrics/source-type/index.scss
@@ -0,0 +1,4 @@
+.topology-metrics-source-type {
+ margin: 6px 0 6px 12px;
+ display: table;
+}
\ No newline at end of file
diff --git a/ui/packages/consul-ui/app/helpers/service/intention-permissions.js b/ui/packages/consul-ui/app/helpers/service/intention-permissions.js
index b4a38f383..b882fa53f 100644
--- a/ui/packages/consul-ui/app/helpers/service/intention-permissions.js
+++ b/ui/packages/consul-ui/app/helpers/service/intention-permissions.js
@@ -3,12 +3,15 @@ import { helper } from '@ember/component/helper';
export default helper(function serviceIntentionPermissions([params] /*, hash*/) {
const hasPermissions = params.Intention.HasPermissions;
const allowed = params.Intention.Allowed;
+ const notExplicitlyDefined = params.Source === 'specific-intention' && !params.TransparentProxy;
switch (true) {
case hasPermissions:
return 'allow';
case !allowed && !hasPermissions:
return 'deny';
+ case allowed && notExplicitlyDefined:
+ return 'not-defined';
default:
return 'allow';
}
diff --git a/ui/packages/consul-ui/app/models/topology.js b/ui/packages/consul-ui/app/models/topology.js
index 9c06acd5e..29bfb448e 100644
--- a/ui/packages/consul-ui/app/models/topology.js
+++ b/ui/packages/consul-ui/app/models/topology.js
@@ -1,4 +1,5 @@
import Model, { attr } from '@ember-data/model';
+import { computed } from '@ember/object';
export const PRIMARY_KEY = 'uid';
export const SLUG_KEY = 'ServiceName';
@@ -11,7 +12,30 @@ export default class Topology extends Model {
@attr('string') Namespace;
@attr('string') Protocol;
@attr('boolean') FilteredByACLs;
+ @attr('boolean') TransparentProxy;
+ @attr('boolean') DefaultAllow;
+ @attr('boolean') WildcardIntention;
@attr() Upstreams; // Service[]
@attr() Downstreams; // Service[],
@attr() meta; // {}
+
+ @computed('Upstreams', 'Downstreams')
+ get undefinedIntention() {
+ let undefinedUpstream = false;
+ let undefinedDownstream = false;
+
+ undefinedUpstream =
+ this.Upstreams.filter(
+ item =>
+ item.Source === 'specific-intention' && !item.TransparentProxy && item.Intention.Allowed
+ ).length !== 0;
+
+ undefinedDownstream =
+ this.Downstreams.filter(
+ item =>
+ item.Source === 'specific-intention' && !item.TransparentProxy && item.Intention.Allowed
+ ).length !== 0;
+
+ return undefinedUpstream || undefinedDownstream;
+ }
}
diff --git a/ui/packages/consul-ui/app/styles/components.scss b/ui/packages/consul-ui/app/styles/components.scss
index ada90c902..8436a0be4 100644
--- a/ui/packages/consul-ui/app/styles/components.scss
+++ b/ui/packages/consul-ui/app/styles/components.scss
@@ -79,6 +79,8 @@
@import 'consul-ui/components/role-selector';
@import 'consul-ui/components/topology-metrics';
+@import 'consul-ui/components/topology-metrics/card';
+@import 'consul-ui/components/topology-metrics/source-type';
@import 'consul-ui/components/topology-metrics/popover';
@import 'consul-ui/components/topology-metrics/series';
@import 'consul-ui/components/topology-metrics/stats';
diff --git a/ui/packages/consul-ui/app/styles/components/pill.scss b/ui/packages/consul-ui/app/styles/components/pill.scss
index 707b41c8d..20c6988b7 100644
--- a/ui/packages/consul-ui/app/styles/components/pill.scss
+++ b/ui/packages/consul-ui/app/styles/components/pill.scss
@@ -1,7 +1,9 @@
span.policy-service-identity,
span.policy-node-identity,
.leader,
-.consul-auth-method-type {
+.consul-auth-method-type,
+.topology-metrics-source-type,
+.consul-transparent-proxy {
@extend %pill-200, %frame-gray-600;
}
span.policy-service-identity::before,
diff --git a/ui/packages/consul-ui/app/templates/dc/services/instance.hbs b/ui/packages/consul-ui/app/templates/dc/services/instance.hbs
index d42586c88..50668d09d 100644
--- a/ui/packages/consul-ui/app/templates/dc/services/instance.hbs
+++ b/ui/packages/consul-ui/app/templates/dc/services/instance.hbs
@@ -58,6 +58,9 @@ as |route|>
+ {{#if (eq proxy.ServiceProxy.Mode 'transparent')}}
+
+ {{/if}}
diff --git a/ui/packages/consul-ui/app/templates/dc/services/show/topology.hbs b/ui/packages/consul-ui/app/templates/dc/services/show/topology.hbs
index d9650f24a..f1ddf5676 100644
--- a/ui/packages/consul-ui/app/templates/dc/services/show/topology.hbs
+++ b/ui/packages/consul-ui/app/templates/dc/services/show/topology.hbs
@@ -23,7 +23,36 @@ as |route|>
{{else}}
{{#if topology.FilteredByACLs}}
-
+
+ {{/if}}
+ {{#if topology.DefaultAllow}}
+
+ {{/if}}
+ {{#if topology.WildcardIntention}}
+
+ {{/if}}
+ {{#if topology.undefinedIntention}}
+
{{/if}}
`
`)}
]
},
+ "Mode": "${fake.helpers.randomize(['', 'direct', 'transparent'])}",
"DestinationServiceName": "${location.pathname.slice(4)}"
${ location.pathname.slice(4) === "service-0" ? `
,
diff --git a/ui/packages/consul-ui/mock-api/v1/internal/ui/service-topology/_ b/ui/packages/consul-ui/mock-api/v1/internal/ui/service-topology/_
index 339adee51..d4f6ade68 100644
--- a/ui/packages/consul-ui/mock-api/v1/internal/ui/service-topology/_
+++ b/ui/packages/consul-ui/mock-api/v1/internal/ui/service-topology/_
@@ -52,10 +52,18 @@ ${
}
fake.seed(index);
+
+ // Randomly make permissive intentions
+ const defaultAllow = fake.random.boolean();
+ const wildcardIntention = defaultAllow ? false : fake.random.boolean();
+
return `
{
"Protocol": "${serviceProto}",
"FilteredByACLs": ${fake.random.boolean()},
+ "TransparentProxy": ${fake.random.boolean()},
+ "DefaultAllow": ${defaultAllow},
+ "WildcardIntention": ${wildcardIntention},
"Upstreams": [
${
upstreams.map((item, i) => {
@@ -70,11 +78,14 @@ ${
"ChecksPassing":${fake.random.number({min: 1, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksWarning":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksCritical":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
+ "Source": "${fake.helpers.randomize(['proxy-registration', 'default-allow', 'wildcard-intention'])}",
+ "TransparentProxy": ${fake.random.boolean()},
"Intention": {
"Allowed": ${allowed},
"HasPermissions": ${hasPerms},
"ExternalSource": "${fake.helpers.randomize(['nomad', 'kubernetes', ''])}",
- "HasExact": ${fake.random.boolean()}
+ "HasExact": ${fake.random.boolean()},
+ "DefaultAllow": ${fake.random.boolean()}
}
}
`})}
@@ -93,11 +104,14 @@ ${
"ChecksPassing":${fake.random.number({min: 1, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksWarning":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
"ChecksCritical":${fake.random.number({min: 0, max: env('CONSUL_CHECK_COUNT', fake.random.number(10))})},
+ "Source": "${fake.helpers.randomize(['proxy-registration', 'specific-intention', 'default-allow', 'wildcard-intention'])}",
+ "TransparentProxy": ${fake.random.boolean()},
"Intention": {
"Allowed": ${allowed},
"HasPermissions": ${hasPerms},
"ExternalSource": "${fake.helpers.randomize(['nomad', 'kubernetes', ''])}",
- "HasExact": ${fake.random.boolean()}
+ "HasExact": ${fake.random.boolean()},
+ "DefaultAllow": ${fake.random.boolean()}
}
}
`})}
diff --git a/ui/packages/consul-ui/translations/en-us.yaml b/ui/packages/consul-ui/translations/en-us.yaml
index 9aa5afc75..021539dc9 100644
--- a/ui/packages/consul-ui/translations/en-us.yaml
+++ b/ui/packages/consul-ui/translations/en-us.yaml
@@ -184,6 +184,51 @@ components:
name: Precedence
asc: Ascending
desc: Descending
+ transparent-proxy: Transparent Proxy
+ topology-metrics:
+ source-type:
+ tooltip: This connection was defined in a proxy registration.
+ text: Defined in proxy registration
+ notice:
+ limited-access:
+ header: Limited Access
+ body: This service may have dependencies you won’t see because you don’t have access to them.
+ default-allow:
+ header: Intentions are set to default allow
+ body: Your Intention settings are currently set to default allow. This means that this view will show connections to every service in your cluster. We recommend changing your Intention settings to default deny and creating specific Intentions for upstream and downstream services for this view to be useful.
+ footer:
+ name: Edit intentions
+ URL: dc.services.show.intentions
+ not-defined-intention:
+ header: Connections are not explicitly defined
+ body: There appears to be an Intention defining traffic, but the services are unable to communicate until that connection is explicitly defined as a downstream or Transparent Proxy mode is turned on.
+ footer: Read the documentation
+ wildcard-intention:
+ header: Permissive Intention
+ body: One or more of your Intentions are set to allow traffic to and/or from all other services in a namespace. This Topology view will show all of those connections if that remains unchanged. We recommend setting more specific Intentions for upstream and downstream services to make this vizualization more useful.
+ footer:
+ name: Edit intentions
+ URL: dc.services.show.intentions
+ popover:
+ l7:
+ header: Layer 7 permissions
+ body: Certain HTTP request info must be identified.
+ action: View
+ deny:
+ header: Connection Denied
+ body:
+ isExact: Change the action of this intention to allow.
+ notExact: Add an intention that allows these two services to connect.
+ action:
+ isExact: Allow
+ notExact: Create
+ not-defined:
+ header: No traffic
+ body: Add the current service as an explicit upstream or turn on Transparent Proxy mode to initiate traffic.
+ action: Documentation
+
+
+
models:
auth-method: