From 6cee819c8b75bae13187870d9ffeb7d0b26e79a5 Mon Sep 17 00:00:00 2001 From: Violetta <38247153+vshakirova@users.noreply.github.com> Date: Thu, 27 May 2021 16:52:35 +0400 Subject: [PATCH] Show all node resources in node view (#2861) Signed-off-by: vshakirova --- src/renderer/api/endpoints/nodes.api.ts | 42 +++++++--- .../+nodes/node-details-resources.scss | 48 ++++++++++++ .../+nodes/node-details-resources.tsx | 78 +++++++++++++++++++ .../components/+nodes/node-details.tsx | 18 ++--- 4 files changed, 165 insertions(+), 21 deletions(-) create mode 100644 src/renderer/components/+nodes/node-details-resources.scss create mode 100644 src/renderer/components/+nodes/node-details-resources.tsx diff --git a/src/renderer/api/endpoints/nodes.api.ts b/src/renderer/api/endpoints/nodes.api.ts index 4734c47a23..40dc2aeadb 100644 --- a/src/renderer/api/endpoints/nodes.api.ts +++ b/src/renderer/api/endpoints/nodes.api.ts @@ -52,39 +52,56 @@ export interface INodeMetrics { export interface Node { spec: { - podCIDR: string; - externalID: string; + podCIDR?: string; + podCIDRs?: string[]; + providerID?: string; + /** + * @deprecated see https://issues.k8s.io/61966 + */ + externalID?: string; taints?: { key: string; value: string; effect: string; + timeAdded: string; }[]; unschedulable?: boolean; }; status: { - capacity: { + capacity?: { cpu: string; + ["ephemeral-storage"]: string; + ["hugepages-1Gi"]: string; + ["hugepages-2Mi"]: string; memory: string; pods: string; }; - allocatable: { + allocatable?: { cpu: string; + ["ephemeral-storage"]: string; + ["hugepages-1Gi"]: string; + ["hugepages-2Mi"]: string; memory: string; pods: string; }; - conditions: { + conditions?: { type: string; - status?: string; + status: string; lastHeartbeatTime?: string; lastTransitionTime?: string; reason?: string; message?: string; }[]; - addresses: { + addresses?: { type: string; address: string; }[]; - nodeInfo: { + daemonEndpoints?: { + kubeletEndpoint: { + Port: number; //it must be uppercase for backwards compatibility + } + } + nodeInfo?: { machineID: string; systemUUID: string; bootID: string; @@ -96,9 +113,14 @@ export interface Node { operatingSystem: string; architecture: string; }; - images: { + images?: { names: string[]; - sizeBytes: number; + sizeBytes?: number; + }[]; + volumesInUse?: string[]; + volumesAttached?: { + name: string; + devicePath: string; }[]; }; } diff --git a/src/renderer/components/+nodes/node-details-resources.scss b/src/renderer/components/+nodes/node-details-resources.scss new file mode 100644 index 0000000000..46bbd6ca5d --- /dev/null +++ b/src/renderer/components/+nodes/node-details-resources.scss @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +.NodeDetailsResources { + .Table { + margin: 0 (-$margin * 3); + } + + .TableCell { + &:first-child { + margin-left: $margin; + } + + &:last-child { + margin-right: $margin; + } + + &.pods { + flex-grow: 0.5; + } + + &.memory { + flex-grow: 0.5; + } + + &.cpu { + flex-grow:0.5; + } + } +} diff --git a/src/renderer/components/+nodes/node-details-resources.tsx b/src/renderer/components/+nodes/node-details-resources.tsx new file mode 100644 index 0000000000..0906857256 --- /dev/null +++ b/src/renderer/components/+nodes/node-details-resources.tsx @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import "./node-details-resources.scss"; + +import { Table } from "../table/table"; +import { TableHead } from "../table/table-head"; +import { TableRow } from "../table/table-row"; +import React from "react"; +import type { Node } from "../../api/endpoints"; +import { TableCell } from "../table/table-cell"; + +interface Props { + node: Node; + type: "allocatable" | "capacity"; +} + +export class NodeDetailsResources extends React.Component { + toMi(resource: string) { + if (resource.endsWith("Ki")) { + return `${(parseInt(resource) / 1024).toFixed(1)}Mi`; + } + + return resource; + } + + render() { + const status = this.props.node.status; + const type = this.props.type; + + if (!status) return null; + + return ( +
+ + + CPU + Memory + Ephemeral Storage + Hugepages-1Gi + Hugepages-2Mi + Pods + + + {status[type].cpu} + {this.toMi(status[type].memory)} + {this.toMi(status[type]["ephemeral-storage"])} + {status[type]["hugepages-1Gi"]} + {status[type]["hugepages-2Mi"]} + {status[type].pods} + +
+
+ ); + } +} diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index df98312d17..6d32eb585b 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -40,6 +40,8 @@ import { KubeEventDetails } from "../+events/kube-event-details"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; import { ClusterStore } from "../../../common/cluster-store"; +import { NodeDetailsResources } from "./node-details-resources"; +import { DrawerTitle } from "../drawer/drawer-title"; interface Props extends KubeObjectDetailsProps { } @@ -64,7 +66,7 @@ export class NodeDetails extends React.Component { if (!node) return null; const { status } = node; - const { nodeInfo, addresses, capacity, allocatable } = status; + const { nodeInfo, addresses } = status; const conditions = node.getActiveConditions(); const taints = node.getTaints(); const childPods = podsStore.getPodsByNode(node.getName()); @@ -88,16 +90,6 @@ export class NodeDetails extends React.Component { )} - - CPU: {capacity.cpu},{" "} - Memory: {Math.floor(parseInt(capacity.memory) / 1024)}Mi,{" "} - Pods: {capacity.pods} - - - CPU: {allocatable.cpu},{" "} - Memory: {Math.floor(parseInt(allocatable.memory) / 1024)}Mi,{" "} - Pods: {allocatable.pods} - {addresses && { @@ -167,6 +159,10 @@ export class NodeDetails extends React.Component { } } + + + +