diff --git a/.changeset/olive-zebras-itch.md b/.changeset/olive-zebras-itch.md new file mode 100644 index 0000000000..5e67673e8c --- /dev/null +++ b/.changeset/olive-zebras-itch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes': patch +--- + +Show Kubernetes Service manifests diff --git a/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx b/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx index 39e73782f1..9716616009 100644 --- a/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx +++ b/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx @@ -47,6 +47,7 @@ import { DeploymentsAccordions } from '../DeploymentsAccordions'; import { ErrorReporting } from '../ErrorReporting'; import { groupResponses } from '../../utils/response'; import { DetectedError, detectErrors } from '../../error-detection'; +import { ServicesAccordions } from '../ServicesAccordions'; type KubernetesContentProps = { entity: Entity; children?: React.ReactNode }; @@ -187,10 +188,18 @@ const Cluster = ({ clusterObjects, detectedErrors }: ClusterProps) => { /> - + + + + + + + + + diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.test.tsx b/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.test.tsx new file mode 100644 index 0000000000..d9082ff632 --- /dev/null +++ b/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.test.tsx @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import * as services from './__fixtures__/2-services.json'; +import { wrapInTestApp } from '@backstage/test-utils'; +import { ServiceDrawer } from './ServiceDrawer'; + +describe('ServiceDrawer', () => { + it('should render deployment drawer', async () => { + const { getByText, getAllByText } = render( + wrapInTestApp( + , + ), + ); + + expect(getAllByText('awesome-service-grpc')).toHaveLength(2); + expect(getAllByText('Service')).toHaveLength(2); + expect(getByText('YAML')).toBeInTheDocument(); + expect(getByText('Cluster IP')).toBeInTheDocument(); + expect(getByText('Ports')).toBeInTheDocument(); + expect(getByText('Target Port: 1997')).toBeInTheDocument(); + expect(getByText('App: awesome-service')).toBeInTheDocument(); + }); +}); diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx b/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx new file mode 100644 index 0000000000..a93a9153d9 --- /dev/null +++ b/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx @@ -0,0 +1,60 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { V1Service } from '@kubernetes/client-node'; +import { KubernetesDrawer } from '../KubernetesDrawer/KubernetesDrawer'; +import { Typography, Grid } from '@material-ui/core'; + +export const ServiceDrawer = ({ + service, + expanded, +}: { + service: V1Service; + expanded?: boolean; +}) => { + return ( + { + return { + ...service.spec, + }; + }} + > + + + + {service.metadata?.name ?? 'unknown object'} + + + + + Service + + + + + ); +}; diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.test.tsx b/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.test.tsx new file mode 100644 index 0000000000..46172b4150 --- /dev/null +++ b/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.test.tsx @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import * as twoDeployFixture from './__fixtures__/2-services.json'; +import { wrapInTestApp } from '@backstage/test-utils'; +import { ServicesAccordions } from './ServicesAccordions'; + +describe('ServicesAccordions', () => { + it('should render 2 services', async () => { + const { getByText } = render( + wrapInTestApp( + , + ), + ); + + expect(getByText('awesome-service-grpc')).toBeInTheDocument(); + expect(getByText('Type: ClusterIP')).toBeInTheDocument(); + + expect(getByText('awesome-service-pg')).toBeInTheDocument(); + expect(getByText('Type: ExternalName')).toBeInTheDocument(); + }); +}); diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.tsx b/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.tsx new file mode 100644 index 0000000000..6484f2211d --- /dev/null +++ b/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.tsx @@ -0,0 +1,123 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GroupedResponses } from '../../types/types'; +import React from 'react'; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Divider, + Grid, + Typography, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import { V1Service } from '@kubernetes/client-node'; +import { StructuredMetadataTable } from '@backstage/core'; +import { ServiceDrawer } from './ServiceDrawer'; + +type ServicesAccordionsProps = { + deploymentResources: GroupedResponses; +}; + +export const ServicesAccordions = ({ + deploymentResources, +}: ServicesAccordionsProps) => { + return ( + + {deploymentResources.services.map((service, i) => ( + + + + ))} + + ); +}; + +type ServiceAccordionProps = { + service: V1Service; +}; + +const ServiceAccordion = ({ service }: ServiceAccordionProps) => { + return ( + + }> + + + + + + + ); +}; + +type ServiceSummaryProps = { + service: V1Service; +}; + +const ServiceSummary = ({ service }: ServiceSummaryProps) => { + return ( + + + + + + + + + + + + Type: {service.spec?.type ?? '?'} + + + + ); +}; + +type ServiceCardProps = { + service: V1Service; +}; + +const ServiceCard = ({ service }: ServiceCardProps) => { + const metadata: any = {}; + + if (service.status?.loadBalancer?.ingress?.length ?? -1 > 0) { + metadata.loadbalancer = service.status?.loadBalancer; + } + + if (service.spec?.type === 'ClusterIP') { + metadata.clusterIP = service.spec.clusterIP; + } + if (service.spec?.type === 'ExternalName') { + metadata.externalName = service.spec.externalName; + } + + return ( + + ); +}; diff --git a/plugins/kubernetes/src/components/ServicesAccordions/__fixtures__/2-services.json b/plugins/kubernetes/src/components/ServicesAccordions/__fixtures__/2-services.json new file mode 100644 index 0000000000..f982ebf164 --- /dev/null +++ b/plugins/kubernetes/src/components/ServicesAccordions/__fixtures__/2-services.json @@ -0,0 +1,83 @@ +{ + "services": [ + { + "metadata": { + "annotations": { + "artifact.spinnaker.io/location": "default", + "artifact.spinnaker.io/name": "awesome-service-grpc", + "artifact.spinnaker.io/type": "kubernetes/service", + "moniker.spinnaker.io/application": "awesome-service", + "moniker.spinnaker.io/cluster": "service awesome-service-grpc" + }, + "creationTimestamp": "2021-01-04T16:35:04.000Z", + "labels": { + "app": "awesome-service", + "app.kubernetes.io/managed-by": "spinnaker", + "app.kubernetes.io/name": "awesome-service" + }, + "name": "awesome-service-grpc", + "namespace": "default", + "resourceVersion": "548901649", + "selfLink": "/api/v1/namespaces/default/services/awesome-service-grpc", + "uid": "461cdcd7-8c61-4125-91f9-e03d745f2f2c" + }, + "spec": { + "clusterIP": "None", + "ports": [ + { + "name": "grpc", + "port": 1997, + "protocol": "TCP", + "targetPort": 1997 + } + ], + "selector": { + "app": "awesome-service" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + }, + "status": { + "loadBalancer": {} + } + }, + { + "metadata": { + "annotations": { + "artifact.spinnaker.io/location": "default", + "artifact.spinnaker.io/name": "awesome-service-pg", + "artifact.spinnaker.io/type": "kubernetes/service", + "moniker.spinnaker.io/application": "awesome-service", + "moniker.spinnaker.io/cluster": "service awesome-service-pg" + }, + "creationTimestamp": "2021-01-04T16:35:02.000Z", + "labels": { + "app": "awesome-service", + "app.kubernetes.io/managed-by": "spinnaker", + "app.kubernetes.io/name": "awesome-service" + }, + "name": "awesome-service-pg", + "namespace": "default", + "resourceVersion": "548901625", + "selfLink": "/api/v1/namespaces/default/services/awesome-service-pg", + "uid": "7d7ff8f2-6caa-4888-ae55-b6d41833ab92" + }, + "spec": { + "externalName": "10.244.0.5", + "ports": [ + { + "name": "pg", + "port": 5432, + "protocol": "TCP", + "targetPort": 5432 + } + ], + "sessionAffinity": "None", + "type": "ExternalName" + }, + "status": { + "loadBalancer": {} + } + } + ] +} diff --git a/plugins/kubernetes/src/components/ServicesAccordions/index.ts b/plugins/kubernetes/src/components/ServicesAccordions/index.ts new file mode 100644 index 0000000000..a3c392c743 --- /dev/null +++ b/plugins/kubernetes/src/components/ServicesAccordions/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { ServicesAccordions } from './ServicesAccordions';