Merge pull request #12821 from andmagom/master
[Kubernetes plugin] CRDs are configurable per cluster
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
---
|
||||
|
||||
Added a new `customResources` field to the ClusterDetails interface, in order to specify (override) custom resources per cluster
|
||||
@@ -31,6 +31,10 @@ kubernetes:
|
||||
dashboardUrl: http://127.0.0.1:64713 # url copied from running the command: minikube service kubernetes-dashboard -n kubernetes-dashboard
|
||||
dashboardApp: standard
|
||||
caData: ${K8S_CONFIG_CA_DATA}
|
||||
customResources:
|
||||
- group: 'argoproj.io'
|
||||
apiVersion: 'v1alpha1'
|
||||
plural: 'rollouts'
|
||||
- url: http://127.0.0.2:9999
|
||||
name: aws-cluster-1
|
||||
authProvider: 'aws'
|
||||
@@ -254,6 +258,11 @@ See also
|
||||
https://cloud.google.com/kubernetes-engine/docs/how-to/api-server-authentication#environments-without-gcloud
|
||||
for complete docs about GKE without `gcloud`.
|
||||
|
||||
##### `clusters.\*.customResources` (optional)
|
||||
|
||||
Configures which [custom resources][3] to look for when returning an entity's
|
||||
Kubernetes resources belonging to the cluster. Same specification as [`customResources`](#customresources-optional)
|
||||
|
||||
#### `gke`
|
||||
|
||||
This cluster locator is designed to work with Kubernetes clusters running in
|
||||
@@ -327,9 +336,13 @@ it is also possible to implement a
|
||||
|
||||
### `customResources` (optional)
|
||||
|
||||
Configures which [custom resources][3] to look for when returning an entity's
|
||||
Configures which [custom resources][3] to look for by default when returning an entity's
|
||||
Kubernetes resources.
|
||||
|
||||
**Notes:**
|
||||
|
||||
- The optional `kubernetes.customResources` property is overrode by `customResources` at the [clusters level](#clusterscustomresources-optional).
|
||||
|
||||
Defaults to empty array. Example:
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface ClusterDetails {
|
||||
authProvider: string;
|
||||
// (undocumented)
|
||||
caData?: string | undefined;
|
||||
customResources?: CustomResourceMatcher[];
|
||||
dashboardApp?: string;
|
||||
dashboardParameters?: JsonObject;
|
||||
dashboardUrl?: string;
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { ClusterDetails, ObjectFetchParams } from '../types/types';
|
||||
import {
|
||||
ClusterDetails,
|
||||
CustomResource,
|
||||
ObjectFetchParams,
|
||||
} from '../types/types';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
import { PodStatus } from '@kubernetes/client-node/dist/top';
|
||||
|
||||
@@ -56,6 +60,108 @@ const mockMetrics = (mock: jest.Mock) => {
|
||||
);
|
||||
};
|
||||
|
||||
const entity = {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
};
|
||||
|
||||
const cluster1 = {
|
||||
name: 'test-cluster',
|
||||
authProvider: 'serviceAccount',
|
||||
customResources: [
|
||||
{
|
||||
group: 'some-other-crd.example.com',
|
||||
apiVersion: 'v1alpha1',
|
||||
plural: 'some-crd-only-on-this-cluster',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const cluster2 = {
|
||||
name: 'cluster-two',
|
||||
authProvider: 'serviceAccount',
|
||||
customResources: [
|
||||
{
|
||||
group: 'crd-two.example.com',
|
||||
apiVersion: 'v1alpha1',
|
||||
plural: 'crd-two-plural',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function resourcesByCluster(clusterName: string) {
|
||||
return [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: `my-pods-test-component-${clusterName}`,
|
||||
namespace: `ns-test-component-${clusterName}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: `my-configmaps-test-component-${clusterName}`,
|
||||
namespace: `ns-test-component-${clusterName}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: `my-services-test-component-${clusterName}`,
|
||||
namespace: `ns-test-component-${clusterName}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function mockFetchAndGetKubernetesFanOutHandler(
|
||||
customResources: CustomResource[],
|
||||
) {
|
||||
mockFetch(fetchObjectsForService);
|
||||
mockMetrics(fetchPodMetricsByNamespace);
|
||||
|
||||
return getKubernetesFanOutHandler(customResources);
|
||||
}
|
||||
|
||||
function getKubernetesFanOutHandler(customResources: CustomResource[]) {
|
||||
return new KubernetesFanOutHandler({
|
||||
logger: getVoidLogger(),
|
||||
fetcher: {
|
||||
fetchObjectsForService,
|
||||
fetchPodMetricsByNamespace,
|
||||
},
|
||||
serviceLocator: {
|
||||
getClustersByEntity,
|
||||
},
|
||||
customResources: customResources,
|
||||
});
|
||||
}
|
||||
|
||||
function generatePodStatus(
|
||||
_clusterName: string,
|
||||
_namespace: string,
|
||||
@@ -160,7 +266,7 @@ function generateMockResourcesAndErrors(
|
||||
};
|
||||
}
|
||||
|
||||
describe('handleGetKubernetesObjectsForService', () => {
|
||||
describe('getKubernetesObjectsByEntity', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
@@ -177,38 +283,10 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
mockFetch(fetchObjectsForService);
|
||||
mockMetrics(fetchPodMetricsByNamespace);
|
||||
|
||||
const sut = new KubernetesFanOutHandler({
|
||||
logger: getVoidLogger(),
|
||||
fetcher: {
|
||||
fetchObjectsForService,
|
||||
fetchPodMetricsByNamespace,
|
||||
},
|
||||
serviceLocator: {
|
||||
getClustersByEntity,
|
||||
},
|
||||
customResources: [],
|
||||
});
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([]);
|
||||
|
||||
const result = await sut.getKubernetesObjectsByEntity({
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
},
|
||||
entity,
|
||||
auth: {},
|
||||
});
|
||||
|
||||
@@ -227,46 +305,91 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
errors: [],
|
||||
podMetrics: [POD_METRICS_FIXTURE],
|
||||
resources: [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
],
|
||||
resources: resourcesByCluster('test-cluster'),
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('retrieve objects for one cluster using customResources per cluster', async () => {
|
||||
getClustersByEntity.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
clusters: [cluster1],
|
||||
}),
|
||||
);
|
||||
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([]);
|
||||
|
||||
await sut.getKubernetesObjectsByEntity({
|
||||
entity,
|
||||
auth: {},
|
||||
});
|
||||
|
||||
expect(fetchObjectsForService.mock.calls.length).toBe(1);
|
||||
expect(fetchObjectsForService.mock.calls[0][0].customResources.length).toBe(
|
||||
1,
|
||||
);
|
||||
});
|
||||
|
||||
it('retrieve objects for two cluster using customResources per cluster', async () => {
|
||||
getClustersByEntity.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
clusters: [cluster1, cluster2],
|
||||
}),
|
||||
);
|
||||
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([]);
|
||||
|
||||
await sut.getKubernetesObjectsByEntity({
|
||||
entity,
|
||||
auth: {},
|
||||
});
|
||||
|
||||
expect(fetchObjectsForService.mock.calls.length).toBe(2);
|
||||
expect(
|
||||
fetchObjectsForService.mock.calls[0][0].customResources[0].group,
|
||||
).toBe('some-other-crd.example.com');
|
||||
expect(
|
||||
fetchObjectsForService.mock.calls[1][0].customResources[0].group,
|
||||
).toBe('crd-two.example.com');
|
||||
});
|
||||
|
||||
it('retrieve objects for two cluster using customResources globally and per cluster', async () => {
|
||||
getClustersByEntity.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
clusters: [
|
||||
{
|
||||
name: 'test-cluster',
|
||||
authProvider: 'serviceAccount',
|
||||
},
|
||||
cluster2,
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([
|
||||
{
|
||||
objectType: 'customresources',
|
||||
group: 'some-group',
|
||||
apiVersion: 'v2',
|
||||
plural: 'things',
|
||||
},
|
||||
]);
|
||||
|
||||
await sut.getKubernetesObjectsByEntity({
|
||||
entity,
|
||||
auth: {},
|
||||
});
|
||||
|
||||
expect(fetchObjectsForService.mock.calls.length).toBe(2);
|
||||
expect(
|
||||
fetchObjectsForService.mock.calls[0][0].customResources[0].group,
|
||||
).toBe('some-group');
|
||||
expect(
|
||||
fetchObjectsForService.mock.calls[1][0].customResources[0].group,
|
||||
).toBe('crd-two.example.com');
|
||||
});
|
||||
|
||||
it('dont call top for the same namespace twice', async () => {
|
||||
getClustersByEntity.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
@@ -312,35 +435,10 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
|
||||
mockMetrics(fetchPodMetricsByNamespace);
|
||||
|
||||
const sut = new KubernetesFanOutHandler({
|
||||
logger: getVoidLogger(),
|
||||
fetcher: {
|
||||
fetchObjectsForService,
|
||||
fetchPodMetricsByNamespace,
|
||||
},
|
||||
serviceLocator: {
|
||||
getClustersByEntity,
|
||||
},
|
||||
customResources: [],
|
||||
});
|
||||
const sut = getKubernetesFanOutHandler([]);
|
||||
|
||||
const result = await sut.getKubernetesObjectsByEntity({
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
},
|
||||
entity,
|
||||
auth: {},
|
||||
});
|
||||
|
||||
@@ -405,38 +503,10 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
mockFetch(fetchObjectsForService);
|
||||
mockMetrics(fetchPodMetricsByNamespace);
|
||||
|
||||
const sut = new KubernetesFanOutHandler({
|
||||
logger: getVoidLogger(),
|
||||
fetcher: {
|
||||
fetchObjectsForService,
|
||||
fetchPodMetricsByNamespace,
|
||||
},
|
||||
serviceLocator: {
|
||||
getClustersByEntity,
|
||||
},
|
||||
customResources: [],
|
||||
});
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([]);
|
||||
|
||||
const result = await sut.getKubernetesObjectsByEntity({
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
},
|
||||
entity,
|
||||
auth: {
|
||||
google: 'google_token_123',
|
||||
},
|
||||
@@ -453,41 +523,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
errors: [],
|
||||
podMetrics: [POD_METRICS_FIXTURE],
|
||||
resources: [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
],
|
||||
resources: resourcesByCluster('test-cluster'),
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
@@ -495,41 +531,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
errors: [],
|
||||
podMetrics: [POD_METRICS_FIXTURE],
|
||||
resources: [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
],
|
||||
resources: resourcesByCluster('other-cluster'),
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -554,38 +556,10 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
mockFetch(fetchObjectsForService);
|
||||
mockMetrics(fetchPodMetricsByNamespace);
|
||||
|
||||
const sut = new KubernetesFanOutHandler({
|
||||
logger: getVoidLogger(),
|
||||
fetcher: {
|
||||
fetchObjectsForService,
|
||||
fetchPodMetricsByNamespace,
|
||||
},
|
||||
serviceLocator: {
|
||||
getClustersByEntity,
|
||||
},
|
||||
customResources: [],
|
||||
});
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([]);
|
||||
|
||||
const result = await sut.getKubernetesObjectsByEntity({
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
},
|
||||
entity,
|
||||
auth: {
|
||||
google: 'google_token_123',
|
||||
},
|
||||
@@ -601,41 +575,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
errors: [],
|
||||
podMetrics: [POD_METRICS_FIXTURE],
|
||||
resources: [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
],
|
||||
resources: resourcesByCluster('test-cluster'),
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
@@ -643,41 +583,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
errors: [],
|
||||
podMetrics: [POD_METRICS_FIXTURE],
|
||||
resources: [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
],
|
||||
resources: resourcesByCluster('other-cluster'),
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -706,38 +612,10 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
mockFetch(fetchObjectsForService);
|
||||
mockMetrics(fetchPodMetricsByNamespace);
|
||||
|
||||
const sut = new KubernetesFanOutHandler({
|
||||
logger: getVoidLogger(),
|
||||
fetcher: {
|
||||
fetchObjectsForService,
|
||||
fetchPodMetricsByNamespace,
|
||||
},
|
||||
serviceLocator: {
|
||||
getClustersByEntity,
|
||||
},
|
||||
customResources: [],
|
||||
});
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([]);
|
||||
|
||||
const result = await sut.getKubernetesObjectsByEntity({
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
},
|
||||
entity,
|
||||
auth: {
|
||||
google: 'google_token_123',
|
||||
},
|
||||
@@ -753,41 +631,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
errors: [],
|
||||
podMetrics: [POD_METRICS_FIXTURE],
|
||||
resources: [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-test-component-test-cluster',
|
||||
namespace: 'ns-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
],
|
||||
resources: resourcesByCluster('test-cluster'),
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
@@ -795,41 +639,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
errors: [],
|
||||
podMetrics: [POD_METRICS_FIXTURE],
|
||||
resources: [
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'pods',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'configmaps',
|
||||
},
|
||||
{
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-test-component-other-cluster',
|
||||
namespace: 'ns-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'services',
|
||||
},
|
||||
],
|
||||
resources: resourcesByCluster('other-cluster'),
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
@@ -856,3 +666,79 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomResourcesByEntity', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('retrieve objects for one cluster using customResources per cluster', async () => {
|
||||
getClustersByEntity.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
clusters: [cluster1],
|
||||
}),
|
||||
);
|
||||
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([]);
|
||||
|
||||
await sut.getCustomResourcesByEntity({
|
||||
entity,
|
||||
auth: {},
|
||||
customResources: [
|
||||
{
|
||||
group: 'parameter-crd.example.com',
|
||||
apiVersion: 'v1alpha1',
|
||||
plural: 'parameter-crd',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(fetchObjectsForService.mock.calls.length).toBe(1);
|
||||
expect(
|
||||
fetchObjectsForService.mock.calls[0][0].customResources[0].plural,
|
||||
).toBe('parameter-crd');
|
||||
});
|
||||
|
||||
it('retrieve objects for two cluster using customResources globally and per cluster', async () => {
|
||||
getClustersByEntity.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
clusters: [
|
||||
{
|
||||
name: 'test-cluster',
|
||||
authProvider: 'serviceAccount',
|
||||
},
|
||||
cluster2,
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
const sut = mockFetchAndGetKubernetesFanOutHandler([
|
||||
{
|
||||
objectType: 'customresources',
|
||||
group: 'some-group',
|
||||
apiVersion: 'v2',
|
||||
plural: 'things',
|
||||
},
|
||||
]);
|
||||
|
||||
await sut.getCustomResourcesByEntity({
|
||||
entity,
|
||||
auth: {},
|
||||
customResources: [
|
||||
{
|
||||
group: 'parameter-crd.example.com',
|
||||
apiVersion: 'v1alpha1',
|
||||
plural: 'parameter-crd',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(fetchObjectsForService.mock.calls.length).toBe(2);
|
||||
expect(
|
||||
fetchObjectsForService.mock.calls[0][0].customResources[0].group,
|
||||
).toBe('parameter-crd.example.com');
|
||||
expect(
|
||||
fetchObjectsForService.mock.calls[1][0].customResources[0].group,
|
||||
).toBe('parameter-crd.example.com');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -211,19 +211,14 @@ export class KubernetesFanOutHandler {
|
||||
entity,
|
||||
auth,
|
||||
}: KubernetesObjectsByEntity): Promise<ObjectsByEntityResponse> {
|
||||
return this.fanOutRequests(
|
||||
entity,
|
||||
auth,
|
||||
this.objectTypesToFetch,
|
||||
this.customResources,
|
||||
);
|
||||
return this.fanOutRequests(entity, auth, this.objectTypesToFetch);
|
||||
}
|
||||
|
||||
private async fanOutRequests(
|
||||
entity: Entity,
|
||||
auth: KubernetesRequestAuth,
|
||||
objectTypesToFetch: Set<ObjectToFetch>,
|
||||
customResources: CustomResourceMatcher[],
|
||||
customResources?: CustomResourceMatcher[],
|
||||
) {
|
||||
const entityName =
|
||||
entity.metadata?.annotations?.['backstage.io/kubernetes-id'] ||
|
||||
@@ -254,7 +249,11 @@ export class KubernetesFanOutHandler {
|
||||
clusterDetails: clusterDetailsItem,
|
||||
objectTypesToFetch: objectTypesToFetch,
|
||||
labelSelector,
|
||||
customResources: customResources.map(c => ({
|
||||
customResources: (
|
||||
customResources ||
|
||||
clusterDetailsItem.customResources ||
|
||||
this.customResources
|
||||
).map(c => ({
|
||||
...c,
|
||||
objectType: 'customresources',
|
||||
})),
|
||||
|
||||
@@ -193,6 +193,11 @@ export interface ClusterDetails {
|
||||
* @see dashboardApp
|
||||
*/
|
||||
dashboardParameters?: JsonObject;
|
||||
/**
|
||||
* Specifies which custom resources to look for when returning an entity's
|
||||
* Kubernetes resources.
|
||||
*/
|
||||
customResources?: CustomResourceMatcher[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user