Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan
- [#89](https://github.com/kobsio/kobs/pull/89): Rework Opsgenie plugin to show alerts and incidents from Opsgenie.
- [#91](https://github.com/kobsio/kobs/pull/91): Add force delete option for Kubernetes resources.
- [#92](https://github.com/kobsio/kobs/pull/92): Preparation to build a own version of kobs using the [kobsio/app](https://github.com/kobsio/app) template.
- [#93](https://github.com/kobsio/kobs/pull/93): Show status of Kubernetes resource in the table of the resources plugin.

### Fixed

Expand Down
110 changes: 101 additions & 9 deletions plugins/core/src/utils/resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ import {
V1beta1PodSecurityPolicyList,
V2beta1HorizontalPodAutoscalerList,
} from '@kubernetes/client-node';
import { SearchIcon, SquareIcon } from '@patternfly/react-icons';
import { IRow } from '@patternfly/react-table';
import { JSONPath } from 'jsonpath-plus';
import React from 'react';
import { SearchIcon } from '@patternfly/react-icons';

import { getLabelSelector } from './manifests';
import { timeDifference } from './time';

const COLOR_OK = 'var(--pf-global--success-color--100)';
const COLOR_WARNING = 'var(--pf-global--warning-color--100)';
const COLOR_DANGER = 'var(--pf-global--danger-color--100)';

// IResourceItems is a list of resources for the cluster and namespace. The resources field contains a list of json
// manifests, which are representing the resources. This interface is used as input for the rows function of the
// resources object.
Expand Down Expand Up @@ -149,6 +153,7 @@ export const resources: IResources = {
'Available',
'Node Selector',
'Age',
'',
],
description: 'A DaemonSet ensures that all (or some) Nodes run a copy of a Pod.',
isCRD: false,
Expand Down Expand Up @@ -178,6 +183,15 @@ export const resources: IResources = {
nodeSelector.push(`${key}=${daemonSet.spec?.template.spec?.nodeSelector[key]}`);
}

let status = COLOR_WARNING;
if (daemonSet.status && daemonSet.status.numberMisscheduled > 0) {
status = COLOR_DANGER;
} else if (desired === current && desired === ready && desired === upToDate && desired === available) {
status = COLOR_OK;
} else if (current === 0 || ready === 0 || upToDate === 0 || available) {
status = COLOR_DANGER;
}

rows.push({
cells: [
daemonSet.metadata?.name,
Expand All @@ -190,6 +204,9 @@ export const resources: IResources = {
available,
nodeSelector.join(', '),
age,
<span key="status">
<SquareIcon color={status} />
</span>,
],
props: daemonSet,
});
Expand All @@ -202,7 +219,7 @@ export const resources: IResources = {
title: 'Daemon Sets',
},
deployments: {
columns: ['Name', 'Namespace', 'Cluster', 'Ready', 'Up to date', 'Available', 'Age'],
columns: ['Name', 'Namespace', 'Cluster', 'Ready', 'Up to date', 'Available', 'Age', ''],
description: 'A Deployment provides declarative updates for Pods and ReplicaSets.',
isCRD: false,
path: '/apis/apps/v1',
Expand All @@ -225,6 +242,13 @@ export const resources: IResources = {
const upToDate = deployment.status?.updatedReplicas ? deployment.status?.updatedReplicas : 0;
const available = deployment.status?.availableReplicas ? deployment.status?.availableReplicas : 0;

let status = COLOR_WARNING;
if (shouldReady === ready && shouldReady === upToDate && shouldReady === available) {
status = COLOR_OK;
} else if (ready === 0 || upToDate === 0 || available) {
status = COLOR_DANGER;
}

rows.push({
cells: [
deployment.metadata?.name,
Expand All @@ -234,6 +258,9 @@ export const resources: IResources = {
upToDate,
available,
age,
<span key="status">
<SquareIcon color={status} />
</span>,
],
props: deployment,
});
Expand All @@ -246,7 +273,7 @@ export const resources: IResources = {
title: 'Deployments',
},
jobs: {
columns: ['Name', 'Namespace', 'Cluster', 'Completions', 'Duration', 'Age'],
columns: ['Name', 'Namespace', 'Cluster', 'Completions', 'Duration', 'Age', ''],
description:
'A Job creates one or more Pods and will continue to retry execution of the Pods until a specified number of them successfully terminate.',
isCRD: false,
Expand All @@ -272,6 +299,11 @@ export const resources: IResources = {
)
: '-';

let status = COLOR_OK;
if (completions !== completionsShould && completionsShould !== 0) {
status = COLOR_DANGER;
}

rows.push({
cells: [
job.metadata?.name,
Expand All @@ -280,6 +312,9 @@ export const resources: IResources = {
`${completions}/${completionsShould}`,
duration,
age,
<span key="status">
<SquareIcon color={status} />
</span>,
],
props: job,
});
Expand All @@ -292,7 +327,7 @@ export const resources: IResources = {
title: 'Jobs',
},
pods: {
columns: ['Name', 'Namespace', 'Cluster', 'Ready', 'Status', 'Restarts', 'Age'],
columns: ['Name', 'Namespace', 'Cluster', 'Ready', 'Status', 'Restarts', 'Age', ''],
description: 'Pods are the smallest deployable units of computing that you can create and manage in Kubernetes.',
isCRD: false,
path: '/api/v1',
Expand Down Expand Up @@ -343,6 +378,17 @@ export const resources: IResources = {
reason ? reason : phase,
restarts,
age,
<span key="status">
<SquareIcon
color={
phase === 'Running' || phase === 'Succeeded'
? COLOR_OK
: phase === 'Unknown'
? COLOR_WARNING
: COLOR_DANGER
}
/>
</span>,
],
props: pod,
});
Expand All @@ -355,7 +401,7 @@ export const resources: IResources = {
title: 'Pods',
},
replicasets: {
columns: ['Name', 'Namespace', 'Cluster', 'Desired', 'Current', 'Ready', 'Age'],
columns: ['Name', 'Namespace', 'Cluster', 'Desired', 'Current', 'Ready', 'Age', ''],
description: "A ReplicaSet's purpose is to maintain a stable set of replica Pods running at any given time.",
isCRD: false,
path: '/apis/apps/v1',
Expand All @@ -377,8 +423,24 @@ export const resources: IResources = {
const current = replicaSet.status?.availableReplicas ? replicaSet.status?.availableReplicas : 0;
const ready = replicaSet.status?.readyReplicas ? replicaSet.status?.readyReplicas : 0;

let status = COLOR_OK;
if (desired !== 0 && desired !== current && desired !== ready) {
status = COLOR_DANGER;
}

rows.push({
cells: [replicaSet.metadata?.name, item.namespace, item.cluster, desired, current, ready, age],
cells: [
replicaSet.metadata?.name,
item.namespace,
item.cluster,
desired,
current,
ready,
age,
<span key="status">
<SquareIcon color={status} />
</span>,
],
props: replicaSet,
});
}
Expand All @@ -390,7 +452,7 @@ export const resources: IResources = {
title: 'Replica Sets',
},
statefulsets: {
columns: ['Name', 'Namespace', 'Cluster', 'Ready', 'Up to date', 'Age'],
columns: ['Name', 'Namespace', 'Cluster', 'Ready', 'Up to date', 'Age', ''],
description: 'StatefulSet is the workload API object used to manage stateful applications.',
isCRD: false,
path: '/apis/apps/v1',
Expand All @@ -412,8 +474,25 @@ export const resources: IResources = {
const shouldReady = statefulSet.status?.replicas ? statefulSet.status?.replicas : 0;
const upToDate = statefulSet.status?.updatedReplicas ? statefulSet.status?.updatedReplicas : 0;

let status = COLOR_WARNING;
if (shouldReady === 0 || (shouldReady === ready && shouldReady === upToDate)) {
status = COLOR_OK;
} else if (ready === 0 || upToDate === 0) {
status = COLOR_DANGER;
}

rows.push({
cells: [statefulSet.metadata?.name, item.namespace, item.cluster, `${ready}/${shouldReady}`, upToDate, age],
cells: [
statefulSet.metadata?.name,
item.namespace,
item.cluster,
`${ready}/${shouldReady}`,
upToDate,
age,
<span key="status">
<SquareIcon color={status} />
</span>,
],
props: statefulSet,
});
}
Expand Down Expand Up @@ -779,7 +858,7 @@ export const resources: IResources = {
title: 'Persistent Volumes',
},
poddisruptionbudgets: {
columns: ['Name', 'Namespace', 'Cluster', 'Min. Available', 'Max. Unavailable', 'Allowed Disruptions', 'Age'],
columns: ['Name', 'Namespace', 'Cluster', 'Min. Available', 'Max. Unavailable', 'Allowed Disruptions', 'Age', ''],
description: '',
isCRD: false,
path: '/apis/policy/v1beta1',
Expand All @@ -798,6 +877,16 @@ export const resources: IResources = {
? timeDifference(new Date().getTime(), new Date(pdb.metadata.creationTimestamp.toString()).getTime())
: '-';

let status = COLOR_OK;
if (
!pdb.status ||
!pdb.status.currentHealthy ||
!pdb.status.desiredHealthy ||
pdb.status.currentHealthy < pdb.status.desiredHealthy
) {
status = COLOR_DANGER;
}

rows.push({
cells: [
pdb.metadata?.name,
Expand All @@ -807,6 +896,9 @@ export const resources: IResources = {
maxUnavailable,
allowedDisruptions,
age,
<span key="status">
<SquareIcon color={status} />
</span>,
],
props: pdb,
});
Expand Down