feat(kubernetes): update k8s-backend plugin to use label selectors

update plugin to use label selectors when querying backend
This commit is contained in:
Moustafa Baiou
2020-10-19 23:22:08 -04:00
committed by moustafab
parent da2f4cd41a
commit e2085293a6
11 changed files with 132 additions and 74 deletions
@@ -57,7 +57,7 @@ describe('KubernetesClientProvider', () => {
clientMock.listServiceForAllNamespaces.mockRejectedValue(errorResponse);
const result = await sut.fetchObjectsByServiceId(
const result = await sut.fetchObjectsForService(
'some-service',
{
name: 'cluster1',
@@ -120,7 +120,7 @@ describe('KubernetesClientProvider', () => {
},
});
const result = await sut.fetchObjectsByServiceId(
const result = await sut.fetchObjectsForService(
'some-service',
{
name: 'cluster1',
@@ -169,7 +169,7 @@ describe('KubernetesClientProvider', () => {
});
it('should throw error on unknown type', () => {
expect(() =>
sut.fetchObjectsByServiceId(
sut.fetchObjectsForService(
'some-service',
{
name: 'cluster1',
@@ -105,15 +105,19 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
this.logger = logger;
}
fetchObjectsByServiceId(
fetchObjectsForService(
serviceId: string,
clusterDetails: ClusterDetails,
objectTypesToFetch: Set<KubernetesObjectTypes>,
labelSelector: string,
): Promise<FetchResponseWrapper> {
const fetchResults = Array.from(objectTypesToFetch).map(type => {
return this.fetchByObjectType(serviceId, clusterDetails, type).catch(
captureKubernetesErrorsRethrowOthers,
);
return this.fetchByObjectType(
serviceId,
clusterDetails,
type,
labelSelector,
).catch(captureKubernetesErrorsRethrowOthers);
});
return Promise.all(fetchResults).then(fetchResultsToResponseWrapper);
@@ -124,42 +128,53 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
serviceId: string,
clusterDetails: ClusterDetails,
type: KubernetesObjectTypes,
labelSelector: string,
): Promise<FetchResponse> {
switch (type) {
case 'pods':
return this.fetchPodsByServiceId(serviceId, clusterDetails).then(r => ({
return this.fetchPodsForService(
serviceId,
clusterDetails,
labelSelector,
).then(r => ({
type: type,
resources: r,
}));
case 'configmaps':
return this.fetchConfigMapsByServiceId(
return this.fetchConfigMapsForService(
serviceId,
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'deployments':
return this.fetchDeploymentsByServiceId(
return this.fetchDeploymentsForService(
serviceId,
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'replicasets':
return this.fetchReplicaSetsByServiceId(
return this.fetchReplicaSetsForService(
serviceId,
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'services':
return this.fetchServicesByServiceId(
return this.fetchServicesForService(
serviceId,
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'horizontalpodautoscalers':
return this.fetchHorizontalPodAutoscalersByServiceId(
return this.fetchHorizontalPodAutoscalersForService(
serviceId,
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
case 'ingresses':
return this.fetchIngressesByServiceId(
return this.fetchIngressesForService(
serviceId,
clusterDetails,
labelSelector,
).then(r => ({ type: type, resources: r }));
default:
// unrecognised type
@@ -192,79 +207,60 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
});
}
private fetchServicesByServiceId(
private fetchServicesForService(
serviceId: string,
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1Service>> {
return this.singleClusterFetch<V1Service>(clusterDetails, ({ core }) =>
core.listServiceForAllNamespaces(
false,
'',
'',
`backstage.io/kubernetes-id=${serviceId}`,
),
core.listServiceForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchPodsByServiceId(
private fetchPodsForService(
serviceId: string,
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1Pod>> {
return this.singleClusterFetch<V1Pod>(clusterDetails, ({ core }) =>
core.listPodForAllNamespaces(
false,
'',
'',
`backstage.io/kubernetes-id=${serviceId}`,
),
core.listPodForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchConfigMapsByServiceId(
private fetchConfigMapsForService(
serviceId: string,
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1ConfigMap>> {
return this.singleClusterFetch<V1Pod>(clusterDetails, ({ core }) =>
core.listConfigMapForAllNamespaces(
false,
'',
'',
`backstage.io/kubernetes-id=${serviceId}`,
),
core.listConfigMapForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchDeploymentsByServiceId(
private fetchDeploymentsForService(
serviceId: string,
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1Deployment>> {
return this.singleClusterFetch<V1Deployment>(clusterDetails, ({ apps }) =>
apps.listDeploymentForAllNamespaces(
false,
'',
'',
`backstage.io/kubernetes-id=${serviceId}`,
),
apps.listDeploymentForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchReplicaSetsByServiceId(
private fetchReplicaSetsForService(
serviceId: string,
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1ReplicaSet>> {
return this.singleClusterFetch<V1ReplicaSet>(clusterDetails, ({ apps }) =>
apps.listReplicaSetForAllNamespaces(
false,
'',
'',
`backstage.io/kubernetes-id=${serviceId}`,
),
apps.listReplicaSetForAllNamespaces(false, '', '', labelSelector),
);
}
private fetchHorizontalPodAutoscalersByServiceId(
private fetchHorizontalPodAutoscalersForService(
serviceId: string,
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<V1HorizontalPodAutoscaler>> {
return this.singleClusterFetch<V1HorizontalPodAutoscaler>(
clusterDetails,
@@ -273,14 +269,15 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
false,
'',
'',
`backstage.io/kubernetes-id=${serviceId}`,
labelSelector,
),
);
}
private fetchIngressesByServiceId(
private fetchIngressesForService(
serviceId: string,
clusterDetails: ClusterDetails,
labelSelector: string,
): Promise<Array<ExtensionsV1beta1Ingress>> {
return this.singleClusterFetch<ExtensionsV1beta1Ingress>(
clusterDetails,
@@ -289,7 +286,7 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher {
false,
'',
'',
`backstage.io/kubernetes-id=${serviceId}`,
labelSelector,
),
);
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { handleGetKubernetesObjectsByServiceId } from './getKubernetesObjectsByServiceIdHandler';
import { handleGetKubernetesObjectsForService } from './getKubernetesObjectsForServiceHandler';
import { getVoidLogger } from '@backstage/backend-common';
import { ClusterDetails } from '..';
@@ -81,10 +81,10 @@ describe('handleGetKubernetesObjectsByServiceId', () => {
mockFetch(fetchObjectsByServiceId);
const result = await handleGetKubernetesObjectsByServiceId(
const result = await handleGetKubernetesObjectsForService(
TEST_SERVICE_ID,
{
fetchObjectsByServiceId,
fetchObjectsForService: fetchObjectsByServiceId,
},
{
getClustersByServiceId,
@@ -155,10 +155,10 @@ describe('handleGetKubernetesObjectsByServiceId', () => {
mockFetch(fetchObjectsByServiceId);
const result = await handleGetKubernetesObjectsByServiceId(
const result = await handleGetKubernetesObjectsForService(
TEST_SERVICE_ID,
{
fetchObjectsByServiceId,
fetchObjectsForService: fetchObjectsByServiceId,
},
{
getClustersByServiceId,
@@ -26,12 +26,13 @@ import {
import { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';
import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';
export type GetKubernetesObjectsByServiceIdHandler = (
export type GetKubernetesObjectsForServiceHandler = (
serviceId: string,
fetcher: KubernetesFetcher,
serviceLocator: KubernetesServiceLocator,
logger: Logger,
requestBody: AuthRequestBody,
labelSelector: string,
objectsToFetch?: Set<KubernetesObjectTypes>,
) => Promise<ObjectsByServiceIdResponse>;
@@ -46,12 +47,13 @@ const DEFAULT_OBJECTS = new Set<KubernetesObjectTypes>([
]);
// Fans out the request to all clusters that the service lives in, aggregates their responses together
export const handleGetKubernetesObjectsByServiceId: GetKubernetesObjectsByServiceIdHandler = async (
export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServiceHandler = async (
serviceId,
fetcher,
serviceLocator,
logger,
requestBody,
labelSelector: string,
objectsToFetch = DEFAULT_OBJECTS,
) => {
const clusterDetails: ClusterDetails[] = await serviceLocator.getClustersByServiceId(
@@ -81,7 +83,7 @@ export const handleGetKubernetesObjectsByServiceId: GetKubernetesObjectsByServic
return Promise.all(
clusterDetailsDecoratedForAuth.map(cd => {
return fetcher
.fetchObjectsByServiceId(serviceId, cd, objectsToFetch)
.fetchObjectsForService(serviceId, cd, objectsToFetch, labelSelector)
.then(result => {
return {
cluster: {
@@ -32,7 +32,7 @@ describe('router', () => {
beforeAll(async () => {
kubernetesFetcher = {
fetchObjectsByServiceId: jest.fn(),
fetchObjectsForService: jest.fn(),
};
kubernetesServiceLocator = {
@@ -22,9 +22,9 @@ import { MultiTenantServiceLocator } from '../service-locator/MultiTenantService
import { KubernetesClientBasedFetcher } from './KubernetesFetcher';
import { KubernetesClientProvider } from './KubernetesClientProvider';
import {
GetKubernetesObjectsByServiceIdHandler,
handleGetKubernetesObjectsByServiceId,
} from './getKubernetesObjectsByServiceIdHandler';
GetKubernetesObjectsForServiceHandler,
handleGetKubernetesObjectsForService,
} from './getKubernetesObjectsForServiceHandler';
import {
AuthRequestBody,
KubernetesServiceLocator,
@@ -64,13 +64,14 @@ export const makeRouter = (
logger: Logger,
fetcher: KubernetesFetcher,
serviceLocator: KubernetesServiceLocator,
handleGetByServiceId: GetKubernetesObjectsByServiceIdHandler,
handleGetByServiceId: GetKubernetesObjectsForServiceHandler,
): express.Router => {
const router = Router();
router.use(express.json());
router.post('/services/:serviceId', async (req, res) => {
const serviceId = req.params.serviceId;
const labelSelector = req.query.labelSelector;
const requestBody: AuthRequestBody = req.body;
try {
const response = await handleGetByServiceId(
@@ -79,6 +80,7 @@ export const makeRouter = (
serviceLocator,
logger,
requestBody,
labelSelector,
);
res.send(response);
} catch (e) {
@@ -119,6 +121,6 @@ export async function createRouter(
logger,
fetcher,
serviceLocator,
handleGetKubernetesObjectsByServiceId,
handleGetKubernetesObjectsForService,
);
}
@@ -110,10 +110,11 @@ export interface IngressesFetchResponse {
// Fetches information from a kubernetes cluster using the cluster details object
// to target a specific cluster
export interface KubernetesFetcher {
fetchObjectsByServiceId(
fetchObjectsForService(
serviceId: string,
clusterDetails: ClusterDetails,
objectTypesToFetch: Set<KubernetesObjectTypes>,
labelSelector: string,
): Promise<FetchResponseWrapper>;
}