Fetch only the required podMetrics for the given component (#17489)

The `PodMetrics` are now limited by `labelSelector` like already done
for pods and probably other requests to Kubernetes.  This limits the
amount of data that is fetched.

Tested locally by modifying `app-config.yaml` and an example component
to use an internal cluster, which leads to the following request size
improvements:

Before: 344.71 kB compressed, 6.89 MB uncompressed
After: 12.01 kB compressed, 238.86 kB uncompressed

For the POST http://localhost:7007/api/kubernetes/services/playback-order
call, in a Kubernetes cluster with ~500 pods.

Fixes #17450.

Signed-off-by: Luna Stadler <luc@spreadshirt.net>
This commit is contained in:
Luna Stadler
2023-04-26 21:43:53 +02:00
committed by GitHub
parent 1c907ad726
commit f4114f02d4
5 changed files with 18 additions and 4 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-kubernetes-backend': minor
---
Allow fetching pod metrics limited by a `labelSelector`.
This is used by the Kubernetes tab on a components' page and leads to much smaller responses being received from Kubernetes, especially with larger Kubernetes clusters.
@@ -918,7 +918,7 @@ describe('getKubernetesObjectsByEntity', () => {
{
errorType: 'FETCH_ERROR',
message:
'request to https://fails/api/v1/pods?labelSelector=backstage.io/kubernetes-id=test-component failed, reason: socket error',
'request to https://fails/api/v1/pods?labelSelector=backstage.io%2Fkubernetes-id%3Dtest-component failed, reason: socket error',
},
],
},
@@ -283,7 +283,9 @@ export class KubernetesFanOutHandler {
})),
namespace,
})
.then(result => this.getMetricsForPods(clusterDetailsItem, result))
.then(result =>
this.getMetricsForPods(clusterDetailsItem, labelSelector, result),
)
.catch(
(e): Promise<responseWithMetrics> =>
e.name === 'FetchError'
@@ -365,6 +367,7 @@ export class KubernetesFanOutHandler {
async getMetricsForPods(
clusterDetails: ClusterDetails,
labelSelector: string,
result: FetchResponseWrapper,
): Promise<responseWithMetrics> {
if (clusterDetails.skipMetricsLookup) {
@@ -385,6 +388,7 @@ export class KubernetesFanOutHandler {
const podMetrics = await this.fetcher.fetchPodMetricsByNamespaces(
clusterDetails,
namespaces,
labelSelector,
);
result.errors.push(...podMetrics.errors);
@@ -119,6 +119,7 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
fetchPodMetricsByNamespaces(
clusterDetails: ClusterDetails,
namespaces: Set<string>,
labelSelector?: string,
): Promise<FetchResponseWrapper> {
const fetchResults = Array.from(namespaces).map(async ns => {
const [podMetrics, podList] = await Promise.all([
@@ -128,8 +129,9 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
'v1beta1',
'pods',
ns,
labelSelector,
),
this.fetchResource(clusterDetails, '', 'v1', 'pods', ns),
this.fetchResource(clusterDetails, '', 'v1', 'pods', ns, labelSelector),
]);
if (podMetrics.ok && podList.ok) {
return topPods(
@@ -213,7 +215,7 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
}
if (labelSelector) {
url.search = `labelSelector=${labelSelector}`;
url.search = `labelSelector=${encode(labelSelector)}`;
}
return fetch(url, requestInit);
@@ -56,6 +56,7 @@ export interface KubernetesFetcher {
fetchPodMetricsByNamespaces(
clusterDetails: ClusterDetails,
namespaces: Set<string>,
labelSelector?: string,
): Promise<FetchResponseWrapper>;
}