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';