Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dataplanes): add visualization for built-in gateways #2082

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/app/data-planes/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DiscoverySubscriptionCollection, type DiscoverySubscription } from '@/a
import type { ApiKindListResponse, PaginatedApiListResponse } from '@/types/api.d'
import type {
DataPlane as PartialDataplane,
DataplaneGateway as PartialDataplaneGateway,
DataplaneInbound as PartialDataplaneInbound,
DataPlaneInsight as PartialDataplaneInsight,
DataplaneNetworking as PartialDataplaneNetworking,
Expand Down Expand Up @@ -43,6 +44,8 @@ export type DataplaneOutbound = PartialDataplaneOutbound & {
protocol: string
}

export type DataplaneGateway = PartialDataplaneGateway & {}

export type DataplaneNetworking = Omit<PartialDataplaneNetworking, 'inbound' | 'outbound'> & {
inbounds: DataplaneInbound[]
outbounds: DataplaneOutbound[]
Expand Down
10 changes: 5 additions & 5 deletions src/app/data-planes/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ export const sources = (source: Source, api: KumaApi, can: Can) => {
return api.getDataplaneFromMesh(params, { format: 'kubernetes' })
},

'/meshes/:mesh/dataplanes/:name/stats': async (params) => {
const { mesh, name } = params
'/meshes/:mesh/dataplanes/:name/stats/:service': async (params) => {
const { mesh, name, service } = params
const res = await api.getDataplaneData({
mesh,
dppName: name,
Expand All @@ -76,21 +76,21 @@ export const sources = (source: Source, api: KumaApi, can: Can) => {
// parse the stuff
const json = parse(res)

// inbounds is anything starting with `localhost_`
const inbounds = getTraffic(json, (key) => key.startsWith('localhost_'))
// inbounds is anything starting with `service`
const inbounds = getTraffic(json, (key) => key.startsWith(service))

// outbounds are anything else unless it starts with something in the
// below list these are likely to follow a pattern at some point at which
// point this list can be removed and replaced by something that exludes
// the pattern
const outbounds = getTraffic(json, (key) => {
return ![
service, // Removes inbounds
'_', // most internal names will be prefixed by `_` the rest will become legacy internal names
'admin',
'async-client',
'kuma_envoy_admin',
'probe_listener',
'localhost_',
'inbound_passthrough',
'outbound_passthrough',
'access_log_sink',
Expand Down
153 changes: 146 additions & 7 deletions src/app/data-planes/views/DataPlaneDetailView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
>
<DataSource
v-slot="{ data: traffic, error, refresh }: StatsSource"
:src="props.data.dataplaneType === 'standard' ? `/meshes/${route.params.mesh}/dataplanes/${route.params.dataPlane}/stats` : ''"
:src="props.data.dataplaneType === 'delegated' ? '' : `/meshes/${route.params.mesh}/dataplanes/${route.params.dataPlane}/stats/${props.data.dataplaneType === 'builtin' && props.data.dataplane.networking.gateway ? props.data.dataplane.networking.gateway.tags['kuma.io/service'] : 'localhost_'}`"
kleinfreund marked this conversation as resolved.
Show resolved Hide resolved
>
<AppView>
<template
Expand Down Expand Up @@ -115,7 +115,145 @@
</KCard>

<KCard
v-if="props.data.dataplaneType === 'standard'"
v-if="props.data.dataplaneType === 'builtin' && props.data.dataplane.networking.gateway"
class="traffic"
data-testid="dataplane-traffic"
>
<div class="columns">
<DataPlaneTraffic>
<template #title>
<ForwardIcon
display="inline-block"
decorative
:size="KUI_ICON_SIZE_30"
/>

Inbounds
</template>

<ServiceTrafficGroup type="inbound">
<template
v-for="(inbound, index) in [
(traffic || { inbounds: [] }).inbounds.find((inbound) => inbound.name === props.data.dataplane.networking.gateway?.tags['kuma.io/service']),
]"
:key="index"
>
<ServiceTrafficCard
protocol="http"
:traffic="inbound"
>
<RouterLink
:to="{
name: 'data-plane-inbound-summary-overview-view',
params: {
service: props.data.dataplane.networking.gateway.tags['kuma.io/service'],
},
query: {
inactive: route.params.inactive ? null : undefined,
},
}"
>
{{ props.data.dataplane.networking.gateway.tags['kuma.io/service'] }}
</RouterLink>

<TagList
:tags="[{
label: 'kuma.io/service',
value: props.data.dataplane.networking.gateway.tags['kuma.io/service'],
}]"
/>
</ServiceTrafficCard>
</template>
</ServiceTrafficGroup>
</DataPlaneTraffic>

<DataPlaneTraffic>
<template
v-if="traffic"
#actions
>
<KInputSwitch
v-model="route.params.inactive"
data-testid="dataplane-outbounds-inactive-toggle"
>
<template #label>
Show inactive
</template>
</KInputSwitch>

<KButton
appearance="primary"
@click="refresh"
>
<RefreshIcon :size="KUI_ICON_SIZE_30" />

Refresh
</KButton>
</template>

<template #title>
<GatewayIcon
display="inline-block"
decorative
:size="KUI_ICON_SIZE_30"
/>

Outbounds
</template>

<template v-if="traffic">
<ServiceTrafficGroup type="passthrough">
<ServiceTrafficCard
:protocol="`passthrough`"
:traffic="traffic.passthrough"
>
Non mesh traffic
</ServiceTrafficCard>
</ServiceTrafficGroup>

<template
v-for="outbounds in [
route.params.inactive ? traffic.outbounds : traffic.outbounds.filter((item) => (item.protocol === 'tcp' ? item.tcp?.downstream_cx_rx_bytes_total : item.http?.downstream_rq_total) as (number | undefined) ?? 0 > 0),
]"
:key="outbounds"
>
<ServiceTrafficGroup
v-if="outbounds.length > 0"
type="outbound"
data-testid="dataplane-outbounds"
>
<template
v-for="item in outbounds"
:key="`${item.name}`"
>
<ServiceTrafficCard
:protocol="item.protocol"
:traffic="item"
>
<RouterLink
:to="{
name: ((name) => name.includes('bound') ? name.replace('-inbound-', '-outbound-') : 'data-plane-outbound-summary-overview-view')(String(_route.name)),
params: {
service: item.name,
},
query: {
inactive: route.params.inactive ? null : undefined,
},
}"
>
{{ item.name }}
</RouterLink>
</ServiceTrafficCard>
</template>
</ServiceTrafficGroup>
</template>
</template>
</DataPlaneTraffic>
</div>
</KCard>

<KCard
v-else-if="props.data.dataplaneType === 'standard'"
class="traffic"
data-testid="dataplane-traffic"
>
Expand Down Expand Up @@ -163,7 +301,7 @@
:to="{
name: ((name) => name.includes('bound') ? name.replace('-outbound-', '-inbound-') : 'data-plane-inbound-summary-overview-view')(String(_route.name)),
params: {
service: item.port,
service: `localhost_${item.port}`,
},
query: {
inactive: route.params.inactive ? null : undefined,
Expand Down Expand Up @@ -273,6 +411,7 @@
</DataPlaneTraffic>
</div>
</KCard>

<RouterView
v-slot="child"
>
Expand All @@ -295,10 +434,10 @@
>
<component
:is="child.Component"
:data="String(child.route.name).includes('-inbound-') ?
props.data.dataplane.networking.inbounds || [] :
traffic?.outbounds || []
"
:dataplane-type="props.data.dataplaneType"
:gateway="props.data.dataplane.networking.gateway"
:inbounds="(child.route.name as string).includes('-inbound-') ? props.data.dataplane.networking.inbounds : []"
:data="(child.route.name as string).includes('-inbound-') ? traffic?.inbounds || [] : traffic?.outbounds || []"
/>
</SummaryView>
</RouterView>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,36 @@
name="data-plane-inbound-summary-overview-view"
>
<AppView>
<div class="stack-with-borders">
<div
v-if="props.gateway"
class="stack-with-borders"
>
<DefinitionCard layout="horizontal">
<template #title>
Tags
</template>

<template #body>
<TagList
:tags="props.data.tags"
:tags="props.gateway.tags"
alignment="right"
/>
</template>
</DefinitionCard>
</div>

<div
v-else-if="props.inbound"
class="stack-with-borders"
>
<DefinitionCard layout="horizontal">
<template #title>
Tags
</template>

<template #body>
<TagList
:tags="props.inbound.tags"
alignment="right"
/>
</template>
Expand All @@ -24,9 +45,9 @@

<template #body>
<KBadge
:appearance="props.data.health.ready ? 'success' : 'danger'"
:appearance="props.inbound.health.ready ? 'success' : 'danger'"
>
{{ props.data.health.ready ? 'Healthy' : 'Unhealthy' }}
{{ props.inbound.health.ready ? 'Healthy' : 'Unhealthy' }}
</KBadge>
</template>
</DefinitionCard>
Expand All @@ -39,7 +60,7 @@
<KBadge
appearance="info"
>
{{ t(`http.api.value.${props.data.protocol}`) }}
{{ t(`http.api.value.${props.inbound.protocol}`) }}
</KBadge>
</template>
</DefinitionCard>
Expand All @@ -50,7 +71,7 @@

<template #body>
<TextWithCopyButton
:text="`${props.data.addressPort}`"
:text="`${props.inbound.addressPort}`"
/>
</template>
</DefinitionCard>
Expand All @@ -61,20 +82,23 @@

<template #body>
<TextWithCopyButton
:text="`${props.data.serviceAddressPort}`"
:text="`${props.inbound.serviceAddressPort}`"
/>
</template>
</DefinitionCard>
</div>
</AppView>
</RouteView>
</template>

<script lang="ts" setup>
import type { DataplaneInbound } from '../data'
import type { DataplaneGateway, DataplaneInbound } from '../data'
import DefinitionCard from '@/app/common/DefinitionCard.vue'
import TagList from '@/app/common/TagList.vue'
import TextWithCopyButton from '@/app/common/TextWithCopyButton.vue'

const props = defineProps<{
data: DataplaneInbound
inbound?: DataplaneInbound
gateway?: DataplaneGateway
}>()
</script>
13 changes: 6 additions & 7 deletions src/app/data-planes/views/DataPlaneInboundSummaryStatsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<div>
<DataSource
v-slot="{ data, error, refresh }: StatsSource"
:src="`/meshes/${route.params.mesh}/dataplanes/${route.params.dataPlane}/stats`"
:src="`/meshes/${route.params.mesh}/dataplanes/${route.params.dataPlane}/stats/${route.params.service}`"
>
<ErrorBlock
v-if="error"
Expand All @@ -34,12 +34,11 @@
<CodeBlock
v-else
language="json"
:code="(() => `${
data.raw.split('\n')
.filter(item => item.includes(`.localhost_${route.params.service}.`))
.map(item => item.replace(`localhost_${route.params.service}.`, ''))
.join('\n')
}`)()"
:code="(() => data.raw.split('\n')
.filter((item) => item.includes(`.${route.params.service}.`))
.map((item) => item.replace(`${route.params.service}.`, ''))
.join('\n')
)()"
is-searchable
:query="route.params.codeSearch"
:is-filter-mode="route.params.codeFilter"
Expand Down
Loading