Skip to content

Commit

Permalink
feature(dataplanes): add filtered XDS config to inbound drawers
Browse files Browse the repository at this point in the history
Signed-off-by: John Cowen <[email protected]>
  • Loading branch information
johncowen committed Nov 18, 2024
1 parent 769956a commit 876dce4
Show file tree
Hide file tree
Showing 10 changed files with 904 additions and 463 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ connections:
item:
navigation:
overview: 'Overview'
xds: 'XDS Configuration'
stats: 'Stats'
clusters: 'Clusters'
10 changes: 10 additions & 0 deletions packages/kuma-gui/src/app/connections/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export const routes = (): RouteRecordRaw[] => {
name: 'connection-inbound-summary-overview-view',
component: () => import('@/app/connections/views/ConnectionInboundSummaryOverviewView.vue'),
},
{
path: 'xds-config',
name: 'connection-inbound-summary-xds-config-view',
component: () => import('@/app/connections/views/ConnectionInboundSummaryXdsConfigView.vue'),
},
{
path: 'stats',
name: 'connection-inbound-summary-stats-view',
Expand All @@ -33,6 +38,11 @@ export const routes = (): RouteRecordRaw[] => {
name: 'connection-outbound-summary-overview-view',
component: () => import('@/app/connections/views/ConnectionOutboundSummaryOverviewView.vue'),
},
{
path: 'xds-config',
name: 'connection-outbound-summary-xds-config-view',
component: () => import('@/app/connections/views/ConnectionOutboundSummaryXdsConfigView.vue'),
},
{
path: 'stats',
name: 'connection-outbound-summary-stats-view',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<RouteView
:params="{
codeSearch: '',
codeFilter: false,
codeRegExp: false,
mesh: '',
dataPlane: '',
connection: '',
}"
name="connection-inbound-summary-xds-config-view"
v-slot="{ route, uri }"
>
<RouteTitle
:render="false"
:title="`XDS Configuration`"
/>
<AppView>
<DataLoader
:src="uri(sources, '/meshes/:mesh/dataplanes/:dataplane/inbound/:inbound/xds', {
mesh: route.params.mesh,
dataplane: route.params.dataPlane,
inbound: `${props.data.addressPort}`,
})"
v-slot="{ data: raw, refresh }"
>
<XCodeBlock
language="json"
:code="JSON.stringify(raw, null, 2)"
is-searchable
:query="route.params.codeSearch"
:is-filter-mode="route.params.codeFilter"
:is-reg-exp-mode="route.params.codeRegExp"
@query-change="route.update({ codeSearch: $event })"
@filter-mode-change="route.update({ codeFilter: $event })"
@reg-exp-mode-change="route.update({ codeRegExp: $event })"
>
<template #primary-actions>
<XAction
action="refresh"
appearance="primary"
@click="refresh"
>
Refresh
</XAction>
</template>
</XCodeBlock>
</DataLoader>
</AppView>
</RouteView>
</template>
<script lang="ts" setup>
import type { DataplaneInbound, DataplaneOverview } from '@/app/data-planes/data/'
import { sources } from '@/app/data-planes/sources'
const props = defineProps<{
data: DataplaneInbound
dataplaneOverview: DataplaneOverview
}>()
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<RouteView
:params="{
codeSearch: '',
codeFilter: false,
codeRegExp: false,
mesh: '',
dataPlane: '',
connection: '',
includeEds: false,
}"
name="connection-outbound-summary-xds-config-view"
v-slot="{ route, uri }"
>
<RouteTitle
:render="false"
:title="`XDS Configuration`"
/>
<AppView>
<DataLoader
:src="uri(sources, '/meshes/:mesh/dataplanes/:dataplane/outbound/:outbound/xds/:endpoints', {
mesh: route.params.mesh,
dataplane: route.params.dataPlane,
outbound: route.params.connection,
endpoints: String(route.params.includeEds),
})"
v-slot="{ data: raw, refresh }"
>
<XCodeBlock
language="json"
:code="JSON.stringify(raw, null, 2)"
is-searchable
:query="route.params.codeSearch"
:is-filter-mode="route.params.codeFilter"
:is-reg-exp-mode="route.params.codeRegExp"
@query-change="route.update({ codeSearch: $event })"
@filter-mode-change="route.update({ codeFilter: $event })"
@reg-exp-mode-change="route.update({ codeRegExp: $event })"
>
<template #primary-actions>
<XCheckbox
v-model="route.params.includeEds"
label="Include Endpoints"
/>
<XAction
action="refresh"
appearance="primary"
@click="refresh"
>
Refresh
</XAction>
</template>
</XCodeBlock>
</DataLoader>
</AppView>
</RouteView>
</template>
<script lang="ts" setup>
import { sources } from '@/app/data-planes/sources'
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ export const DataplaneNetworking = {
listenerAddress: '',
}]
: inbounds.map((item) => {
const address = item.address ?? networking.address
// inbound address, advertisedAddress, networkingAddress because externally accessible address
const address = item.address ?? networking.advertisedAddress ?? networking.address
const port = item.servicePort ?? item.port
return {
...item,
Expand All @@ -91,8 +92,7 @@ export const DataplaneNetworking = {
service: item.tags['kuma.io/service'],
protocol: item.tags['kuma.io/protocol'] ?? 'tcp',
address,
// inbound address, advertisedAddress, networkingAddress because externally accessible address
addressPort: `${item.address ?? networking.advertisedAddress ?? networking.address}:${item.port}`,
addressPort: `${address}:${item.port}`,
// inbound serviceAddress, inbound address, networkingAddress because the internal services accessible address
serviceAddressPort: `${item.serviceAddress ?? address}:${port}`,
}
Expand Down
81 changes: 81 additions & 0 deletions packages/kuma-gui/src/app/data-planes/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,44 @@ export type MeshGatewayDataplaneSource = DataSourceResponse<MeshGatewayDataplane
const includes = <T extends readonly string[]>(arr: T, item: string): item is T[number] => {
return arr.includes(item as T[number])
}
type XdsConfig = Record<'configs', {
dynamic_active_clusters?: {
cluster: {
name: string
}
}[]
dynamic_listeners?: {
name: string
}[]
dynamic_endpoint_configs?: {
endpoint_config: {
cluster_name: string
}
}[]
}[]>
const filter = (data: XdsConfig, cb: (key: string, arr: unknown[]) => unknown[]) => {
const { configs } = data
return {
configs: configs.reduce((prev, item) => {
const entries = Object.entries(item)
const found = entries.reduce((prev, [key, value]) => {
const found = cb(key, value)
if (found.length > 0) {
if (typeof prev[key] === 'undefined') {
prev[key] = []
}
prev[key] = prev[key].concat(found)
}
return prev
}, {} as typeof configs[number])
if (Object.keys(found).length > 0) {
return prev.concat(found)
}
return prev

}, [] as typeof configs),
}
}
export const sources = (source: Source, api: KumaApi, can: Can) => {
return defineSources({
// always resolves and keeps polling until we have at least one dataplane and all dataplanes are online
Expand Down Expand Up @@ -87,6 +124,50 @@ export const sources = (source: Source, api: KumaApi, can: Can) => {
dataPath,
})
},
'/meshes/:mesh/dataplanes/:dataplane/inbound/:inbound/xds': async (params) => {
const { mesh, dataplane, inbound } = params

// we don't ask for endpoints because we don't need them for inbound filtering
const res = await api.getDataplaneData({
mesh,
dppName: dataplane,
dataPath: 'xds',
}, {
include_eds: false,
})
// @ts-ignore res: api.getDataplaneData() returns a string even though it doesn't always return a string
// once we get OpenAPI specs for this we should be able to remove
return filter(res, (key: string, arr: { name: string }[]) => {
switch (key) {
case 'dynamic_listeners':
return arr.filter(item => item.name === `inbound:${inbound}`)
}
return []
})
},
'/meshes/:mesh/dataplanes/:dataplane/outbound/:outbound/xds/:endpoints': async (params) => {
const { mesh, dataplane, outbound, endpoints } = params

// we don't ask for endpoints because we don't need them for inbound filtering
const res = await api.getDataplaneData({
mesh,
dppName: dataplane,
dataPath: 'xds',
}, {
include_eds: endpoints,
})
// @ts-ignore res: api.getDataplaneData() returns a string even though it doesn't always return a string
// once we get OpenAPI specs for this we should be able to remove
return filter(res, (key: string, arr: { endpoint_config: { cluster_name: string }, cluster: { name: string } }[]) => {
switch (key) {
case 'dynamic_active_clusters':
return arr.filter(item => item.cluster.name === outbound)
case 'dynamic_endpoint_configs':
return arr.filter(item => item.endpoint_config.cluster_name === outbound)
}
return []
})
},
'/meshes/:mesh/dataplanes/:name/xds/:endpoints': async (params) => {
const { mesh, name, endpoints } = params

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<template>
<div>
<div
class="x-code-block"
data-testid="x-code-block"
>
<template
v-if="$slots['primary-actions']"
>
Expand All @@ -17,7 +20,7 @@
:initial-filter-mode="props.isFilterMode"
:initial-reg-exp-mode="props.isRegExpMode"
:processing="isProcessing"
:searchable="isSearchable"
:searchable="true"
:show-copy-button="showCopyButton"
:query="props.query"
theme="dark"
Expand Down
3 changes: 3 additions & 0 deletions packages/kuma-gui/src/test-support/FakeKuma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ export class KumaModule {
}
}

/**
* @deprecated - please inline networking property instead
*/
dataplaneNetworking(
{
type = 'proxy',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ export default ({ env, fake }: EndpointDependencies): MockResponder => (req) =>
// temporarily overwrite the result of dataplaneNetworking as it doesn't
// currently accept port plus we need to keep our ports synced.
; (networking.inbound ?? []).forEach((inbound, i) => {
if (fake.datatype.boolean()) {
// if (fake.datatype.boolean()) {

Check failure on line 40 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
inbound.address = address

Check failure on line 41 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
inbound.port = ports[i].port

Check failure on line 42 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
inbound.servicePort = undefined

Check failure on line 43 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
} else {
inbound.port = fake.number.int({ min: 1, max: 65535 })
inbound.servicePort = ports[i].port
}
inbound.tags['kuma.io/protocol'] = ports[i].protocol
})
// } else {

Check failure on line 44 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
// inbound.port = fake.number.int({ min: 1, max: 65535 })

Check failure on line 45 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
// inbound.servicePort = ports[i].port

Check failure on line 46 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
// }

Check failure on line 47 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
inbound.tags['kuma.io/protocol'] = ports[i].protocol

Check failure on line 48 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 4 spaces but found 6
})

Check failure on line 49 in packages/kuma-gui/src/test-support/mocks/src/meshes/_/dataplanes/_/_overview.ts

View workflow job for this annotation

GitHub Actions / lint-tests

Expected indentation of 2 spaces but found 4

const parts = String(name).split('.')
const displayName = parts.slice(0, -1).join('.')
Expand All @@ -57,10 +58,36 @@ export default ({ env, fake }: EndpointDependencies): MockResponder => (req) =>
type: 'DataplaneOverview',
mesh,
name,
creationTime: '2021-02-17T08:33:36.442044+01:00',
modificationTime: '2021-02-17T08:33:36.442044+01:00',
...((modificationTime) => ({
creationTime: fake.kuma.date({ refDate: modificationTime }),
modificationTime,
}))(fake.kuma.date()),
dataplane: {
networking,
networking: {
...networking,
inbounds: Array.from({ length: inboundCount }).map((_, i) => {
return {
...(() => {
// TODO(jc) we need to understand correctly, and cope with serviceAddress and servicePort and how it relates to address
return {
address,
port: ports[i].port,
}
})(),
tags: fake.kuma.tags({
protocol: fake.kuma.protocol(),
service,
zone: isMultizone && fake.datatype.boolean() ? fake.hacker.noun() : undefined,
}),
}
}),
outbounds: [
{
port: fake.internet.port(),
tags: fake.kuma.tags({ service }),
},
],
},
},
...(k8s
? {
Expand Down
Loading

0 comments on commit 876dce4

Please sign in to comment.