diff --git a/.changeset/two-planets-beam.md b/.changeset/two-planets-beam.md
new file mode 100644
index 0000000000..d500d22853
--- /dev/null
+++ b/.changeset/two-planets-beam.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-kubernetes-common': patch
+'@backstage/plugin-kubernetes-react': patch
+---
+
+Add support to fetch data for Daemon Sets and display an accordion in the same way as with Deployments
diff --git a/plugins/kubernetes-common/api-report.md b/plugins/kubernetes-common/api-report.md
index c1d399b196..2f46ef90e5 100644
--- a/plugins/kubernetes-common/api-report.md
+++ b/plugins/kubernetes-common/api-report.md
@@ -275,6 +275,8 @@ export interface GroupedResponses extends DeploymentResources {
// (undocumented)
customResources: any[];
// (undocumented)
+ daemonSets: V1DaemonSet[];
+ // (undocumented)
ingresses: V1Ingress[];
// (undocumented)
jobs: V1Job[];
diff --git a/plugins/kubernetes-common/src/types.ts b/plugins/kubernetes-common/src/types.ts
index cd316af089..c4bb5fd32f 100644
--- a/plugins/kubernetes-common/src/types.ts
+++ b/plugins/kubernetes-common/src/types.ts
@@ -294,4 +294,5 @@ export interface GroupedResponses extends DeploymentResources {
cronJobs: V1CronJob[];
customResources: any[];
statefulsets: V1StatefulSet[];
+ daemonSets: V1DaemonSet[];
}
diff --git a/plugins/kubernetes-common/src/util/response.ts b/plugins/kubernetes-common/src/util/response.ts
index a86d90f780..b62fa162d1 100644
--- a/plugins/kubernetes-common/src/util/response.ts
+++ b/plugins/kubernetes-common/src/util/response.ts
@@ -58,6 +58,9 @@ export const groupResponses = (
case 'statefulsets':
prev.statefulsets.push(...next.resources);
break;
+ case 'daemonsets':
+ prev.daemonSets.push(...next.resources);
+ break;
default:
}
return prev;
@@ -74,6 +77,7 @@ export const groupResponses = (
cronJobs: [],
customResources: [],
statefulsets: [],
+ daemonSets: [],
} as GroupedResponses,
);
};
diff --git a/plugins/kubernetes-react/src/__fixtures__/2-daemonsets.json b/plugins/kubernetes-react/src/__fixtures__/2-daemonsets.json
new file mode 100644
index 0000000000..1c88b9d8a7
--- /dev/null
+++ b/plugins/kubernetes-react/src/__fixtures__/2-daemonsets.json
@@ -0,0 +1,581 @@
+{
+ "daemonSets": [
+ {
+ "apiVersion": "apps/v1",
+ "kind": "DaemonSet",
+ "metadata": {
+ "annotations": {
+ "deprecated.daemonset.template.generation": "1",
+ "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"DaemonSet\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\",\"k8s-app\":\"fluentd-logging\"},\"name\":\"fluentd-elasticsearch\",\"namespace\":\"default\"},\"spec\":{\"selector\":{\"matchLabels\":{\"name\":\"fluentd-elasticsearch\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"fluentd-elasticsearch\"}},\"spec\":{\"containers\":[{\"image\":\"quay.io/fluentd_elasticsearch/fluentd:v2.5.2\",\"name\":\"fluentd-elasticsearch\",\"resources\":{\"limits\":{\"memory\":\"200Mi\"},\"requests\":{\"cpu\":\"100m\",\"memory\":\"200Mi\"}}}],\"terminationGracePeriodSeconds\":30}}}}\n"
+ },
+ "creationTimestamp": "2024-02-14T21:00:28Z",
+ "generation": 1,
+ "labels": {
+ "backstage.io/kubernetes-id": "dice-roller",
+ "k8s-app": "fluentd-logging"
+ },
+ "name": "fluentd-elasticsearch",
+ "namespace": "default",
+ "resourceVersion": "1769498",
+ "uid": "2ba243f3-a733-4b63-9db9-c9b8ce303a23"
+ },
+ "spec": {
+ "revisionHistoryLimit": 10,
+ "selector": {
+ "matchLabels": {
+ "name": "fluentd-elasticsearch"
+ }
+ },
+ "template": {
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "name": "fluentd-elasticsearch"
+ }
+ },
+ "spec": {
+ "containers": [
+ {
+ "image": "quay.io/fluentd_elasticsearch/fluentd:v2.5.2",
+ "imagePullPolicy": "IfNotPresent",
+ "name": "fluentd-elasticsearch",
+ "resources": {
+ "limits": {
+ "memory": "200Mi"
+ },
+ "requests": {
+ "cpu": "100m",
+ "memory": "200Mi"
+ }
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "terminationMessagePolicy": "File"
+ }
+ ],
+ "dnsPolicy": "ClusterFirst",
+ "restartPolicy": "Always",
+ "schedulerName": "default-scheduler",
+ "securityContext": {},
+ "terminationGracePeriodSeconds": 30
+ }
+ },
+ "updateStrategy": {
+ "rollingUpdate": {
+ "maxSurge": 0,
+ "maxUnavailable": 1
+ },
+ "type": "RollingUpdate"
+ }
+ },
+ "status": {
+ "currentNumberScheduled": 1,
+ "desiredNumberScheduled": 1,
+ "numberAvailable": 1,
+ "numberMisscheduled": 0,
+ "numberReady": 1,
+ "observedGeneration": 1,
+ "updatedNumberScheduled": 1
+ }
+ },
+ {
+ "apiVersion": "apps/v1",
+ "kind": "DaemonSet",
+ "metadata": {
+ "annotations": {
+ "deprecated.daemonset.template.generation": "1",
+ "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"DaemonSet\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\",\"k8s-app\":\"fluentd-logging\"},\"name\":\"fluentd-elasticsearch2\",\"namespace\":\"default\"},\"spec\":{\"selector\":{\"matchLabels\":{\"name\":\"fluentd-elasticsearch2\"}},\"template\":{\"metadata\":{\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\",\"name\":\"fluentd-elasticsearch2\"}},\"spec\":{\"containers\":[{\"image\":\"quay.io/fluentd_elasticsearch/fluentd:v2.5.2\",\"name\":\"fluentd-elasticsearch\",\"resources\":{\"limits\":{\"memory\":\"200Mi\"},\"requests\":{\"cpu\":\"100m\",\"memory\":\"200Mi\"}}}],\"terminationGracePeriodSeconds\":30}}}}\n"
+ },
+ "creationTimestamp": "2024-02-16T18:11:26Z",
+ "generation": 1,
+ "labels": {
+ "backstage.io/kubernetes-id": "dice-roller",
+ "k8s-app": "fluentd-logging"
+ },
+ "name": "fluentd-elasticsearch2",
+ "namespace": "default",
+ "resourceVersion": "1981736",
+ "uid": "b923d035-e9a4-4a40-9472-f0f3468f30df"
+ },
+ "spec": {
+ "revisionHistoryLimit": 10,
+ "selector": {
+ "matchLabels": {
+ "name": "fluentd-elasticsearch2"
+ }
+ },
+ "template": {
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "backstage.io/kubernetes-id": "dice-roller",
+ "name": "fluentd-elasticsearch2"
+ }
+ },
+ "spec": {
+ "containers": [
+ {
+ "image": "quay.io/fluentd_elasticsearch/fluentd:v2.5.2",
+ "imagePullPolicy": "IfNotPresent",
+ "name": "fluentd-elasticsearch",
+ "resources": {
+ "limits": {
+ "memory": "200Mi"
+ },
+ "requests": {
+ "cpu": "100m",
+ "memory": "200Mi"
+ }
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "terminationMessagePolicy": "File"
+ }
+ ],
+ "dnsPolicy": "ClusterFirst",
+ "restartPolicy": "Always",
+ "schedulerName": "default-scheduler",
+ "securityContext": {},
+ "terminationGracePeriodSeconds": 30
+ }
+ },
+ "updateStrategy": {
+ "rollingUpdate": {
+ "maxSurge": 0,
+ "maxUnavailable": 1
+ },
+ "type": "RollingUpdate"
+ }
+ },
+ "status": {
+ "currentNumberScheduled": 1,
+ "desiredNumberScheduled": 1,
+ "numberAvailable": 1,
+ "numberMisscheduled": 0,
+ "numberReady": 1,
+ "observedGeneration": 1,
+ "updatedNumberScheduled": 1
+ }
+ }
+ ],
+ "pods": [
+ {
+ "apiVersion": "v1",
+ "kind": "Pod",
+ "metadata": {
+ "creationTimestamp": "2024-02-16T16:35:06Z",
+ "generateName": "fluentd-elasticsearch-",
+ "labels": {
+ "backstage.io/kubernetes-id": "dice-roller",
+ "controller-revision-hash": "86978587c8",
+ "name": "fluentd-elasticsearch",
+ "pod-template-generation": "2"
+ },
+ "name": "fluentd-elasticsearch-mmkpf",
+ "namespace": "default",
+ "ownerReferences": [
+ {
+ "apiVersion": "apps/v1",
+ "blockOwnerDeletion": true,
+ "controller": true,
+ "kind": "DaemonSet",
+ "name": "fluentd-elasticsearch",
+ "uid": "2ba243f3-a733-4b63-9db9-c9b8ce303a23"
+ }
+ ],
+ "resourceVersion": "1970744",
+ "uid": "fc9f9070-1a3c-4e09-9cd6-8803a4ebfb0a"
+ },
+ "spec": {
+ "affinity": {
+ "nodeAffinity": {
+ "requiredDuringSchedulingIgnoredDuringExecution": {
+ "nodeSelectorTerms": [
+ {
+ "matchFields": [
+ {
+ "key": "metadata.name",
+ "operator": "In",
+ "values": ["ucp-control-plane"]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "containers": [
+ {
+ "image": "quay.io/fluentd_elasticsearch/fluentd:v2.5.2",
+ "imagePullPolicy": "IfNotPresent",
+ "name": "fluentd-elasticsearch",
+ "resources": {
+ "limits": {
+ "memory": "200Mi"
+ },
+ "requests": {
+ "cpu": "100m",
+ "memory": "200Mi"
+ }
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "terminationMessagePolicy": "File",
+ "volumeMounts": [
+ {
+ "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
+ "name": "kube-api-access-8cwbv",
+ "readOnly": true
+ }
+ ]
+ }
+ ],
+ "dnsPolicy": "ClusterFirst",
+ "enableServiceLinks": true,
+ "nodeName": "ucp-control-plane",
+ "preemptionPolicy": "PreemptLowerPriority",
+ "priority": 0,
+ "restartPolicy": "Always",
+ "schedulerName": "default-scheduler",
+ "securityContext": {},
+ "serviceAccount": "default",
+ "serviceAccountName": "default",
+ "terminationGracePeriodSeconds": 30,
+ "tolerations": [
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/not-ready",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/unreachable",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/disk-pressure",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/memory-pressure",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/pid-pressure",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/unschedulable",
+ "operator": "Exists"
+ }
+ ],
+ "volumes": [
+ {
+ "name": "kube-api-access-8cwbv",
+ "projected": {
+ "defaultMode": 420,
+ "sources": [
+ {
+ "serviceAccountToken": {
+ "expirationSeconds": 3607,
+ "path": "token"
+ }
+ },
+ {
+ "configMap": {
+ "items": [
+ {
+ "key": "ca.crt",
+ "path": "ca.crt"
+ }
+ ],
+ "name": "kube-root-ca.crt"
+ }
+ },
+ {
+ "downwardAPI": {
+ "items": [
+ {
+ "fieldRef": {
+ "apiVersion": "v1",
+ "fieldPath": "metadata.namespace"
+ },
+ "path": "namespace"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "status": {
+ "conditions": [
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T16:35:06Z",
+ "status": "True",
+ "type": "Initialized"
+ },
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T16:35:08Z",
+ "status": "True",
+ "type": "Ready"
+ },
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T16:35:08Z",
+ "status": "True",
+ "type": "ContainersReady"
+ },
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T16:35:06Z",
+ "status": "True",
+ "type": "PodScheduled"
+ }
+ ],
+ "containerStatuses": [
+ {
+ "containerID": "containerd://958e4ec14b6a3557724fabeaac9c8f8fe2ea797337a4397e700209f6e482e898",
+ "image": "quay.io/fluentd_elasticsearch/fluentd:v2.5.2",
+ "imageID": "sha256:a5bf47027e067e0376708cae10750ea154b13356dfc0209610f5ea0bc7c16fe0",
+ "lastState": {},
+ "name": "fluentd-elasticsearch",
+ "ready": true,
+ "restartCount": 0,
+ "started": true,
+ "state": {
+ "running": {
+ "startedAt": "2024-02-16T16:35:07Z"
+ }
+ }
+ }
+ ],
+ "hostIP": "172.19.0.3",
+ "phase": "Running",
+ "podIP": "10.244.0.215",
+ "podIPs": [
+ {
+ "ip": "10.244.0.215"
+ }
+ ],
+ "qosClass": "Burstable",
+ "startTime": "2024-02-16T16:35:06Z"
+ }
+ },
+ {
+ "apiVersion": "v1",
+ "kind": "Pod",
+ "metadata": {
+ "creationTimestamp": "2024-02-16T18:11:26Z",
+ "generateName": "fluentd-elasticsearch2-",
+ "labels": {
+ "backstage.io/kubernetes-id": "dice-roller",
+ "controller-revision-hash": "5979b599f6",
+ "name": "fluentd-elasticsearch2",
+ "pod-template-generation": "1"
+ },
+ "name": "fluentd-elasticsearch2-7hwwg",
+ "namespace": "default",
+ "ownerReferences": [
+ {
+ "apiVersion": "apps/v1",
+ "blockOwnerDeletion": true,
+ "controller": true,
+ "kind": "DaemonSet",
+ "name": "fluentd-elasticsearch2",
+ "uid": "b923d035-e9a4-4a40-9472-f0f3468f30df"
+ }
+ ],
+ "resourceVersion": "1981735",
+ "uid": "1b829903-2c3a-453f-a8f2-b6603eec0bbe"
+ },
+ "spec": {
+ "affinity": {
+ "nodeAffinity": {
+ "requiredDuringSchedulingIgnoredDuringExecution": {
+ "nodeSelectorTerms": [
+ {
+ "matchFields": [
+ {
+ "key": "metadata.name",
+ "operator": "In",
+ "values": ["ucp-control-plane"]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "containers": [
+ {
+ "image": "quay.io/fluentd_elasticsearch/fluentd:v2.5.2",
+ "imagePullPolicy": "IfNotPresent",
+ "name": "fluentd-elasticsearch",
+ "resources": {
+ "limits": {
+ "memory": "200Mi"
+ },
+ "requests": {
+ "cpu": "100m",
+ "memory": "200Mi"
+ }
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "terminationMessagePolicy": "File",
+ "volumeMounts": [
+ {
+ "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
+ "name": "kube-api-access-rpkbp",
+ "readOnly": true
+ }
+ ]
+ }
+ ],
+ "dnsPolicy": "ClusterFirst",
+ "enableServiceLinks": true,
+ "nodeName": "ucp-control-plane",
+ "preemptionPolicy": "PreemptLowerPriority",
+ "priority": 0,
+ "restartPolicy": "Always",
+ "schedulerName": "default-scheduler",
+ "securityContext": {},
+ "serviceAccount": "default",
+ "serviceAccountName": "default",
+ "terminationGracePeriodSeconds": 30,
+ "tolerations": [
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/not-ready",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoExecute",
+ "key": "node.kubernetes.io/unreachable",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/disk-pressure",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/memory-pressure",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/pid-pressure",
+ "operator": "Exists"
+ },
+ {
+ "effect": "NoSchedule",
+ "key": "node.kubernetes.io/unschedulable",
+ "operator": "Exists"
+ }
+ ],
+ "volumes": [
+ {
+ "name": "kube-api-access-rpkbp",
+ "projected": {
+ "defaultMode": 420,
+ "sources": [
+ {
+ "serviceAccountToken": {
+ "expirationSeconds": 3607,
+ "path": "token"
+ }
+ },
+ {
+ "configMap": {
+ "items": [
+ {
+ "key": "ca.crt",
+ "path": "ca.crt"
+ }
+ ],
+ "name": "kube-root-ca.crt"
+ }
+ },
+ {
+ "downwardAPI": {
+ "items": [
+ {
+ "fieldRef": {
+ "apiVersion": "v1",
+ "fieldPath": "metadata.namespace"
+ },
+ "path": "namespace"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "status": {
+ "conditions": [
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T18:11:27Z",
+ "status": "True",
+ "type": "Initialized"
+ },
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T18:11:28Z",
+ "status": "True",
+ "type": "Ready"
+ },
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T18:11:28Z",
+ "status": "True",
+ "type": "ContainersReady"
+ },
+ {
+ "lastProbeTime": null,
+ "lastTransitionTime": "2024-02-16T18:11:27Z",
+ "status": "True",
+ "type": "PodScheduled"
+ }
+ ],
+ "containerStatuses": [
+ {
+ "containerID": "containerd://3372cb5a300c87e5b1530b32fea7af35dce92470fc7c1cea47c714fac283feb9",
+ "image": "quay.io/fluentd_elasticsearch/fluentd:v2.5.2",
+ "imageID": "sha256:a5bf47027e067e0376708cae10750ea154b13356dfc0209610f5ea0bc7c16fe0",
+ "lastState": {},
+ "name": "fluentd-elasticsearch",
+ "ready": true,
+ "restartCount": 0,
+ "started": true,
+ "state": {
+ "running": {
+ "startedAt": "2024-02-16T18:11:28Z"
+ }
+ }
+ }
+ ],
+ "hostIP": "172.19.0.3",
+ "phase": "Running",
+ "podIP": "10.244.0.88",
+ "podIPs": [
+ {
+ "ip": "10.244.0.88"
+ }
+ ],
+ "qosClass": "Burstable",
+ "startTime": "2024-02-16T18:11:27Z"
+ }
+ }
+ ]
+}
diff --git a/plugins/kubernetes-react/src/components/Cluster/Cluster.tsx b/plugins/kubernetes-react/src/components/Cluster/Cluster.tsx
index f2108ac1b7..d713b9a873 100644
--- a/plugins/kubernetes-react/src/components/Cluster/Cluster.tsx
+++ b/plugins/kubernetes-react/src/components/Cluster/Cluster.tsx
@@ -34,6 +34,7 @@ import { IngressesAccordions } from '../IngressesAccordions';
import { ServicesAccordions } from '../ServicesAccordions';
import { CronJobsAccordions } from '../CronJobsAccordions';
import { CustomResources } from '../CustomResources';
+import { DaemonSetsAccordions } from '../DaemonSetsAccordions';
import {
ClusterContext,
GroupedResponsesContext,
@@ -151,6 +152,11 @@ export const Cluster = ({ clusterObjects, podsWithErrors }: ClusterProps) => {
) : undefined}
+ {groupedResponses.daemonSets.length > 0 ? (
+
+
+
+ ) : undefined}
{groupedResponses.statefulsets.length > 0 ? (
diff --git a/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsAccordions.test.tsx b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsAccordions.test.tsx
new file mode 100644
index 0000000000..9f38abf897
--- /dev/null
+++ b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsAccordions.test.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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 { screen } from '@testing-library/react';
+import { DaemonSetsAccordions } from './DaemonSetsAccordions';
+import * as oneDaemonsFixture from '../../__fixtures__/2-daemonsets.json';
+import { renderInTestApp } from '@backstage/test-utils';
+import { kubernetesProviders } from '../../hooks/test-utils';
+
+describe('DaemonSetsAccordions', () => {
+ it('should render two daemonset', async () => {
+ const wrapper = kubernetesProviders(oneDaemonsFixture);
+
+ await renderInTestApp(wrapper());
+
+ expect(screen.getByText('fluentd-elasticsearch')).toBeInTheDocument();
+ expect(screen.getByText('fluentd-elasticsearch2')).toBeInTheDocument();
+ });
+});
diff --git a/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsAccordions.tsx b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsAccordions.tsx
new file mode 100644
index 0000000000..834a86e837
--- /dev/null
+++ b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsAccordions.tsx
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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, { useContext } from 'react';
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Grid,
+} from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import { V1Pod, V1DaemonSet } from '@kubernetes/client-node';
+import { PodsTable } from '../Pods';
+import { DaemonSetDrawer } from './DaemonSetsDrawer';
+import { getOwnedResources } from '../../utils/owner';
+import {
+ GroupedResponsesContext,
+ PodNamesWithErrorsContext,
+} from '../../hooks';
+import { StatusError, StatusOK } from '@backstage/core-components';
+import { READY_COLUMNS, RESOURCE_COLUMNS } from '../Pods/PodsTable';
+
+type DaemonSetsAccordionsProps = {
+ children?: React.ReactNode;
+};
+
+type DaemonSetAccordionProps = {
+ daemonset: V1DaemonSet;
+ ownedPods: V1Pod[];
+ children?: React.ReactNode;
+};
+
+type DaemonSetSummaryProps = {
+ daemonset: V1DaemonSet;
+ numberOfCurrentPods: number;
+ numberOfPodsWithErrors: number;
+ children?: React.ReactNode;
+};
+
+const DaemonSetSummary = ({
+ daemonset,
+ numberOfCurrentPods,
+ numberOfPodsWithErrors,
+}: DaemonSetSummaryProps) => {
+ return (
+
+
+
+
+
+
+ {numberOfCurrentPods} pods
+
+
+ {numberOfPodsWithErrors > 0 ? (
+
+ {numberOfPodsWithErrors} pod
+ {numberOfPodsWithErrors > 1 ? 's' : ''} with errors
+
+ ) : (
+ No pods with errors
+ )}
+
+
+
+ );
+};
+
+const DaemonSetAccordion = ({
+ daemonset,
+ ownedPods,
+}: DaemonSetAccordionProps) => {
+ const podNamesWithErrors = useContext(PodNamesWithErrorsContext);
+
+ const podsWithErrors = ownedPods.filter(p =>
+ podNamesWithErrors.has(p.metadata?.name ?? ''),
+ );
+
+ return (
+
+ }>
+
+
+
+
+
+
+ );
+};
+
+export const DaemonSetsAccordions = ({}: DaemonSetsAccordionsProps) => {
+ const groupedResponses = useContext(GroupedResponsesContext);
+
+ return (
+
+ {groupedResponses.daemonSets.map((daemonset, i) => (
+
+
+
+
+
+ ))}
+
+ );
+};
diff --git a/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsDrawer.test.tsx b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsDrawer.test.tsx
new file mode 100644
index 0000000000..51e70a3b9b
--- /dev/null
+++ b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsDrawer.test.tsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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 * as daemonsets from '../../__fixtures__/2-daemonsets.json';
+import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
+import { DaemonSetDrawer } from './DaemonSetsDrawer';
+import { kubernetesClusterLinkFormatterApiRef } from '../../api';
+
+describe('DaemonsetsDrawer', () => {
+ it('should render daemonsets drawer', async () => {
+ const { getByText, getAllByText } = await renderInTestApp(
+
+
+ ,
+ ,
+ );
+ expect(getAllByText('fluentd-elasticsearch')).toHaveLength(2);
+ expect(getAllByText('DaemonSet')).toHaveLength(2);
+ expect(getByText('YAML')).toBeInTheDocument();
+ expect(getByText('Update Strategy Type')).toBeInTheDocument();
+ expect(getByText('RollingUpdate')).toBeInTheDocument();
+ expect(getByText('Min Ready Seconds')).toBeInTheDocument();
+ expect(getByText('???')).toBeInTheDocument();
+ expect(getByText('Min Ready Seconds')).toBeInTheDocument();
+ expect(getByText('Revision History Limit')).toBeInTheDocument();
+ expect(getByText('Current Number Scheduled')).toBeInTheDocument();
+ expect(getByText('Desired Number Scheduled')).toBeInTheDocument();
+ expect(getByText('Number Available')).toBeInTheDocument();
+ expect(getByText('Number Misscheduled')).toBeInTheDocument();
+ expect(getByText('Number Ready')).toBeInTheDocument();
+ expect(getByText('namespace: default')).toBeInTheDocument();
+ });
+
+ it('should render deployment drawer without namespace', async () => {
+ const daemonset = (daemonsets as any).daemonSets[0];
+ const { queryByText } = await renderInTestApp(
+
+
+ ,
+ ,
+ );
+
+ expect(queryByText('namespace: default')).not.toBeInTheDocument();
+ });
+});
diff --git a/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsDrawer.tsx b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsDrawer.tsx
new file mode 100644
index 0000000000..e0f64ed679
--- /dev/null
+++ b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/DaemonSetsDrawer.tsx
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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 { V1DaemonSet } from '@kubernetes/client-node';
+import { KubernetesStructuredMetadataTableDrawer } from '../KubernetesDrawer';
+import { Typography, Grid, Chip } from '@material-ui/core';
+
+export const DaemonSetDrawer = ({
+ daemonset,
+ expanded,
+}: {
+ daemonset: V1DaemonSet;
+ expanded?: boolean;
+}) => {
+ const namespace = daemonset.metadata?.namespace;
+ return (
+ {
+ return {
+ updateStrategyType: daemonsetObj.spec?.updateStrategy?.type ?? '???',
+ minReadySeconds: daemonsetObj.spec?.minReadySeconds ?? '???',
+ revisionHistoryLimit:
+ daemonsetObj.spec?.revisionHistoryLimit ?? '???',
+ currentNumberScheduled:
+ daemonsetObj.status?.currentNumberScheduled ?? '???',
+ desiredNumberScheduled:
+ daemonsetObj.status?.desiredNumberScheduled ?? '???',
+ numberAvailable: daemonsetObj.status?.numberAvailable ?? '???',
+ numberMisscheduled: daemonsetObj.status?.numberMisscheduled ?? '???',
+ numberReady: daemonsetObj.status?.numberReady ?? '???',
+ };
+ }}
+ >
+
+
+
+ {daemonset.metadata?.name ?? 'unknown object'}
+
+
+
+
+ DaemonSet
+
+
+ {namespace && (
+
+
+
+ )}
+
+
+ );
+};
diff --git a/plugins/kubernetes-react/src/components/DaemonSetsAccordions/index.ts b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/index.ts
new file mode 100644
index 0000000000..ca25150cbd
--- /dev/null
+++ b/plugins/kubernetes-react/src/components/DaemonSetsAccordions/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2024 The Backstage Authors
+ *
+ * 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 { DaemonSetsAccordions } from './DaemonSetsAccordions';
diff --git a/plugins/kubernetes-react/src/hooks/GroupedResponses.ts b/plugins/kubernetes-react/src/hooks/GroupedResponses.ts
index 7a81a74337..10cd3a8abe 100644
--- a/plugins/kubernetes-react/src/hooks/GroupedResponses.ts
+++ b/plugins/kubernetes-react/src/hooks/GroupedResponses.ts
@@ -25,6 +25,7 @@ export const GroupedResponsesContext = React.createContext({
pods: [],
replicaSets: [],
deployments: [],
+ daemonSets: [],
services: [],
configMaps: [],
horizontalPodAutoscalers: [],