minor refactorings after code review
Signed-off-by: Morgan Martinet <morgan@mmm-experts.com>
This commit is contained in:
committed by
Morgan Martinet
parent
891d2bec18
commit
c80f53a4b5
@@ -1,7 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': minor
|
||||
'@backstage/plugin-kubernetes-backend': minor
|
||||
'@backstage/plugin-kubernetes-common': minor
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
'@backstage/plugin-kubernetes-common': patch
|
||||
---
|
||||
|
||||
Provide access to the Kubernetes dashboard when viewing a specific resource
|
||||
|
||||
@@ -49,7 +49,6 @@ describe('ConfigClusterLocator', () => {
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
name: 'cluster1',
|
||||
dashboardUrl: undefined,
|
||||
serviceAccountToken: undefined,
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
@@ -93,7 +92,6 @@ describe('ConfigClusterLocator', () => {
|
||||
},
|
||||
{
|
||||
name: 'cluster2',
|
||||
dashboardUrl: undefined,
|
||||
serviceAccountToken: undefined,
|
||||
url: 'http://localhost:8081',
|
||||
authProvider: 'google',
|
||||
@@ -137,7 +135,6 @@ describe('ConfigClusterLocator', () => {
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
assumeRole: undefined,
|
||||
dashboardUrl: undefined,
|
||||
name: 'cluster1',
|
||||
serviceAccountToken: 'token',
|
||||
externalId: undefined,
|
||||
@@ -147,7 +144,6 @@ describe('ConfigClusterLocator', () => {
|
||||
},
|
||||
{
|
||||
assumeRole: 'SomeRole',
|
||||
dashboardUrl: undefined,
|
||||
name: 'cluster2',
|
||||
externalId: undefined,
|
||||
serviceAccountToken: undefined,
|
||||
|
||||
@@ -30,14 +30,17 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier {
|
||||
return new ConfigClusterLocator(
|
||||
config.getConfigArray('clusters').map(c => {
|
||||
const authProvider = c.getString('authProvider');
|
||||
const clusterDetails = {
|
||||
const clusterDetails: ClusterDetails = {
|
||||
name: c.getString('name'),
|
||||
url: c.getString('url'),
|
||||
dashboardUrl: c.getOptionalString('dashboardUrl'),
|
||||
serviceAccountToken: c.getOptionalString('serviceAccountToken'),
|
||||
skipTLSVerify: c.getOptionalBoolean('skipTLSVerify') ?? false,
|
||||
authProvider: authProvider,
|
||||
};
|
||||
const dashboardUrl = c.getOptionalString('dashboardUrl');
|
||||
if (dashboardUrl) {
|
||||
clusterDetails.dashboardUrl = dashboardUrl;
|
||||
}
|
||||
|
||||
switch (authProvider) {
|
||||
case 'google': {
|
||||
|
||||
@@ -50,7 +50,6 @@ describe('getCombinedClusterDetails', () => {
|
||||
expect(result).toStrictEqual([
|
||||
{
|
||||
name: 'cluster1',
|
||||
dashboardUrl: undefined,
|
||||
serviceAccountToken: 'token',
|
||||
url: 'http://localhost:8080',
|
||||
authProvider: 'serviceAccount',
|
||||
@@ -58,7 +57,6 @@ describe('getCombinedClusterDetails', () => {
|
||||
},
|
||||
{
|
||||
name: 'cluster2',
|
||||
dashboardUrl: undefined,
|
||||
serviceAccountToken: undefined,
|
||||
url: 'http://localhost:8081',
|
||||
authProvider: 'google',
|
||||
|
||||
@@ -165,7 +165,6 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
items: [
|
||||
{
|
||||
cluster: {
|
||||
dashboardUrl: undefined,
|
||||
name: 'test-cluster',
|
||||
},
|
||||
errors: [],
|
||||
@@ -301,7 +300,6 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
dashboardUrl: undefined,
|
||||
name: 'other-cluster',
|
||||
},
|
||||
errors: [],
|
||||
@@ -400,7 +398,6 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
items: [
|
||||
{
|
||||
cluster: {
|
||||
dashboardUrl: undefined,
|
||||
name: 'test-cluster',
|
||||
},
|
||||
errors: [],
|
||||
@@ -439,7 +436,6 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
dashboardUrl: undefined,
|
||||
name: 'other-cluster',
|
||||
},
|
||||
errors: [],
|
||||
@@ -542,7 +538,6 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
items: [
|
||||
{
|
||||
cluster: {
|
||||
dashboardUrl: undefined,
|
||||
name: 'test-cluster',
|
||||
},
|
||||
errors: [],
|
||||
@@ -581,7 +576,6 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
dashboardUrl: undefined,
|
||||
name: 'other-cluster',
|
||||
},
|
||||
errors: [],
|
||||
@@ -620,7 +614,6 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
},
|
||||
{
|
||||
cluster: {
|
||||
dashboardUrl: undefined,
|
||||
name: 'error-cluster',
|
||||
},
|
||||
errors: ['some random cluster error'],
|
||||
|
||||
@@ -22,7 +22,10 @@ import {
|
||||
KubernetesObjectTypes,
|
||||
KubernetesServiceLocator,
|
||||
} from '../types/types';
|
||||
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
|
||||
import {
|
||||
ClusterObjects,
|
||||
KubernetesRequestBody,
|
||||
} from '@backstage/plugin-kubernetes-common';
|
||||
import { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';
|
||||
import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';
|
||||
|
||||
@@ -111,14 +114,17 @@ export class KubernetesFanOutHandler {
|
||||
customResources: this.customResources,
|
||||
})
|
||||
.then(result => {
|
||||
return {
|
||||
const objects: ClusterObjects = {
|
||||
cluster: {
|
||||
name: clusterDetailsItem.name,
|
||||
dashboardUrl: clusterDetailsItem.dashboardUrl,
|
||||
},
|
||||
resources: result.responses,
|
||||
errors: result.errors,
|
||||
};
|
||||
if (clusterDetailsItem.dashboardUrl) {
|
||||
objects.cluster.dashboardUrl = clusterDetailsItem.dashboardUrl;
|
||||
}
|
||||
return objects;
|
||||
});
|
||||
}),
|
||||
).then(r => ({
|
||||
|
||||
@@ -34,6 +34,7 @@ import jsYaml from 'js-yaml';
|
||||
import {
|
||||
CodeSnippet,
|
||||
StructuredMetadataTable,
|
||||
Link,
|
||||
} from '@backstage/core-components';
|
||||
import { ClusterContext } from '../../hooks';
|
||||
import { formatClusterLink } from '../../utils/clusterLinks';
|
||||
@@ -108,11 +109,11 @@ const KubernetesDrawerContent = <T extends KubernetesDrawerable>({
|
||||
|
||||
const classes = useDrawerContentStyles();
|
||||
const cluster = useContext(ClusterContext);
|
||||
const clusterLink = formatClusterLink(
|
||||
cluster.dashboardUrl ?? '',
|
||||
const clusterLink = formatClusterLink({
|
||||
dashboardUrl: cluster.dashboardUrl,
|
||||
object,
|
||||
kind,
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -150,8 +151,8 @@ const KubernetesDrawerContent = <T extends KubernetesDrawerable>({
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="small"
|
||||
href={clusterLink}
|
||||
target="_blank"
|
||||
component={Link}
|
||||
to={clusterLink}
|
||||
>
|
||||
Open Kubernetes Dashboard...
|
||||
</Button>
|
||||
|
||||
@@ -19,94 +19,98 @@ import { formatClusterLink } from './clusterLinks';
|
||||
describe('clusterLinks', () => {
|
||||
describe('formatClusterLink', () => {
|
||||
it('should not return an url when there is no dashboard url', () => {
|
||||
const url = formatClusterLink('', {}, 'foo');
|
||||
const url = formatClusterLink({ object: {}, kind: 'foo' });
|
||||
expect(url).toBeUndefined();
|
||||
});
|
||||
it('should return an url even when there is no object', () => {
|
||||
const url = formatClusterLink('https://k8s.foo.com', undefined, 'foo');
|
||||
const url = formatClusterLink({
|
||||
dashboardUrl: 'https://k8s.foo.com',
|
||||
object: undefined,
|
||||
kind: 'foo',
|
||||
});
|
||||
expect(url).toBe('https://k8s.foo.com');
|
||||
});
|
||||
it('should return an url on the workloads when there is a namespace only', () => {
|
||||
const url = formatClusterLink(
|
||||
'https://k8s.foo.com',
|
||||
{
|
||||
const url = formatClusterLink({
|
||||
dashboardUrl: 'https://k8s.foo.com',
|
||||
object: {
|
||||
metadata: {
|
||||
namespace: 'bar',
|
||||
},
|
||||
},
|
||||
'foo',
|
||||
);
|
||||
kind: 'foo',
|
||||
});
|
||||
expect(url).toBe('https://k8s.foo.com/#/workloads?namespace=bar');
|
||||
});
|
||||
it('should return an url on the workloads when the kind is not recognizeed', () => {
|
||||
const url = formatClusterLink(
|
||||
'https://k8s.foo.com',
|
||||
{
|
||||
const url = formatClusterLink({
|
||||
dashboardUrl: 'https://k8s.foo.com',
|
||||
object: {
|
||||
metadata: {
|
||||
name: 'foobar',
|
||||
namespace: 'bar',
|
||||
},
|
||||
},
|
||||
'UnknownKind',
|
||||
);
|
||||
kind: 'UnknownKind',
|
||||
});
|
||||
expect(url).toBe('https://k8s.foo.com/#/workloads?namespace=bar');
|
||||
});
|
||||
it('should return an url on the deployment', () => {
|
||||
const url = formatClusterLink(
|
||||
'https://k8s.foo.com/',
|
||||
{
|
||||
const url = formatClusterLink({
|
||||
dashboardUrl: 'https://k8s.foo.com/',
|
||||
object: {
|
||||
metadata: {
|
||||
name: 'foobar',
|
||||
namespace: 'bar',
|
||||
},
|
||||
},
|
||||
'Deployment',
|
||||
);
|
||||
kind: 'Deployment',
|
||||
});
|
||||
expect(url).toBe(
|
||||
'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar',
|
||||
);
|
||||
});
|
||||
it('should return an url on the service', () => {
|
||||
const url = formatClusterLink(
|
||||
'https://k8s.foo.com/',
|
||||
{
|
||||
const url = formatClusterLink({
|
||||
dashboardUrl: 'https://k8s.foo.com/',
|
||||
object: {
|
||||
metadata: {
|
||||
name: 'foobar',
|
||||
namespace: 'bar',
|
||||
},
|
||||
},
|
||||
'Service',
|
||||
);
|
||||
kind: 'Service',
|
||||
});
|
||||
expect(url).toBe(
|
||||
'https://k8s.foo.com/#/service/bar/foobar?namespace=bar',
|
||||
);
|
||||
});
|
||||
it('should return an url on the ingress', () => {
|
||||
const url = formatClusterLink(
|
||||
'https://k8s.foo.com/',
|
||||
{
|
||||
const url = formatClusterLink({
|
||||
dashboardUrl: 'https://k8s.foo.com/',
|
||||
object: {
|
||||
metadata: {
|
||||
name: 'foobar',
|
||||
namespace: 'bar',
|
||||
},
|
||||
},
|
||||
'Ingress',
|
||||
);
|
||||
kind: 'Ingress',
|
||||
});
|
||||
expect(url).toBe(
|
||||
'https://k8s.foo.com/#/ingress/bar/foobar?namespace=bar',
|
||||
);
|
||||
});
|
||||
it('should return an url on the deployment for a hpa', () => {
|
||||
const url = formatClusterLink(
|
||||
'https://k8s.foo.com/',
|
||||
{
|
||||
const url = formatClusterLink({
|
||||
dashboardUrl: 'https://k8s.foo.com/',
|
||||
object: {
|
||||
metadata: {
|
||||
name: 'foobar',
|
||||
namespace: 'bar',
|
||||
},
|
||||
},
|
||||
'HorizontalPodAutoscaler',
|
||||
);
|
||||
kind: 'HorizontalPodAutoscaler',
|
||||
});
|
||||
expect(url).toBe(
|
||||
'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar',
|
||||
);
|
||||
|
||||
@@ -14,33 +14,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const KindMappings: any = {
|
||||
const KindMappings: Record<string, string> = {
|
||||
deployment: 'deployment',
|
||||
ingress: 'ingress',
|
||||
service: 'service',
|
||||
horizontalpodautoscaler: 'deployment',
|
||||
};
|
||||
|
||||
export function formatClusterLink(
|
||||
dashboardUrl: string,
|
||||
object: any,
|
||||
kind: string,
|
||||
) {
|
||||
if (!dashboardUrl) {
|
||||
export function formatClusterLink(options: {
|
||||
dashboardUrl?: string;
|
||||
object: any;
|
||||
kind: string;
|
||||
}) {
|
||||
if (!options.dashboardUrl) {
|
||||
return undefined;
|
||||
}
|
||||
if (!object) {
|
||||
return dashboardUrl;
|
||||
if (!options.object) {
|
||||
return options.dashboardUrl;
|
||||
}
|
||||
const host = dashboardUrl.endsWith('/') ? dashboardUrl : `${dashboardUrl}/`;
|
||||
const name = object.metadata?.name;
|
||||
const namespace = object.metadata?.namespace;
|
||||
const validKind = KindMappings[kind.toLocaleLowerCase()];
|
||||
const host = options.dashboardUrl.endsWith('/')
|
||||
? options.dashboardUrl
|
||||
: `${options.dashboardUrl}/`;
|
||||
const name = options.object.metadata?.name;
|
||||
const namespace = options.object.metadata?.namespace;
|
||||
const validKind = KindMappings[options.kind.toLocaleLowerCase()];
|
||||
if (validKind && name && namespace) {
|
||||
return `${host}#/${validKind}/${namespace}/${name}?namespace=${namespace}`;
|
||||
return `${host}#/${encodeURIComponent(validKind)}/${encodeURIComponent(
|
||||
namespace,
|
||||
)}/${encodeURIComponent(name)}?namespace=${encodeURIComponent(namespace)}`;
|
||||
}
|
||||
if (namespace) {
|
||||
return `${host}#/workloads?namespace=${namespace}`;
|
||||
return `${host}#/workloads?namespace=${encodeURIComponent(namespace)}`;
|
||||
}
|
||||
return dashboardUrl;
|
||||
return options.dashboardUrl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user