diff --git a/packages/kuma-gui/src/app/connections/locales/en-us/index.yaml b/packages/kuma-gui/src/app/connections/locales/en-us/index.yaml index 5d6ecf86b..49e8930db 100644 --- a/packages/kuma-gui/src/app/connections/locales/en-us/index.yaml +++ b/packages/kuma-gui/src/app/connections/locales/en-us/index.yaml @@ -3,5 +3,6 @@ connections: item: navigation: overview: 'Overview' + xds: 'XDS Configuration' stats: 'Stats' clusters: 'Clusters' diff --git a/packages/kuma-gui/src/app/connections/routes.ts b/packages/kuma-gui/src/app/connections/routes.ts index bc5e99017..dca4160a0 100644 --- a/packages/kuma-gui/src/app/connections/routes.ts +++ b/packages/kuma-gui/src/app/connections/routes.ts @@ -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', @@ -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', diff --git a/packages/kuma-gui/src/app/connections/views/ConnectionInboundSummaryXdsConfigView.vue b/packages/kuma-gui/src/app/connections/views/ConnectionInboundSummaryXdsConfigView.vue new file mode 100644 index 000000000..4f1381ac1 --- /dev/null +++ b/packages/kuma-gui/src/app/connections/views/ConnectionInboundSummaryXdsConfigView.vue @@ -0,0 +1,60 @@ + + diff --git a/packages/kuma-gui/src/app/connections/views/ConnectionOutboundSummaryXdsConfigView.vue b/packages/kuma-gui/src/app/connections/views/ConnectionOutboundSummaryXdsConfigView.vue new file mode 100644 index 000000000..64c8410e1 --- /dev/null +++ b/packages/kuma-gui/src/app/connections/views/ConnectionOutboundSummaryXdsConfigView.vue @@ -0,0 +1,60 @@ + + diff --git a/packages/kuma-gui/src/app/data-planes/data/DataplaneNetworking.ts b/packages/kuma-gui/src/app/data-planes/data/DataplaneNetworking.ts index 3349eea0a..008d307ae 100644 --- a/packages/kuma-gui/src/app/data-planes/data/DataplaneNetworking.ts +++ b/packages/kuma-gui/src/app/data-planes/data/DataplaneNetworking.ts @@ -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, @@ -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}`, } diff --git a/packages/kuma-gui/src/app/data-planes/sources.ts b/packages/kuma-gui/src/app/data-planes/sources.ts index dacbf7db5..724a463e9 100644 --- a/packages/kuma-gui/src/app/data-planes/sources.ts +++ b/packages/kuma-gui/src/app/data-planes/sources.ts @@ -30,7 +30,44 @@ export type MeshGatewayDataplaneSource = DataSourceResponse(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 @@ -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 diff --git a/packages/kuma-gui/src/app/x/components/x-code-block/XCodeBlock.vue b/packages/kuma-gui/src/app/x/components/x-code-block/XCodeBlock.vue index f243fa0d5..56b815c6d 100644 --- a/packages/kuma-gui/src/app/x/components/x-code-block/XCodeBlock.vue +++ b/packages/kuma-gui/src/app/x/components/x-code-block/XCodeBlock.vue @@ -1,5 +1,8 @@