mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Improving metric queries (#3424)
This commit is contained in:
1 parent
84c767a3d2
commit
c6a4d55d86
33 files changed
+452
-357
No files matched your search
@@ -27,36 +27,46 @@ import kebabCase from "lodash/kebabCase";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { DrawerItem, DrawerItemLabels } from "../drawer";
|
||||
import { Badge } from "../badge";
|
||||
import { nodesStore } from "./nodes.store";
|
||||
import { ResourceMetrics } from "../resource-metrics";
|
||||
import { podsStore } from "../+workloads-pods/pods.store";
|
||||
import type { KubeObjectDetailsProps } from "../kube-object";
|
||||
import type { Node } from "../../api/endpoints";
|
||||
import { getMetricsByNodeNames, IClusterMetrics, Node } from "../../api/endpoints";
|
||||
import { NodeCharts } from "./node-charts";
|
||||
import { reaction } from "mobx";
|
||||
import { makeObservable, observable, reaction } from "mobx";
|
||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||
import { NodeDetailsResources } from "./node-details-resources";
|
||||
import { DrawerTitle } from "../drawer/drawer-title";
|
||||
import { boundMethod } from "../../utils";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<Node> {
|
||||
}
|
||||
|
||||
@observer
|
||||
export class NodeDetails extends React.Component<Props> {
|
||||
@observable metrics: Partial<IClusterMetrics>;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@disposeOnUnmount
|
||||
clean = reaction(() => this.props.object.getName(), () => {
|
||||
nodesStore.nodeMetrics = null;
|
||||
this.metrics = null;
|
||||
});
|
||||
|
||||
async componentDidMount() {
|
||||
podsStore.reloadAll();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
nodesStore.nodeMetrics = null;
|
||||
@boundMethod
|
||||
async loadMetrics() {
|
||||
const { object: node } = this.props;
|
||||
|
||||
this.metrics = await getMetricsByNodeNames([node.getName()]);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -68,7 +78,7 @@ export class NodeDetails extends React.Component<Props> {
|
||||
const conditions = node.getActiveConditions();
|
||||
const taints = node.getTaints();
|
||||
const childPods = podsStore.getPodsByNode(node.getName());
|
||||
const metrics = nodesStore.nodeMetrics;
|
||||
const { metrics } = this;
|
||||
const metricTabs = [
|
||||
"CPU",
|
||||
"Memory",
|
||||
@@ -81,7 +91,7 @@ export class NodeDetails extends React.Component<Props> {
|
||||
<div className="NodeDetails">
|
||||
{!isMetricHidden && podsStore.isLoaded && (
|
||||
<ResourceMetrics
|
||||
loader={() => nodesStore.loadMetrics(node.getName())}
|
||||
loader={this.loadMetrics}
|
||||
tabs={metricTabs} object={node} params={{ metrics }}
|
||||
>
|
||||
<NodeCharts/>
|
||||
|
||||
@@ -18,22 +18,17 @@
|
||||
* 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 { sum } from "lodash";
|
||||
import { action, computed, observable, makeObservable } from "mobx";
|
||||
import { clusterApi, IClusterMetrics, INodeMetrics, Node, nodesApi } from "../../api/endpoints";
|
||||
import { autoBind } from "../../utils";
|
||||
import { KubeObjectStore } from "../../kube-object.store";
|
||||
import { computed, makeObservable } from "mobx";
|
||||
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { Node, nodesApi } from "../../api/endpoints";
|
||||
import { KubeObjectStore } from "../../kube-object.store";
|
||||
import { autoBind } from "../../utils";
|
||||
|
||||
export class NodesStore extends KubeObjectStore<Node> {
|
||||
api = nodesApi;
|
||||
|
||||
@observable metrics: Partial<INodeMetrics> = {};
|
||||
@observable nodeMetrics: Partial<IClusterMetrics> = null;
|
||||
@observable metricsLoading = false;
|
||||
@observable metricsLoaded = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -41,23 +36,6 @@ export class NodesStore extends KubeObjectStore<Node> {
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
@action
|
||||
async loadUsageMetrics() {
|
||||
this.metricsLoading = true;
|
||||
|
||||
try {
|
||||
this.metrics = await nodesApi.getMetrics();
|
||||
this.metricsLoaded = true;
|
||||
} finally {
|
||||
this.metricsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async loadMetrics(nodeName: string) {
|
||||
this.nodeMetrics = await clusterApi.getMetrics([nodeName]);
|
||||
}
|
||||
|
||||
@computed get masterNodes() {
|
||||
return this.items.filter(node => node.getRoleLabels().includes("master"));
|
||||
}
|
||||
@@ -66,41 +44,9 @@ export class NodesStore extends KubeObjectStore<Node> {
|
||||
return this.items.filter(node => !node.getRoleLabels().includes("master"));
|
||||
}
|
||||
|
||||
getLastMetricValues(node: Node, metricNames: string[]): number[] {
|
||||
if (!this.metricsLoaded) {
|
||||
return [];
|
||||
}
|
||||
const nodeName = node.getName();
|
||||
|
||||
return metricNames.map(metricName => {
|
||||
try {
|
||||
const metric = this.metrics[metricName];
|
||||
const result = metric.data.result.find(result => {
|
||||
return [
|
||||
result.metric.node,
|
||||
result.metric.instance,
|
||||
result.metric.kubernetes_node,
|
||||
].includes(nodeName);
|
||||
});
|
||||
|
||||
return result ? parseFloat(result.values.slice(-1)[0][1]) : 0;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getWarningsCount(): number {
|
||||
return sum(this.items.map((node: Node) => node.getWarningConditions().length));
|
||||
}
|
||||
|
||||
reset() {
|
||||
super.reset();
|
||||
this.metrics = {};
|
||||
this.nodeMetrics = null;
|
||||
this.metricsLoading = false;
|
||||
this.metricsLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
export const nodesStore = new NodesStore();
|
||||
|
||||
@@ -28,7 +28,7 @@ import { TabLayout } from "../layout/tab-layout";
|
||||
import { nodesStore } from "./nodes.store";
|
||||
import { podsStore } from "../+workloads-pods/pods.store";
|
||||
import { KubeObjectListLayout } from "../kube-object";
|
||||
import type { Node } from "../../api/endpoints/nodes.api";
|
||||
import { getMetricsForAllNodes, INodeMetrics, Node } from "../../api/endpoints/nodes.api";
|
||||
import { LineProgress } from "../line-progress";
|
||||
import { bytesToUnits } from "../../utils/convertMemory";
|
||||
import { Tooltip, TooltipPosition } from "../tooltip";
|
||||
@@ -39,6 +39,8 @@ import { Badge } from "../badge/badge";
|
||||
import { kubeWatchApi } from "../../api/kube-watch-api";
|
||||
import { eventStore } from "../+events/event.store";
|
||||
import type { NodesRouteParams } from "../../../common/routes";
|
||||
import { observable } from "mobx";
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -58,7 +60,8 @@ interface Props extends RouteComponentProps<NodesRouteParams> {
|
||||
|
||||
@observer
|
||||
export class Nodes extends React.Component<Props> {
|
||||
private metricsWatcher = interval(30, () => nodesStore.loadUsageMetrics());
|
||||
@observable metrics: Partial<INodeMetrics> = {};
|
||||
private metricsWatcher = interval(30, async () => this.metrics = await getMetricsForAllNodes());
|
||||
|
||||
componentDidMount() {
|
||||
this.metricsWatcher.start(true);
|
||||
@@ -73,8 +76,32 @@ export class Nodes extends React.Component<Props> {
|
||||
this.metricsWatcher.stop();
|
||||
}
|
||||
|
||||
getLastMetricValues(node: Node, metricNames: string[]): number[] {
|
||||
if (isEmpty(this.metrics)) {
|
||||
return [];
|
||||
}
|
||||
const nodeName = node.getName();
|
||||
|
||||
return metricNames.map(metricName => {
|
||||
try {
|
||||
const metric = this.metrics[metricName];
|
||||
const result = metric.data.result.find(result => {
|
||||
return [
|
||||
result.metric.node,
|
||||
result.metric.instance,
|
||||
result.metric.kubernetes_node,
|
||||
].includes(nodeName);
|
||||
});
|
||||
|
||||
return result ? parseFloat(result.values.slice(-1)[0][1]) : 0;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderCpuUsage(node: Node) {
|
||||
const metrics = nodesStore.getLastMetricValues(node, ["cpuUsage", "cpuCapacity"]);
|
||||
const metrics = this.getLastMetricValues(node, ["cpuUsage", "cpuCapacity"]);
|
||||
|
||||
if (!metrics || !metrics[1]) return <LineProgress value={0}/>;
|
||||
const usage = metrics[0];
|
||||
@@ -97,7 +124,7 @@ export class Nodes extends React.Component<Props> {
|
||||
}
|
||||
|
||||
renderMemoryUsage(node: Node) {
|
||||
const metrics = nodesStore.getLastMetricValues(node, ["workloadMemoryUsage", "memoryAllocatableCapacity"]);
|
||||
const metrics = this.getLastMetricValues(node, ["workloadMemoryUsage", "memoryAllocatableCapacity"]);
|
||||
|
||||
if (!metrics || !metrics[1]) return <LineProgress value={0}/>;
|
||||
const usage = metrics[0];
|
||||
@@ -116,7 +143,7 @@ export class Nodes extends React.Component<Props> {
|
||||
}
|
||||
|
||||
renderDiskUsage(node: Node): any {
|
||||
const metrics = nodesStore.getLastMetricValues(node, ["fsUsage", "fsSize"]);
|
||||
const metrics = this.getLastMetricValues(node, ["fsUsage", "fsSize"]);
|
||||
|
||||
if (!metrics || !metrics[1]) return <LineProgress value={0}/>;
|
||||
const usage = metrics[0];
|
||||
@@ -172,9 +199,9 @@ export class Nodes extends React.Component<Props> {
|
||||
isSelectable={false}
|
||||
sortingCallbacks={{
|
||||
[columnId.name]: (node: Node) => node.getName(),
|
||||
[columnId.cpu]: (node: Node) => nodesStore.getLastMetricValues(node, ["cpuUsage"]),
|
||||
[columnId.memory]: (node: Node) => nodesStore.getLastMetricValues(node, ["memoryUsage"]),
|
||||
[columnId.disk]: (node: Node) => nodesStore.getLastMetricValues(node, ["fsUsage"]),
|
||||
[columnId.cpu]: (node: Node) => this.getLastMetricValues(node, ["cpuUsage"]),
|
||||
[columnId.memory]: (node: Node) => this.getLastMetricValues(node, ["memoryUsage"]),
|
||||
[columnId.disk]: (node: Node) => this.getLastMetricValues(node, ["fsUsage"]),
|
||||
[columnId.conditions]: (node: Node) => node.getNodeConditionText(),
|
||||
[columnId.taints]: (node: Node) => node.getTaints().length,
|
||||
[columnId.roles]: (node: Node) => node.getRoleLabels(),
|
||||
|
||||
Reference in new issue
Block a user