refactor kubernetes fetcher (#7504)

* refactor kubernetes fetcher

Signed-off-by: mclarke47 <matthewclarke47@gmail.com>

* typo

Signed-off-by: mclarke47 <matthewclarke47@gmail.com>

* tsc errors

Signed-off-by: mclarke47 <matthewclarke47@gmail.com>

* Create unlucky-laws-doubt.md

Signed-off-by: mclarke47 <matthewclarke47@gmail.com>

* missed prettier

Signed-off-by: mclarke47 <matthewclarke47@gmail.com>

* api report

Signed-off-by: mclarke47 <matthewclarke47@gmail.com>

* fix tests

Signed-off-by: mclarke47 <matthewclarke47@gmail.com>
This commit is contained in:
Matthew Clarke
2021-10-11 15:38:37 +01:00
committed by GitHub
parent adf3c687b3
commit 89bcf90b66
7 changed files with 329 additions and 275 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-kubernetes': patch
---
Refactor kubernetes fetcher to reduce boilerplate code
+18 -8
View File
@@ -46,19 +46,15 @@ export function createRouter(options: RouterOptions): Promise<express.Router>;
// Warning: (ae-missing-release-tag) "CustomResource" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export interface CustomResource {
export interface CustomResource extends ObjectToFetch {
// (undocumented)
apiVersion: string;
// (undocumented)
group: string;
// (undocumented)
plural: string;
objectType: 'customresources';
}
// Warning: (ae-missing-release-tag) "DEFAULT_OBJECTS" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const DEFAULT_OBJECTS: KubernetesObjectTypes[];
export const DEFAULT_OBJECTS: ObjectToFetch[];
// Warning: (ae-missing-release-tag) "FetchResponseWrapper" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -139,11 +135,25 @@ export interface ObjectFetchParams {
// (undocumented)
labelSelector: string;
// (undocumented)
objectTypesToFetch: Set<KubernetesObjectTypes>;
objectTypesToFetch: Set<ObjectToFetch>;
// (undocumented)
serviceId: string;
}
// Warning: (ae-missing-release-tag) "ObjectToFetch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export interface ObjectToFetch {
// (undocumented)
apiVersion: string;
// (undocumented)
group: string;
// (undocumented)
objectType: KubernetesObjectTypes;
// (undocumented)
plural: string;
}
// Warning: (ae-missing-release-tag) "RouterOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -19,8 +19,8 @@ import {
ClusterDetails,
CustomResource,
KubernetesFetcher,
KubernetesObjectTypes,
KubernetesServiceLocator,
ObjectToFetch,
} from '../types/types';
import {
ClusterObjects,
@@ -29,14 +29,49 @@ import {
import { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';
import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';
export const DEFAULT_OBJECTS: KubernetesObjectTypes[] = [
'pods',
'services',
'configmaps',
'deployments',
'replicasets',
'horizontalpodautoscalers',
'ingresses',
export const DEFAULT_OBJECTS: ObjectToFetch[] = [
{
group: '',
apiVersion: 'v1',
plural: 'pods',
objectType: 'pods',
},
{
group: '',
apiVersion: 'v1',
plural: 'services',
objectType: 'services',
},
{
group: '',
apiVersion: 'v1',
plural: 'configmaps',
objectType: 'configmaps',
},
{
group: 'apps',
apiVersion: 'v1',
plural: 'deployments',
objectType: 'deployments',
},
{
group: 'apps',
apiVersion: 'v1',
plural: 'replicasets',
objectType: 'replicasets',
},
{
group: 'autoscaling',
apiVersion: 'v1',
plural: 'horizontalpodautoscalers',
objectType: 'horizontalpodautoscalers',
},
{
group: 'networking.k8s.io',
apiVersion: 'v1',
plural: 'ingresses',
objectType: 'ingresses',
},
];
export interface KubernetesFanOutHandlerOptions {
@@ -44,7 +79,7 @@ export interface KubernetesFanOutHandlerOptions {
fetcher: KubernetesFetcher;
serviceLocator: KubernetesServiceLocator;
customResources: CustomResource[];
objectTypesToFetch?: KubernetesObjectTypes[];
objectTypesToFetch?: ObjectToFetch[];
}
export class KubernetesFanOutHandler {
@@ -52,7 +87,7 @@ export class KubernetesFanOutHandler {
private readonly fetcher: KubernetesFetcher;
private readonly serviceLocator: KubernetesServiceLocator;
private readonly customResources: CustomResource[];
private readonly objectTypesToFetch: KubernetesObjectTypes[];
private readonly objectTypesToFetch: Set<ObjectToFetch>;
constructor({
logger,
@@ -65,7 +100,7 @@ export class KubernetesFanOutHandler {
this.fetcher = fetcher;
this.serviceLocator = serviceLocator;
this.customResources = customResources;
this.objectTypesToFetch = objectTypesToFetch;
this.objectTypesToFetch = new Set(objectTypesToFetch);
}
async getKubernetesObjectsByEntity(requestBody: KubernetesRequestBody) {
@@ -109,7 +144,7 @@ export class KubernetesFanOutHandler {
.fetchObjectsForService({
serviceId: entityName,
clusterDetails: clusterDetailsItem,
objectTypesToFetch: new Set(this.objectTypesToFetch),
objectTypesToFetch: this.objectTypesToFetch,
labelSelector,
customResources: this.customResources,
})
@@ -16,6 +16,22 @@
import { getVoidLogger } from '@backstage/backend-common';
import { KubernetesClientBasedFetcher } from './KubernetesFetcher';
import { ObjectToFetch } from '../types/types';
const OBJECTS_TO_FETCH = new Set<ObjectToFetch>([
{
group: '',
apiVersion: 'v1',
plural: 'pods',
objectType: 'pods',
},
{
group: '',
apiVersion: 'v1',
plural: 'services',
objectType: 'services',
},
]);
describe('KubernetesFetcher', () => {
let clientMock: any;
@@ -25,15 +41,11 @@ describe('KubernetesFetcher', () => {
beforeEach(() => {
jest.resetAllMocks();
clientMock = {
listPodForAllNamespaces: jest.fn(),
listServiceForAllNamespaces: jest.fn(),
listClusterCustomObject: jest.fn(),
addInterceptor: jest.fn(),
};
kubernetesClientProvider = {
getCoreClientByClusterDetails: jest.fn(() => clientMock),
getAppsClientByClusterDetails: jest.fn(() => clientMock),
getAutoscalingClientByClusterDetails: jest.fn(() => clientMock),
getNetworkingBeta1Client: jest.fn(() => clientMock),
getCustomObjectsClient: jest.fn(() => clientMock),
};
@@ -44,7 +56,7 @@ describe('KubernetesFetcher', () => {
});
const testErrorResponse = async (errorResponse: any, expectedResult: any) => {
clientMock.listPodForAllNamespaces.mockResolvedValueOnce({
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
@@ -56,7 +68,7 @@ describe('KubernetesFetcher', () => {
},
});
clientMock.listServiceForAllNamespaces.mockRejectedValue(errorResponse);
clientMock.listClusterCustomObject.mockRejectedValue(errorResponse);
const result = await sut.fetchObjectsForService({
serviceId: 'some-service',
@@ -66,7 +78,7 @@ describe('KubernetesFetcher', () => {
serviceAccountToken: 'token',
authProvider: 'serviceAccount',
},
objectTypesToFetch: new Set(['pods', 'services']),
objectTypesToFetch: OBJECTS_TO_FETCH,
labelSelector: '',
customResources: [],
});
@@ -87,19 +99,35 @@ describe('KubernetesFetcher', () => {
],
});
expect(clientMock.listPodForAllNamespaces.mock.calls.length).toBe(1);
expect(clientMock.listServiceForAllNamespaces.mock.calls.length).toBe(1);
expect(clientMock.listClusterCustomObject.mock.calls.length).toBe(2);
expect(clientMock.listClusterCustomObject.mock.calls[0]).toEqual([
'',
'v1',
'pods',
'',
'',
'',
'backstage.io/kubernetes-id=some-service',
]);
expect(clientMock.listClusterCustomObject.mock.calls[1]).toEqual([
'',
'v1',
'services',
'',
'',
'',
'backstage.io/kubernetes-id=some-service',
]);
expect(
kubernetesClientProvider.getAppsClientByClusterDetails.mock.calls.length,
).toBe(2);
expect(
kubernetesClientProvider.getCoreClientByClusterDetails.mock.calls.length,
kubernetesClientProvider.getCustomObjectsClient.mock.calls.length,
).toBe(2);
};
it('should return pods, services', async () => {
clientMock.listPodForAllNamespaces.mockResolvedValueOnce({
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
@@ -111,7 +139,7 @@ describe('KubernetesFetcher', () => {
},
});
clientMock.listServiceForAllNamespaces.mockResolvedValueOnce({
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
@@ -131,7 +159,7 @@ describe('KubernetesFetcher', () => {
serviceAccountToken: 'token',
authProvider: 'serviceAccount',
},
objectTypesToFetch: new Set(['pods', 'services']),
objectTypesToFetch: OBJECTS_TO_FETCH,
labelSelector: '',
customResources: [],
});
@@ -162,41 +190,160 @@ describe('KubernetesFetcher', () => {
],
});
expect(clientMock.listPodForAllNamespaces.mock.calls.length).toBe(1);
expect(clientMock.listServiceForAllNamespaces.mock.calls.length).toBe(1);
expect(clientMock.listClusterCustomObject.mock.calls.length).toBe(2);
expect(clientMock.listClusterCustomObject.mock.calls[0]).toEqual([
'',
'v1',
'pods',
'',
'',
'',
'backstage.io/kubernetes-id=some-service',
]);
expect(clientMock.listClusterCustomObject.mock.calls[1]).toEqual([
'',
'v1',
'services',
'',
'',
'',
'backstage.io/kubernetes-id=some-service',
]);
expect(
kubernetesClientProvider.getAppsClientByClusterDetails.mock.calls.length,
).toBe(2);
expect(
kubernetesClientProvider.getCoreClientByClusterDetails.mock.calls.length,
kubernetesClientProvider.getCustomObjectsClient.mock.calls.length,
).toBe(2);
});
it('should throw error on unknown type', () => {
expect(() =>
sut.fetchObjectsForService({
serviceId: 'some-service',
clusterDetails: {
name: 'cluster1',
url: 'http://localhost:9999',
serviceAccountToken: 'token',
authProvider: 'serviceAccount',
it('should return pods, services and customobjects', async () => {
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
metadata: {
name: 'pod-name',
},
},
],
},
});
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
metadata: {
name: 'service-name',
},
},
],
},
});
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
metadata: {
name: 'something-else',
},
},
],
},
});
const result = await sut.fetchObjectsForService({
serviceId: 'some-service',
clusterDetails: {
name: 'cluster1',
url: 'http://localhost:9999',
serviceAccountToken: 'token',
authProvider: 'serviceAccount',
},
objectTypesToFetch: OBJECTS_TO_FETCH,
labelSelector: '',
customResources: [
{
objectType: 'customresources',
group: 'some-group',
apiVersion: 'v2',
plural: 'things',
},
objectTypesToFetch: new Set<any>(['foo']),
labelSelector: '',
customResources: [],
}),
).toThrow('unrecognised type=foo');
],
});
expect(clientMock.listPodForAllNamespaces.mock.calls.length).toBe(0);
expect(clientMock.listServiceForAllNamespaces.mock.calls.length).toBe(0);
expect(result).toStrictEqual({
errors: [],
responses: [
{
type: 'pods',
resources: [
{
metadata: {
name: 'pod-name',
},
},
],
},
{
type: 'services',
resources: [
{
metadata: {
name: 'service-name',
},
},
],
},
{
type: 'customresources',
resources: [
{
metadata: {
name: 'something-else',
},
},
],
},
],
});
expect(clientMock.listClusterCustomObject.mock.calls.length).toBe(3);
expect(clientMock.listClusterCustomObject.mock.calls[0]).toEqual([
'',
'v1',
'pods',
'',
'',
'',
'backstage.io/kubernetes-id=some-service',
]);
expect(clientMock.listClusterCustomObject.mock.calls[1]).toEqual([
'',
'v1',
'services',
'',
'',
'',
'backstage.io/kubernetes-id=some-service',
]);
expect(clientMock.listClusterCustomObject.mock.calls[2]).toEqual([
'some-group',
'v2',
'things',
'',
'',
'',
'backstage.io/kubernetes-id=some-service',
]);
expect(
kubernetesClientProvider.getAppsClientByClusterDetails.mock.calls.length,
).toBe(0);
expect(
kubernetesClientProvider.getCoreClientByClusterDetails.mock.calls.length,
).toBe(0);
kubernetesClientProvider.getCustomObjectsClient.mock.calls.length,
).toBe(3);
});
// they're in testErrorResponse
// eslint-disable-next-line jest/expect-expect
@@ -283,7 +430,7 @@ describe('KubernetesFetcher', () => {
);
});
it('should always add a labelSelector query', async () => {
clientMock.listPodForAllNamespaces.mockResolvedValueOnce({
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
@@ -295,7 +442,7 @@ describe('KubernetesFetcher', () => {
},
});
clientMock.listServiceForAllNamespaces.mockResolvedValueOnce({
clientMock.listClusterCustomObject.mockResolvedValueOnce({
body: {
items: [
{
@@ -315,12 +462,12 @@ describe('KubernetesFetcher', () => {
serviceAccountToken: 'token',
authProvider: 'serviceAccount',
},
objectTypesToFetch: new Set(['pods', 'services']),
objectTypesToFetch: OBJECTS_TO_FETCH,
labelSelector: '',
customResources: [],
});
const mockCall = clientMock.listPodForAllNamespaces.mock.calls[0];
const mockCall = clientMock.listClusterCustomObject.mock.calls[0];
const actualSelector = mockCall[mockCall.length - 1];
const expectedSelector = 'backstage.io/kubernetes-id=some-service';
expect(actualSelector).toBe(expectedSelector);
@@ -18,16 +18,8 @@ import {
AppsV1Api,
AutoscalingV1Api,
CoreV1Api,
ExtensionsV1beta1Ingress,
NetworkingV1beta1Api,
V1ConfigMap,
V1Deployment,
V1HorizontalPodAutoscaler,
V1Pod,
V1ReplicaSet,
} from '@kubernetes/client-node';
import { V1Service } from '@kubernetes/client-node/dist/gen/model/v1Service';
import http from 'http';
import lodash, { Dictionary } from 'lodash';
import { Logger } from 'winston';
import {
@@ -36,7 +28,7 @@ import {
KubernetesFetcher,
KubernetesObjectTypes,
ObjectFetchParams,
CustomResource,
ObjectToFetch,
} from '../types/types';
import {
FetchResponse,
@@ -88,17 +80,6 @@ const statusCodeToErrorType = (statusCode: number): KubernetesErrorTypes => {
}
};
const captureKubernetesErrorsRethrowOthers = (e: any): KubernetesFetchError => {
if (e.response && e.response.statusCode) {
return {
errorType: statusCodeToErrorType(e.response.statusCode),
statusCode: e.response.statusCode,
resourcePath: e.response.request.uri.pathname,
};
}
throw e;
};
export class KubernetesClientBasedFetcher implements KubernetesFetcher {
private readonly kubernetesClientProvider: KubernetesClientProvider;
private readonly logger: Logger;
@@ -114,202 +95,60 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
fetchObjectsForService(
params: ObjectFetchParams,
): Promise<FetchResponseWrapper> {
const fetchResults = Array.from(params.objectTypesToFetch).map(type => {
return this.fetchByObjectType(
params.clusterDetails,
type,
params.labelSelector ||
`backstage.io/kubernetes-id=${params.serviceId}`,
).catch(captureKubernetesErrorsRethrowOthers);
});
const fetchResults = Array.from(params.objectTypesToFetch)
.concat(params.customResources)
.map(toFetch => {
return this.fetchResource(
params.clusterDetails,
toFetch,
params.labelSelector ||
`backstage.io/kubernetes-id=${params.serviceId}`,
toFetch.objectType,
).catch(this.captureKubernetesErrorsRethrowOthers.bind(this));
});
const customObjectsFetchResults = params.customResources.map(cr => {
return this.fetchCustomResource(
params.clusterDetails,
cr,
params.labelSelector ||
`backstage.io/kubernetes-id=${params.serviceId}`,
).catch(captureKubernetesErrorsRethrowOthers);
});
return Promise.all(fetchResults.concat(customObjectsFetchResults)).then(
fetchResultsToResponseWrapper,
);
return Promise.all(fetchResults).then(fetchResultsToResponseWrapper);
}
// TODO could probably do with a tidy up
private fetchByObjectType(
clusterDetails: ClusterDetails,
type: KubernetesObjectTypes,
labelSelector: string,
): Promise<FetchResponse> {
switch (type) {
case 'pods':
return this.fetchPodsForService(clusterDetails, labelSelector).then(
r => ({
type: type,
resources: r,
}),
);
case 'configmaps':
return this.fetchConfigMapsForService(
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'deployments':
return this.fetchDeploymentsForService(
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'replicasets':
return this.fetchReplicaSetsForService(
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'services':
return this.fetchServicesForService(clusterDetails, labelSelector).then(
r => ({ type: type, resources: r }),
);
case 'horizontalpodautoscalers':
return this.fetchHorizontalPodAutoscalersForService(
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'ingresses':
return this.fetchIngressesForService(
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
default:
// unrecognised type
throw new Error(`unrecognised type=${type}`);
private captureKubernetesErrorsRethrowOthers(e: any): KubernetesFetchError {
if (e.response && e.response.statusCode) {
this.logger.info(
`statusCode=${e.response.statusCode} for resource ${e.response.request.uri.pathname}`,
);
return {
errorType: statusCodeToErrorType(e.response.statusCode),
statusCode: e.response.statusCode,
resourcePath: e.response.request.uri.pathname,
};
}
throw e;
}
private fetchCustomResource(
private fetchResource(
clusterDetails: ClusterDetails,
customResource: CustomResource,
resource: ObjectToFetch,
labelSelector: string,
objectType: KubernetesObjectTypes,
): Promise<FetchResponse> {
const customObjects =
this.kubernetesClientProvider.getCustomObjectsClient(clusterDetails);
customObjects.addInterceptor((requestOptions: any) => {
requestOptions.uri = requestOptions.uri.replace('/apis//v1/', '/api/v1/');
});
return customObjects
.listClusterCustomObject(
customResource.group,
customResource.apiVersion,
customResource.plural,
resource.group,
resource.apiVersion,
resource.plural,
'',
'',
'',
labelSelector,
)
.then(r => {
return { type: 'customresources', resources: (r.body as any).items };
return { type: objectType, resources: (r.body as any).items };
});
}
private singleClusterFetch<T>(
clusterDetails: ClusterDetails,
fn: (
client: Clients,
) => Promise<{ body: { items: Array<T> }; response: http.IncomingMessage }>,
): Promise<Array<T>> {
const core =
this.kubernetesClientProvider.getCoreClientByClusterDetails(
clusterDetails,
);
const apps =
this.kubernetesClientProvider.getAppsClientByClusterDetails(
clusterDetails,
);
const autoscaling =
this.kubernetesClientProvider.getAutoscalingClientByClusterDetails(
clusterDetails,
);
const networkingBeta1 =
this.kubernetesClientProvider.getNetworkingBeta1Client(clusterDetails);
this.logger.debug(`calling cluster=${clusterDetails.name}`);
return fn({ core, apps, autoscaling, networkingBeta1 }).then(({ body }) => {
return body.items;
});
}
private fetchServicesForService(
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1Service>> {
return this.singleClusterFetch<V1Service>(clusterDetails, ({ core }) =>
core.listServiceForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchPodsForService(
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1Pod>> {
return this.singleClusterFetch<V1Pod>(clusterDetails, ({ core }) =>
core.listPodForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchConfigMapsForService(
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1ConfigMap>> {
return this.singleClusterFetch<V1Pod>(clusterDetails, ({ core }) =>
core.listConfigMapForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchDeploymentsForService(
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1Deployment>> {
return this.singleClusterFetch<V1Deployment>(clusterDetails, ({ apps }) =>
apps.listDeploymentForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchReplicaSetsForService(
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1ReplicaSet>> {
return this.singleClusterFetch<V1ReplicaSet>(clusterDetails, ({ apps }) =>
apps.listReplicaSetForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchHorizontalPodAutoscalersForService(
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1HorizontalPodAutoscaler>> {
return this.singleClusterFetch<V1HorizontalPodAutoscaler>(
clusterDetails,
({ autoscaling }) =>
autoscaling.listHorizontalPodAutoscalerForAllNamespaces(
false,
'',
'',
labelSelector,
),
);
}
private fetchIngressesForService(
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<ExtensionsV1beta1Ingress>> {
return this.singleClusterFetch<ExtensionsV1beta1Ingress>(
clusterDetails,
({ networkingBeta1 }) =>
networkingBeta1.listIngressForAllNamespaces(
false,
'',
'',
labelSelector,
),
);
}
}
@@ -30,7 +30,10 @@ import {
} from '../types/types';
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
import { KubernetesClientProvider } from './KubernetesClientProvider';
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
import {
KubernetesFanOutHandler,
DEFAULT_OBJECTS,
} from './KubernetesFanOutHandler';
import { KubernetesClientBasedFetcher } from './KubernetesFetcher';
export interface RouterOptions {
@@ -109,6 +112,7 @@ export async function createRouter(
group: c.getString('group'),
apiVersion: c.getString('apiVersion'),
plural: c.getString('plural'),
objectType: 'customresources',
} as CustomResource),
);
@@ -134,10 +138,18 @@ export async function createRouter(
);
const serviceLocator = getServiceLocator(options.config, clusterDetails);
const objectTypesToFetch = options.config.getOptionalStringArray(
const objectTypesToFetchStrings = options.config.getOptionalStringArray(
'kubernetes.objectTypes',
) as KubernetesObjectTypes[];
let objectTypesToFetch;
if (objectTypesToFetchStrings) {
objectTypesToFetch = DEFAULT_OBJECTS.filter(obj =>
objectTypesToFetchStrings.includes(obj.objectType),
);
}
const kubernetesFanOutHandler = new KubernetesFanOutHandler({
logger,
fetcher,
+12 -7
View File
@@ -19,12 +19,6 @@ import type {
KubernetesFetchError,
} from '@backstage/plugin-kubernetes-common';
export interface CustomResource {
group: string;
apiVersion: string;
plural: string;
}
export interface ObjectFetchParams {
serviceId: string;
clusterDetails:
@@ -32,7 +26,7 @@ export interface ObjectFetchParams {
| GKEClusterDetails
| ServiceAccountClusterDetails
| ClusterDetails;
objectTypesToFetch: Set<KubernetesObjectTypes>;
objectTypesToFetch: Set<ObjectToFetch>;
labelSelector: string;
customResources: CustomResource[];
}
@@ -52,6 +46,17 @@ export interface FetchResponseWrapper {
// TODO fairly sure there's a easier way to do this
export interface ObjectToFetch {
objectType: KubernetesObjectTypes;
group: string;
apiVersion: string;
plural: string;
}
export interface CustomResource extends ObjectToFetch {
objectType: 'customresources';
}
export type KubernetesObjectTypes =
| 'pods'
| 'services'