modify approach to post entire entity to k8s backend

This commit is contained in:
Moustafa Baiou
2020-11-09 01:42:08 -05:00
committed by moustafab
parent 99fffed216
commit 4639d20720
15 changed files with 74 additions and 90 deletions
@@ -15,13 +15,13 @@
*/
import { KubernetesAuthTranslator } from './types';
import { AuthRequestBody, ClusterDetails } from '../types/types';
import { KubernetesRequestBody, ClusterDetails } from '../types/types';
export class GoogleKubernetesAuthTranslator
implements KubernetesAuthTranslator {
async decorateClusterDetailsWithAuth(
clusterDetails: ClusterDetails,
requestBody: AuthRequestBody,
requestBody: KubernetesRequestBody,
): Promise<ClusterDetails> {
const clusterDetailsWithAuthToken: ClusterDetails = Object.assign(
{},
@@ -15,7 +15,7 @@
*/
import { KubernetesAuthTranslator } from './types';
import { AuthRequestBody, ClusterDetails } from '../types/types';
import { KubernetesRequestBody, ClusterDetails } from '../types/types';
export class ServiceAccountKubernetesAuthTranslator
implements KubernetesAuthTranslator {
@@ -23,7 +23,7 @@ export class ServiceAccountKubernetesAuthTranslator
clusterDetails: ClusterDetails,
// To ignore TS6133 linting error where it detects 'requestBody' is declared but its value is never read.
// @ts-ignore-start
requestBody: AuthRequestBody, // eslint-disable-line @typescript-eslint/no-unused-vars
requestBody: KubernetesRequestBody, // eslint-disable-line @typescript-eslint/no-unused-vars
// @ts-ignore-end
): Promise<ClusterDetails> {
return clusterDetails;
@@ -14,11 +14,11 @@
* limitations under the License.
*/
import { AuthRequestBody, ClusterDetails } from '../types/types';
import { KubernetesRequestBody, ClusterDetails } from '../types/types';
export interface KubernetesAuthTranslator {
decorateClusterDetailsWithAuth(
clusterDetails: ClusterDetails,
requestBody: AuthRequestBody,
requestBody: KubernetesRequestBody,
): Promise<ClusterDetails>;
}
@@ -91,7 +91,6 @@ describe('handleGetKubernetesObjectsForService', () => {
},
getVoidLogger(),
{},
'',
);
expect(getClustersByServiceId.mock.calls.length).toBe(1);
@@ -16,25 +16,25 @@
import { Logger } from 'winston';
import {
AuthRequestBody,
KubernetesRequestBody,
ClusterDetails,
KubernetesServiceLocator,
KubernetesFetcher,
KubernetesObjectTypes,
ObjectsByServiceIdResponse,
ObjectsByEntityResponse,
} from '../types/types';
import { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';
import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';
import { ComponentEntityV1alpha1 } from '@backstage/catalog-model';
export type GetKubernetesObjectsForServiceHandler = (
serviceId: string,
fetcher: KubernetesFetcher,
serviceLocator: KubernetesServiceLocator,
logger: Logger,
requestBody: AuthRequestBody,
labelSelector: string,
requestBody: KubernetesRequestBody,
objectsToFetch?: Set<KubernetesObjectTypes>,
) => Promise<ObjectsByServiceIdResponse>;
) => Promise<ObjectsByEntityResponse>;
const DEFAULT_OBJECTS = new Set<KubernetesObjectTypes>([
'pods',
@@ -46,6 +46,26 @@ const DEFAULT_OBJECTS = new Set<KubernetesObjectTypes>([
'ingresses',
]);
function parseLabelSelector(entity: ComponentEntityV1alpha1): string {
if (
entity &&
entity.spec &&
entity.spec.kubernetes &&
entity.spec.kubernetes.selector
) {
// TODO: figure out how to convert the selector to the full query param from the yaml
// (as shown here https://github.com/kubernetes/apimachinery/blob/master/pkg/labels/selector.go)
const { matchLabels } = entity.spec.kubernetes.selector;
if (!matchLabels) {
return '';
}
return Object.keys(matchLabels)
.map(key => `${key}=${matchLabels[key.toString()]}`)
.join(',');
}
return '';
}
// Fans out the request to all clusters that the service lives in, aggregates their responses together
export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServiceHandler = async (
serviceId,
@@ -53,7 +73,6 @@ export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServic
serviceLocator,
logger,
requestBody,
labelSelector: string,
objectsToFetch = DEFAULT_OBJECTS,
) => {
const clusterDetails: ClusterDetails[] = await serviceLocator.getClustersByServiceId(
@@ -80,6 +99,8 @@ export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServic
.join(', ')}]`,
);
const labelSelector = parseLabelSelector(requestBody.entity);
return Promise.all(
clusterDetailsDecoratedForAuth.map(cd => {
return fetcher
@@ -21,14 +21,14 @@ import { makeRouter } from './router';
import {
KubernetesServiceLocator,
KubernetesFetcher,
ObjectsByServiceIdResponse,
ObjectsByEntityResponse,
} from '..';
describe('router', () => {
let app: express.Express;
let kubernetesFetcher: jest.Mocked<KubernetesFetcher>;
let kubernetesServiceLocator: jest.Mocked<KubernetesServiceLocator>;
let handleGetByServiceId: jest.Mock<Promise<ObjectsByServiceIdResponse>>;
let handleGetByServiceId: jest.Mock<Promise<ObjectsByEntityResponse>>;
beforeAll(async () => {
kubernetesFetcher = {
@@ -26,7 +26,7 @@ import {
handleGetKubernetesObjectsForService,
} from './getKubernetesObjectsForServiceHandler';
import {
AuthRequestBody,
KubernetesRequestBody,
KubernetesServiceLocator,
KubernetesFetcher,
ServiceLocatorMethod,
@@ -64,23 +64,21 @@ export const makeRouter = (
logger: Logger,
fetcher: KubernetesFetcher,
serviceLocator: KubernetesServiceLocator,
handleGetByServiceId: GetKubernetesObjectsForServiceHandler,
handleGetByEntity: 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;
const requestBody: KubernetesRequestBody = req.body;
try {
const response = await handleGetByServiceId(
const response = await handleGetByEntity(
serviceId,
fetcher,
serviceLocator,
logger,
requestBody,
labelSelector ? labelSelector.toString() : '',
);
res.send(response);
} catch (e) {
@@ -23,6 +23,7 @@ import {
V1ReplicaSet,
V1Service,
} from '@kubernetes/client-node';
import { ComponentEntityV1alpha1 } from '@backstage/catalog-model';
export interface ClusterDetails {
name: string;
@@ -31,10 +32,11 @@ export interface ClusterDetails {
serviceAccountToken?: string | undefined;
}
export interface AuthRequestBody {
export interface KubernetesRequestBody {
auth?: {
google?: string;
};
entity: ComponentEntityV1alpha1;
}
export interface ClusterObjects {
@@ -43,7 +45,7 @@ export interface ClusterObjects {
errors: KubernetesFetchError[];
}
export interface ObjectsByServiceIdResponse {
export interface ObjectsByEntityResponse {
items: ClusterObjects[];
}