Merge pull request #8217 from brexhq/k8s-cronjobs-frontend

K8s Cronjobs frontend
This commit is contained in:
Patrik Oldsberg
2021-11-30 23:15:19 +01:00
committed by GitHub
23 changed files with 1530 additions and 24 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-kubernetes': patch
---
Added accordions to display information on Jobs and CronJobs in the kubernetes plugin. Updated the PodsTable with fewer default columns and the ability to pass in additional ones depending on the use case.
+28
View File
@@ -29,6 +29,8 @@ import {
} from '@backstage/plugin-kubernetes-common';
import fixture1 from '../src/__fixtures__/1-deployments.json';
import fixture2 from '../src/__fixtures__/2-deployments.json';
import fixture3 from '../src/__fixtures__/1-cronjobs.json';
import fixture4 from '../src/__fixtures__/2-cronjobs.json';
import { TestApiProvider } from '@backstage/test-utils';
const mockEntity: Entity = {
@@ -102,5 +104,31 @@ createDevApp()
</TestApiProvider>
),
})
.addPage({
path: '/fixture-3',
title: 'Fixture 3',
element: (
<TestApiProvider
apis={[[kubernetesApiRef, new MockKubernetesClient(fixture3)]]}
>
<EntityProvider entity={mockEntity}>
<EntityKubernetesContent />
</EntityProvider>
</TestApiProvider>
),
})
.addPage({
path: '/fixture-4',
title: 'Fixture 4',
element: (
<TestApiProvider
apis={[[kubernetesApiRef, new MockKubernetesClient(fixture4)]]}
>
<EntityProvider entity={mockEntity}>
<EntityKubernetesContent />
</EntityProvider>
</TestApiProvider>
),
})
.registerPlugin(kubernetesPlugin)
.render();
+1
View File
@@ -42,6 +42,7 @@
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"cronstrue": "^1.122.0",
"js-yaml": "^4.0.0",
"lodash": "^4.17.21",
"luxon": "^2.0.2",
@@ -0,0 +1,446 @@
{
"cronJobs": [
{
"metadata": {
"name": "dice-roller-cronjob",
"namespace": "default",
"uid": "9ea073bc-7a4b-4b99-8321-0305bce85568",
"resourceVersion": "1362732552",
"creationTimestamp": "2021-07-16T22:39:58Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller"
},
"annotations": {}
},
"spec": {
"schedule": "30 5 * * *",
"startingDeadlineSeconds": 1800,
"concurrencyPolicy": "Forbid",
"suspend": false,
"jobTemplate": {
"metadata": { "creationTimestamp": null },
"spec": {
"backoffLimit": 2,
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"backstage.io/kubernetes-id": "dice-roller"
},
"annotations": {}
},
"spec": {
"containers": [
{
"name": "busybox",
"image": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"imagePullPolicy": "IfNotPresent",
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"]
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"securityContext": {},
"schedulerName": "default-scheduler"
}
}
}
},
"successfulJobsHistoryLimit": 2,
"failedJobsHistoryLimit": 2
},
"status": {
"active": [
{
"kind": "Job",
"namespace": "default",
"name": "dice-roller-cronjob-1637028600",
"uid": "32be1b89-5b53-45b2-aa84-277e75214f61",
"apiVersion": "batch/v1",
"resourceVersion": "1361174163"
}
],
"lastScheduleTime": "2021-11-16T02:10:00Z"
}
}
],
"jobs": [
{
"metadata": {
"name": "dice-roller-cronjob-1637025000",
"namespace": "default",
"uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"resourceVersion": "1361029181",
"creationTimestamp": "2021-11-16T01:10:24Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller"
},
"ownerReferences": [
{
"apiVersion": "batch/v1",
"kind": "CronJob",
"name": "dice-roller-cronjob",
"uid": "9ea073bc-7a4b-4b99-8321-0305bce85568",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"parallelism": 1,
"completions": 1,
"backoffLimit": 2,
"selector": {
"matchLabels": {
"controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a"
}
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"backstage.io/kubernetes-id": "dice-roller",
"controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"job-name": "dice-roller-cronjob-1637025000"
},
"annotations": {}
},
"spec": {
"containers": [
{
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"securityContext": {},
"schedulerName": "default-scheduler"
}
}
},
"status": {
"conditions": [
{
"type": "Complete",
"status": "True",
"lastProbeTime": "2021-11-16T01:11:31Z",
"lastTransitionTime": "2021-11-16T01:11:31Z"
}
],
"startTime": "2021-11-16T01:10:24Z",
"completionTime": "2021-11-16T01:11:31Z",
"succeeded": 1
}
},
{
"metadata": {
"name": "dice-roller-cronjob-1637028600",
"namespace": "default",
"uid": "32be1b89-5b53-45b2-aa84-277e75214f61",
"resourceVersion": "1361174166",
"creationTimestamp": "2021-11-16T02:10:22Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller"
},
"ownerReferences": [
{
"apiVersion": "batch/v1",
"kind": "CronJob",
"name": "dice-roller-cronjob",
"uid": "9ea073bc-7a4b-4b99-8321-0305bce85568",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"parallelism": 1,
"completions": 1,
"backoffLimit": 2,
"selector": {
"matchLabels": {
"controller-uid": "32be1b89-5b53-45b2-aa84-277e75214f61"
}
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"backstage.io/kubernetes-id": "dice-roller",
"controller-uid": "32be1b89-5b53-45b2-aa84-277e75214f61",
"job-name": "dice-roller-cronjob-1637028600"
},
"annotations": {}
},
"spec": {
"containers": [
{
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"securityContext": {},
"schedulerName": "default-scheduler"
}
}
},
"status": { "startTime": "2021-11-16T02:10:22Z", "active": 1 }
}
],
"pods": [
{
"metadata": {
"name": "dice-roller-cronjob-1637025000-gstc4",
"generateName": "dice-roller-cronjob-1637025000-",
"namespace": "default",
"uid": "3b0f2b65-5ae2-441a-beda-bdc92bcafaf0",
"resourceVersion": "1361029179",
"creationTimestamp": "2021-11-16T01:10:24Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller",
"controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"job-name": "dice-roller-cronjob-1637025000"
},
"annotations": {},
"ownerReferences": [
{
"apiVersion": "batch/v1",
"kind": "Job",
"name": "dice-roller-cronjob-1637025000",
"uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"volumes": [],
"containers": [
{
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "default",
"serviceAccount": "default",
"nodeName": "minikube",
"securityContext": {},
"schedulerName": "default-scheduler",
"tolerations": [
{
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
},
{
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
}
],
"priority": 0,
"enableServiceLinks": true
},
"status": {
"phase": "Succeeded",
"conditions": [
{
"type": "Initialized",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T01:10:27Z",
"reason": "PodCompleted"
},
{
"type": "Ready",
"status": "False",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T01:11:31Z",
"reason": "PodCompleted"
},
{
"type": "ContainersReady",
"status": "False",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T01:11:31Z",
"reason": "PodCompleted"
},
{
"type": "PodScheduled",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T01:10:24Z"
}
],
"hostIP": "192.168.49.2",
"podIP": "172.17.0.25",
"podIPs": [{ "ip": "172.17.0.25" }],
"startTime": "2021-11-16T01:10:24Z",
"containerStatuses": [
{
"name": "busybox",
"state": {
"terminated": {
"exitCode": 0,
"reason": "Completed",
"startedAt": "2021-11-16T01:10:31Z",
"finishedAt": "2021-11-16T01:11:30Z",
"containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615"
}
},
"lastState": {},
"ready": false,
"restartCount": 0,
"image": "busybox:latest/node",
"imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353",
"containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615",
"started": false
}
],
"qosClass": "Burstable"
}
},
{
"metadata": {
"name": "dice-roller-cronjob-1637028600-p4mlc",
"generateName": "dice-roller-cronjob-1637028600-",
"namespace": "default",
"uid": "acddd5d2-ac7f-473b-a9d8-17a89f99ac39",
"resourceVersion": "1361174579",
"creationTimestamp": "2021-11-16T02:10:22Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller",
"controller-uid": "32be1b89-5b53-45b2-aa84-277e75214f61",
"job-name": "dice-roller-cronjob-1637028600"
},
"annotations": {},
"ownerReferences": [
{
"apiVersion": "batch/v1",
"kind": "Job",
"name": "dice-roller-cronjob-1637028600",
"uid": "32be1b89-5b53-45b2-aa84-277e75214f61",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"volumes": [],
"containers": [
{
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "default",
"serviceAccount": "default",
"nodeName": "minikube",
"securityContext": {},
"schedulerName": "default-scheduler",
"tolerations": [
{
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
},
{
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
}
],
"priority": 0,
"enableServiceLinks": true
},
"status": {
"phase": "Running",
"conditions": [
{
"type": "Initialized",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T02:10:25Z"
},
{
"type": "Ready",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T02:10:35Z"
},
{
"type": "ContainersReady",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T02:10:35Z"
},
{
"type": "PodScheduled",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2021-11-16T02:10:22Z"
}
],
"hostIP": "192.168.49.2",
"podIP": "172.17.0.25",
"podIPs": [{ "ip": "172.17.0.25" }],
"startTime": "2021-11-16T02:10:22Z",
"containerStatuses": [
{
"name": "busybox",
"state": {
"running": { "startedAt": "2021-11-16T02:10:31Z" }
},
"lastState": {},
"ready": true,
"restartCount": 0,
"image": "busybox:latest",
"imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353",
"containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615",
"started": true
}
],
"qosClass": "Burstable"
}
}
]
}
@@ -0,0 +1,385 @@
{
"cronJobs": [
{
"metadata": {
"name": "dice-roller-cronjob",
"namespace": "default",
"uid": "9ea073bc-7a4b-4b99-8321-0305bce85568",
"resourceVersion": "1362732552",
"creationTimestamp": "2021-07-16T22:39:58Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller"
},
"annotations": {}
},
"spec": {
"schedule": "* */2 * * *",
"startingDeadlineSeconds": 1800,
"concurrencyPolicy": "Forbid",
"suspend": true,
"jobTemplate": {
"metadata": { "creationTimestamp": null },
"spec": {
"backoffLimit": 2,
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"backstage.io/kubernetes-id": "dice-roller"
},
"annotations": {}
},
"spec": {
"containers": [
{
"name": "busybox",
"image": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"imagePullPolicy": "IfNotPresent",
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"]
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"securityContext": {},
"schedulerName": "default-scheduler"
}
}
}
},
"successfulJobsHistoryLimit": 2,
"failedJobsHistoryLimit": 2
},
"status": {
"lastScheduleTime": "2021-11-16T02:10:00Z"
}
}
],
"jobs": [
{
"metadata": {
"name": "dice-roller-cronjob-1637025000",
"namespace": "default",
"uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"resourceVersion": "1361029181",
"creationTimestamp": "2021-11-16T01:10:24Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller"
},
"ownerReferences": [
{
"apiVersion": "batch/v1",
"kind": "CronJob",
"name": "dice-roller-cronjob",
"uid": "9ea073bc-7a4b-4b99-8321-0305bce85568",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"parallelism": 1,
"completions": 1,
"backoffLimit": 2,
"selector": {
"matchLabels": {
"controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a"
}
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"backstage.io/kubernetes-id": "dice-roller",
"controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"job-name": "dice-roller-cronjob-1637025000"
},
"annotations": {}
},
"spec": {
"containers": [
{
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"securityContext": {},
"schedulerName": "default-scheduler"
}
}
},
"status": {
"conditions": [
{
"type": "Failed",
"status": "True",
"reason": "BackoffLimitExceeded",
"lastProbeTime": "2021-11-16T01:11:31Z",
"lastTransitionTime": "2021-11-16T01:11:31Z"
}
],
"startTime": "2021-11-16T01:10:24Z",
"failed": 2
}
}
],
"pods": [
{
"metadata": {
"name": "dice-roller-cronjob-1637025000-gstc4",
"generateName": "dice-roller-cronjob-1637025000-",
"namespace": "default",
"uid": "3b0f2b65-5ae2-441a-beda-bdc92bcafaf0",
"resourceVersion": "1361029179",
"creationTimestamp": "2021-11-16T01:10:24Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller",
"controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"job-name": "dice-roller-cronjob-1637025000"
},
"annotations": {},
"ownerReferences": [
{
"apiVersion": "batch/v1",
"kind": "Job",
"name": "dice-roller-cronjob-1637025000",
"uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"volumes": [],
"containers": [
{
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "default",
"serviceAccount": "default",
"nodeName": "minikube",
"securityContext": {},
"schedulerName": "default-scheduler",
"tolerations": [
{
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
},
{
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
}
],
"priority": 0,
"enableServiceLinks": true
},
"status": {
"phase": "Failed",
"conditions": [
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:10:13Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:11:02Z",
"message": "containers with unready status: [busybox]",
"reason": "ContainersNotReady",
"status": "False",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:11:02Z",
"message": "containers with unready status: [busybox]",
"reason": "ContainersNotReady",
"status": "False",
"type": "ContainersReady"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:10:08Z",
"status": "True",
"type": "PodScheduled"
}
],
"hostIP": "192.168.49.2",
"podIP": "172.17.0.25",
"podIPs": [{ "ip": "172.17.0.25" }],
"startTime": "2021-11-18T19:10:08Z",
"containerStatuses": [
{
"name": "busybox",
"state": {
"terminated": {
"exitCode": 1,
"finishedAt": "2021-11-18T19:11:01Z",
"reason": "Error",
"startedAt": "2021-11-18T19:10:17Z",
"containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615"
}
},
"lastState": {},
"ready": false,
"restartCount": 0,
"image": "busybox:latest",
"imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353",
"containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615",
"started": false
}
],
"qosClass": "Burstable"
}
},
{
"metadata": {
"name": "dice-roller-cronjob-1637025000-p4mlc",
"generateName": "dice-roller-cronjob-1637025000-",
"namespace": "default",
"uid": "acddd5d2-ac7f-473b-a9d8-17a89f99ac39",
"resourceVersion": "1361174579",
"creationTimestamp": "2021-11-16T02:10:22Z",
"labels": {
"backstage.io/kubernetes-id": "dice-roller",
"controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"job-name": "dice-roller-cronjob-1637025000"
},
"annotations": {},
"ownerReferences": [
{
"apiVersion": "batch/v1",
"kind": "Job",
"name": "dice-roller-cronjob-1637025000",
"uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"volumes": [],
"containers": [
{
"command": ["/bin/sh", "-c", "date; echo Rolling a die!"],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "busybox",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "default",
"serviceAccount": "default",
"nodeName": "minikube",
"securityContext": {},
"schedulerName": "default-scheduler",
"tolerations": [
{
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
},
{
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
}
],
"priority": 0,
"enableServiceLinks": true
},
"status": {
"phase": "Failed",
"conditions": [
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:10:13Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:11:02Z",
"message": "containers with unready status: [busybox]",
"reason": "ContainersNotReady",
"status": "False",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:11:02Z",
"message": "containers with unready status: [busybox]",
"reason": "ContainersNotReady",
"status": "False",
"type": "ContainersReady"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2021-11-18T19:10:08Z",
"status": "True",
"type": "PodScheduled"
}
],
"hostIP": "192.168.49.2",
"podIP": "172.17.0.25",
"podIPs": [{ "ip": "172.17.0.25" }],
"startTime": "2021-11-16T02:10:22Z",
"containerStatuses": [
{
"name": "busybox",
"state": {
"terminated": {
"exitCode": 1,
"finishedAt": "2021-11-18T19:11:01Z",
"reason": "Error",
"startedAt": "2021-11-18T19:10:17Z",
"containerID": "docker://2659c4d0f8a68f2b49863c18738322f1686d5b87275428e5e641fd9fd9e06739"
}
},
"lastState": {},
"ready": true,
"restartCount": 0,
"image": "busybox:latest",
"imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353",
"containerID": "docker://2659c4d0f8a68f2b49863c18738322f1686d5b87275428e5e641fd9fd9e06739",
"started": true
}
],
"qosClass": "Burstable"
}
}
]
}
@@ -29,6 +29,7 @@ import { DeploymentsAccordions } from '../DeploymentsAccordions';
import { groupResponses } from '../../utils/response';
import { IngressesAccordions } from '../IngressesAccordions';
import { ServicesAccordions } from '../ServicesAccordions';
import { CronJobsAccordions } from '../CronJobsAccordions';
import { CustomResources } from '../CustomResources';
import {
ClusterContext,
@@ -133,6 +134,9 @@ export const Cluster = ({ clusterObjects, podsWithErrors }: ClusterProps) => {
<Grid item>
<ServicesAccordions />
</Grid>
<Grid item>
<CronJobsAccordions />
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
@@ -0,0 +1,50 @@
/*
* Copyright 2021 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 { render } from '@testing-library/react';
import { CronJobsAccordions } from './CronJobsAccordions';
import * as oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json';
import * as twoCronJobsFixture from '../../__fixtures__/2-cronjobs.json';
import { wrapInTestApp } from '@backstage/test-utils';
import { kubernetesProviders } from '../../hooks/test-utils';
describe('CronJobsAccordions', () => {
it('should render 1 active cronjobs', async () => {
const wrapper = kubernetesProviders(oneCronJobsFixture, []);
const { getByText } = render(
wrapper(wrapInTestApp(<CronJobsAccordions />)),
);
expect(getByText('dice-roller-cronjob')).toBeInTheDocument();
expect(getByText('CronJob')).toBeInTheDocument();
expect(getByText('namespace: default')).toBeInTheDocument();
expect(getByText('Active')).toBeInTheDocument();
});
it('should render 1 suspended cronjobs', async () => {
const wrapper = kubernetesProviders(twoCronJobsFixture, []);
const { getByText } = render(
wrapper(wrapInTestApp(<CronJobsAccordions />)),
);
expect(getByText('dice-roller-cronjob')).toBeInTheDocument();
expect(getByText('CronJob')).toBeInTheDocument();
expect(getByText('namespace: default')).toBeInTheDocument();
expect(getByText('Suspended')).toBeInTheDocument();
});
});
@@ -0,0 +1,128 @@
/*
* Copyright 2021 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,
Divider,
Grid,
Typography,
} from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { V1CronJob, V1Job } from '@kubernetes/client-node';
import { JobsAccordions } from '../JobsAccordions';
import { CronJobDrawer } from './CronJobsDrawer';
import { getOwnedResources } from '../../utils/owner';
import { GroupedResponsesContext } from '../../hooks';
import { StatusError, StatusOK } from '@backstage/core-components';
import cronstrue from 'cronstrue';
type CronJobsAccordionsProps = {
children?: React.ReactNode;
};
type CronJobAccordionProps = {
cronJob: V1CronJob;
ownedJobs: V1Job[];
children?: React.ReactNode;
};
type CronJobSummaryProps = {
cronJob: V1CronJob;
children?: React.ReactNode;
};
const CronJobSummary = ({ cronJob }: CronJobSummaryProps) => {
return (
<Grid
container
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<Grid xs={3} item>
<CronJobDrawer cronJob={cronJob} />
</Grid>
<Grid item xs={1}>
<Divider style={{ height: '5em' }} orientation="vertical" />
</Grid>
<Grid
item
container
xs={5}
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
>
<Grid item>
{cronJob.spec?.suspend ? (
<StatusError>Suspended</StatusError>
) : (
<StatusOK>Active</StatusOK>
)}
</Grid>
<Grid item>
<Typography variant="body1">
Schedule:{' '}
{cronJob.spec?.schedule
? `${cronJob.spec.schedule} (${cronstrue.toString(
cronJob.spec.schedule,
)})`
: 'N/A'}
</Typography>
</Grid>
</Grid>
</Grid>
);
};
const CronJobAccordion = ({ cronJob, ownedJobs }: CronJobAccordionProps) => {
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<CronJobSummary cronJob={cronJob} />
</AccordionSummary>
<AccordionDetails>
<JobsAccordions jobs={ownedJobs.reverse()} />
</AccordionDetails>
</Accordion>
);
};
export const CronJobsAccordions = ({}: CronJobsAccordionsProps) => {
const groupedResponses = useContext(GroupedResponsesContext);
return (
<Grid
container
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
>
{groupedResponses.cronJobs.map((cronJob, i) => (
<Grid container item key={i} xs>
<Grid item xs>
<CronJobAccordion
ownedJobs={getOwnedResources(cronJob, groupedResponses.jobs)}
cronJob={cronJob}
/>
</Grid>
</Grid>
))}
</Grid>
);
};
@@ -0,0 +1,38 @@
/*
* Copyright 2021 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 oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json';
import { renderInTestApp } from '@backstage/test-utils';
import { CronJobDrawer } from './CronJobsDrawer';
describe('CronJobDrawer', () => {
it('should render cronJob drawer', async () => {
const { getByText, getAllByText } = await renderInTestApp(
<CronJobDrawer
cronJob={(oneCronJobsFixture as any).cronJobs[0]}
expanded
/>,
);
expect(getAllByText('dice-roller-cronjob')).toHaveLength(2);
expect(getAllByText('CronJob')).toHaveLength(2);
expect(getByText('YAML')).toBeInTheDocument();
expect(getByText('Schedule')).toBeInTheDocument();
expect(getByText('30 5 * * *')).toBeInTheDocument();
expect(getByText('Starting Deadline Seconds')).toBeInTheDocument();
expect(getByText('Last Schedule Time')).toBeInTheDocument();
});
});
@@ -0,0 +1,67 @@
/*
* Copyright 2021 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 { V1CronJob } from '@kubernetes/client-node';
import { KubernetesDrawer } from '../KubernetesDrawer/KubernetesDrawer';
import { Typography, Grid, Chip } from '@material-ui/core';
export const CronJobDrawer = ({
cronJob,
expanded,
}: {
cronJob: V1CronJob;
expanded?: boolean;
}) => {
const namespace = cronJob.metadata?.namespace;
return (
<KubernetesDrawer
object={cronJob}
expanded={expanded}
kind="CronJob"
renderObject={(cronJobObj: V1CronJob) => ({
schedule: cronJobObj.spec?.schedule ?? '???',
startingDeadlineSeconds:
cronJobObj.spec?.startingDeadlineSeconds ?? '???',
concurrencyPolicy: cronJobObj.spec?.concurrencyPolicy ?? '???',
lastScheduleTime: cronJobObj.status?.lastScheduleTime ?? '???',
})}
>
<Grid
container
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
spacing={0}
>
<Grid item>
<Typography variant="h5">
{cronJob.metadata?.name ?? 'unknown object'}
</Typography>
</Grid>
<Grid item>
<Typography color="textSecondary" variant="body1">
CronJob
</Typography>
</Grid>
{namespace && (
<Grid item>
<Chip size="small" label={`namespace: ${namespace}`} />
</Grid>
)}
</Grid>
</KubernetesDrawer>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2021 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 { CronJobsAccordions } from './CronJobsAccordions';
@@ -36,11 +36,12 @@ import {
getOwnedPodsThroughReplicaSets,
getMatchingHpa,
} from '../../utils/owner';
import { containersReady, totalRestarts } from '../../utils/pod';
import {
GroupedResponsesContext,
PodNamesWithErrorsContext,
} from '../../hooks';
import { StatusError, StatusOK } from '@backstage/core-components';
import { StatusError, StatusOK, TableColumn } from '@backstage/core-components';
type DeploymentsAccordionsProps = {
children?: React.ReactNode;
@@ -61,6 +62,20 @@ type DeploymentSummaryProps = {
children?: React.ReactNode;
};
const deploymentPodColumns: TableColumn<V1Pod>[] = [
{
title: 'containers ready',
align: 'center',
render: containersReady,
},
{
title: 'total restarts',
align: 'center',
render: totalRestarts,
type: 'numeric',
},
];
const DeploymentSummary = ({
deployment,
numberOfCurrentPods,
@@ -161,7 +176,7 @@ const DeploymentAccordion = ({
/>
</AccordionSummary>
<AccordionDetails>
<PodsTable pods={ownedPods} />
<PodsTable pods={ownedPods} extraColumns={deploymentPodColumns} />
</AccordionDetails>
</Accordion>
);
@@ -0,0 +1,42 @@
/*
* Copyright 2021 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 { render } from '@testing-library/react';
import { JobsAccordions } from './JobsAccordions';
import * as oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json';
import { wrapInTestApp } from '@backstage/test-utils';
import { kubernetesProviders } from '../../hooks/test-utils';
import { V1Job, ObjectSerializer } from '@kubernetes/client-node';
describe('JobsAccordions', () => {
it('should render 2 jobs', async () => {
const wrapper = kubernetesProviders(oneCronJobsFixture, []);
const jobs: V1Job[] = oneCronJobsFixture.jobs.map(
job => ObjectSerializer.deserialize(job, 'V1Job') as V1Job,
);
const { getByText } = render(
wrapper(wrapInTestApp(<JobsAccordions jobs={jobs} />)),
);
expect(getByText('dice-roller-cronjob-1637028600')).toBeInTheDocument();
expect(getByText('Running')).toBeInTheDocument();
expect(getByText('dice-roller-cronjob-1637025000')).toBeInTheDocument();
expect(getByText('Succeeded')).toBeInTheDocument();
});
});
@@ -0,0 +1,125 @@
/*
* Copyright 2021 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,
Divider,
Grid,
} from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { V1Job, V1Pod } from '@kubernetes/client-node';
import { PodsTable } from '../Pods';
import { JobDrawer } from './JobsDrawer';
import { getOwnedResources } from '../../utils/owner';
import { GroupedResponsesContext } from '../../hooks';
import {
StatusError,
StatusOK,
StatusPending,
} from '@backstage/core-components';
type JobsAccordionsProps = {
jobs: V1Job[];
children?: React.ReactNode;
};
type JobAccordionProps = {
job: V1Job;
ownedPods: V1Pod[];
children?: React.ReactNode;
};
type JobSummaryProps = {
job: V1Job;
children?: React.ReactNode;
};
const JobSummary = ({ job }: JobSummaryProps) => {
return (
<Grid
container
direction="row"
justifyContent="flex-start"
alignItems="center"
>
<Grid xs={3} item>
<JobDrawer job={job} />
</Grid>
<Grid item xs={1}>
<Divider style={{ height: '5em' }} orientation="vertical" />
</Grid>
<Grid
item
container
xs={8}
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
>
<Grid item>
{job.status?.succeeded && <StatusOK>Succeeded</StatusOK>}
{job.status?.active && <StatusPending>Running</StatusPending>}
{job.status?.failed && <StatusError>Failed</StatusError>}
</Grid>
<Grid item>Start time: {job.status?.startTime?.toString()}</Grid>
{job.status?.completionTime && (
<Grid item>
Completion time: {job.status.completionTime.toString()}
</Grid>
)}
</Grid>
</Grid>
);
};
const JobAccordion = ({ job, ownedPods }: JobAccordionProps) => {
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<JobSummary job={job} />
</AccordionSummary>
<AccordionDetails>
<PodsTable pods={ownedPods} />
</AccordionDetails>
</Accordion>
);
};
export const JobsAccordions = ({ jobs }: JobsAccordionsProps) => {
const groupedResponses = useContext(GroupedResponsesContext);
return (
<Grid
container
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
>
{jobs.map((job, i) => (
<Grid container item key={i} xs>
<Grid item xs>
<JobAccordion
ownedPods={getOwnedResources(job, groupedResponses.pods)}
job={job}
/>
</Grid>
</Grid>
))}
</Grid>
);
};
@@ -0,0 +1,35 @@
/*
* Copyright 2021 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 oneCronJobsFixture from '../../__fixtures__/1-cronjobs.json';
import { renderInTestApp } from '@backstage/test-utils';
import { JobDrawer } from './JobsDrawer';
describe('JobDrawer', () => {
it('should render job drawer', async () => {
const { getByText, getAllByText } = await renderInTestApp(
<JobDrawer job={(oneCronJobsFixture as any).jobs[0]} expanded />,
);
expect(getAllByText('dice-roller-cronjob-1637025000')).toHaveLength(2);
expect(getAllByText('Job')).toHaveLength(2);
expect(getByText('YAML')).toBeInTheDocument();
expect(getByText('Parallelism')).toBeInTheDocument();
expect(getByText('Completions')).toBeInTheDocument();
expect(getByText('Backoff Limit')).toBeInTheDocument();
expect(getByText('Start Time')).toBeInTheDocument();
});
});
@@ -0,0 +1,62 @@
/*
* Copyright 2021 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 { V1Job } from '@kubernetes/client-node';
import { KubernetesDrawer } from '../KubernetesDrawer/KubernetesDrawer';
import { Typography, Grid } from '@material-ui/core';
export const JobDrawer = ({
job,
expanded,
}: {
job: V1Job;
expanded?: boolean;
}) => {
return (
<KubernetesDrawer
object={job}
expanded={expanded}
kind="Job"
renderObject={(jobObj: V1Job) => {
return {
parallelism: jobObj.spec?.parallelism ?? '???',
completions: jobObj.spec?.completions ?? '???',
backoffLimit: jobObj.spec?.backoffLimit ?? '???',
startTime: jobObj.status?.startTime ?? '???',
};
}}
>
<Grid
container
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
spacing={0}
>
<Grid item>
<Typography variant="h6">
{job.metadata?.name ?? 'unknown object'}
</Typography>
</Grid>
<Grid item>
<Typography color="textSecondary" variant="body1">
Job
</Typography>
</Grid>
</Grid>
</KubernetesDrawer>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2021 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 { JobsAccordions } from './JobsAccordions';
+40 -2
View File
@@ -18,8 +18,25 @@ import React from 'react';
import { render } from '@testing-library/react';
import * as pod from './__fixtures__/pod.json';
import * as crashingPod from './__fixtures__/crashing-pod.json';
import { TableColumn } from '@backstage/core-components';
import { wrapInTestApp } from '@backstage/test-utils';
import { V1Pod } from '@kubernetes/client-node';
import { PodsTable } from './PodsTable';
import { containersReady, totalRestarts } from '../../utils/pod';
const extraColumns: TableColumn<V1Pod>[] = [
{
title: 'containers ready',
align: 'center',
render: containersReady,
},
{
title: 'total restarts',
align: 'center',
render: totalRestarts,
type: 'numeric',
},
];
describe('PodsTable', () => {
it('should render pod', async () => {
@@ -27,6 +44,24 @@ describe('PodsTable', () => {
wrapInTestApp(<PodsTable pods={[pod as any]} />),
);
// titles
expect(getByText('name')).toBeInTheDocument();
expect(getByText('phase')).toBeInTheDocument();
expect(getByText('status')).toBeInTheDocument();
// values
expect(getByText('dice-roller-6c8646bfd-2m5hv')).toBeInTheDocument();
expect(getByText('Running')).toBeInTheDocument();
expect(getByText('OK')).toBeInTheDocument();
});
it('should render pod with extra columns', async () => {
const { getByText } = render(
wrapInTestApp(
<PodsTable pods={[pod as any]} extraColumns={extraColumns} />,
),
);
// titles
expect(getByText('name')).toBeInTheDocument();
expect(getByText('phase')).toBeInTheDocument();
@@ -41,9 +76,12 @@ describe('PodsTable', () => {
expect(getByText('0')).toBeInTheDocument();
expect(getByText('OK')).toBeInTheDocument();
});
it('should render crashing pod', async () => {
it('should render crashing pod with extra columns', async () => {
const { getByText, getAllByText } = render(
wrapInTestApp(<PodsTable pods={[crashingPod as any]} />),
wrapInTestApp(
<PodsTable pods={[crashingPod as any]} extraColumns={extraColumns} />,
),
);
// titles
+6 -20
View File
@@ -17,14 +17,10 @@
import React from 'react';
import { V1Pod } from '@kubernetes/client-node';
import { PodDrawer } from './PodDrawer';
import {
containersReady,
containerStatuses,
totalRestarts,
} from '../../utils/pod';
import { containerStatuses } from '../../utils/pod';
import { Table, TableColumn } from '@backstage/core-components';
const columns: TableColumn<V1Pod>[] = [
const DEFAULT_COLUMNS: TableColumn<V1Pod>[] = [
{
title: 'name',
highlight: true,
@@ -34,29 +30,19 @@ const columns: TableColumn<V1Pod>[] = [
title: 'phase',
render: (pod: V1Pod) => pod.status?.phase ?? 'unknown',
},
{
title: 'containers ready',
align: 'center',
render: containersReady,
},
{
title: 'total restarts',
align: 'center',
render: totalRestarts,
type: 'numeric',
},
{
title: 'status',
render: containerStatuses,
},
];
type DeploymentTablesProps = {
type PodsTablesProps = {
pods: V1Pod[];
extraColumns?: TableColumn<V1Pod>[];
children?: React.ReactNode;
};
export const PodsTable = ({ pods }: DeploymentTablesProps) => {
export const PodsTable = ({ pods, extraColumns = [] }: PodsTablesProps) => {
const tableStyle = {
minWidth: '0',
width: '100%',
@@ -67,7 +53,7 @@ export const PodsTable = ({ pods }: DeploymentTablesProps) => {
<Table
options={{ paging: true, search: false }}
data={pods}
columns={columns}
columns={DEFAULT_COLUMNS.concat(extraColumns)}
/>
</div>
);
@@ -24,5 +24,7 @@ export const GroupedResponsesContext = React.createContext<GroupedResponses>({
configMaps: [],
horizontalPodAutoscalers: [],
ingresses: [],
jobs: [],
cronJobs: [],
customResources: [],
});
+4
View File
@@ -22,6 +22,8 @@ import {
V1Service,
V1ConfigMap,
ExtensionsV1beta1Ingress,
V1Job,
V1CronJob,
} from '@kubernetes/client-node';
export interface DeploymentResources {
@@ -35,6 +37,8 @@ export interface GroupedResponses extends DeploymentResources {
services: V1Service[];
configMaps: V1ConfigMap[];
ingresses: ExtensionsV1beta1Ingress[];
jobs: V1Job[];
cronJobs: V1CronJob[];
customResources: any[];
}
+8
View File
@@ -45,6 +45,12 @@ export const groupResponses = (
case 'ingresses':
prev.ingresses.push(...next.resources);
break;
case 'jobs':
prev.jobs.push(...next.resources);
break;
case 'cronjobs':
prev.cronJobs.push(...next.resources);
break;
case 'customresources':
prev.customResources.push(...next.resources);
break;
@@ -60,6 +66,8 @@ export const groupResponses = (
configMaps: [],
horizontalPodAutoscalers: [],
ingresses: [],
jobs: [],
cronJobs: [],
customResources: [],
} as GroupedResponses,
);
+5
View File
@@ -11978,6 +11978,11 @@ create-require@^1.1.0:
resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cronstrue@^1.122.0:
version "1.122.0"
resolved "https://registry.npmjs.org/cronstrue/-/cronstrue-1.122.0.tgz#bd6838077b476d28f61d381398b47b8c3912a126"
integrity sha512-PFuhZd+iPQQ0AWTXIEYX+t3nFGzBrWxmTWUKJOrsGRewaBSLKZ4I1f8s2kryU75nNxgyugZgiGh2OJsCTA/XlA==
cross-env@^7.0.0:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"