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:
parent
84c767a3d2
commit
c6a4d55d86
@ -62,6 +62,8 @@ export enum ClusterMetricsResourceType {
|
|||||||
VolumeClaim = "VolumeClaim",
|
VolumeClaim = "VolumeClaim",
|
||||||
ReplicaSet = "ReplicaSet",
|
ReplicaSet = "ReplicaSet",
|
||||||
DaemonSet = "DaemonSet",
|
DaemonSet = "DaemonSet",
|
||||||
|
Job = "Job",
|
||||||
|
Namespace = "Namespace"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ClusterRefreshOptions = {
|
export type ClusterRefreshOptions = {
|
||||||
|
|||||||
@ -26,30 +26,30 @@ import { KubeApi } from "../kube-api";
|
|||||||
export class ClusterApi extends KubeApi<Cluster> {
|
export class ClusterApi extends KubeApi<Cluster> {
|
||||||
static kind = "Cluster";
|
static kind = "Cluster";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
|
}
|
||||||
|
|
||||||
async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise<IClusterMetrics> {
|
export function getMetricsByNodeNames(nodeNames: string[], params?: IMetricsReqParams): Promise<IClusterMetrics> {
|
||||||
const nodes = nodeNames.join("|");
|
const nodes = nodeNames.join("|");
|
||||||
const opts = { category: "cluster", nodes };
|
const opts = { category: "cluster", nodes };
|
||||||
|
|
||||||
return metricsApi.getMetrics({
|
return metricsApi.getMetrics({
|
||||||
memoryUsage: opts,
|
memoryUsage: opts,
|
||||||
workloadMemoryUsage: opts,
|
workloadMemoryUsage: opts,
|
||||||
memoryRequests: opts,
|
memoryRequests: opts,
|
||||||
memoryLimits: opts,
|
memoryLimits: opts,
|
||||||
memoryCapacity: opts,
|
memoryCapacity: opts,
|
||||||
memoryAllocatableCapacity: opts,
|
memoryAllocatableCapacity: opts,
|
||||||
cpuUsage: opts,
|
cpuUsage: opts,
|
||||||
cpuRequests: opts,
|
cpuRequests: opts,
|
||||||
cpuLimits: opts,
|
cpuLimits: opts,
|
||||||
cpuCapacity: opts,
|
cpuCapacity: opts,
|
||||||
cpuAllocatableCapacity: opts,
|
cpuAllocatableCapacity: opts,
|
||||||
podUsage: opts,
|
podUsage: opts,
|
||||||
podCapacity: opts,
|
podCapacity: opts,
|
||||||
podAllocatableCapacity: opts,
|
podAllocatableCapacity: opts,
|
||||||
fsSize: opts,
|
fsSize: opts,
|
||||||
fsUsage: opts
|
fsUsage: opts
|
||||||
}, params);
|
}, params);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ClusterStatus {
|
export enum ClusterStatus {
|
||||||
|
|||||||
@ -20,11 +20,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import type { IPodContainer } from "./pods.api";
|
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import { autoBind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import { metricsApi } from "./metrics.api";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
import type { IPodContainer, IPodMetrics } from "./pods.api";
|
||||||
|
|
||||||
export class DaemonSet extends WorkloadKubeObject {
|
export class DaemonSet extends WorkloadKubeObject {
|
||||||
static kind = "DaemonSet";
|
static kind = "DaemonSet";
|
||||||
@ -97,6 +98,24 @@ export class DaemonSet extends WorkloadKubeObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const daemonSetApi = new KubeApi({
|
export class DaemonSetApi extends KubeApi<DaemonSet> {
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMetricsForDaemonSets(daemonsets: DaemonSet[], namespace: string, selector = ""): Promise<IPodMetrics> {
|
||||||
|
const podSelector = daemonsets.map(daemonset => `${daemonset.getName()}-[[:alnum:]]{5}`).join("|");
|
||||||
|
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||||
|
|
||||||
|
return metricsApi.getMetrics({
|
||||||
|
cpuUsage: opts,
|
||||||
|
memoryUsage: opts,
|
||||||
|
fsUsage: opts,
|
||||||
|
networkReceive: opts,
|
||||||
|
networkTransmit: opts,
|
||||||
|
}, {
|
||||||
|
namespace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const daemonSetApi = new DaemonSetApi({
|
||||||
objectConstructor: DaemonSet,
|
objectConstructor: DaemonSet,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import moment from "moment";
|
|||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import { autoBind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import { metricsApi } from "./metrics.api";
|
||||||
|
import type { IPodMetrics } from "./pods.api";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class DeploymentApi extends KubeApi<Deployment> {
|
export class DeploymentApi extends KubeApi<Deployment> {
|
||||||
@ -68,6 +70,21 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMetricsForDeployments(deployments: Deployment[], namespace: string, selector = ""): Promise<IPodMetrics> {
|
||||||
|
const podSelector = deployments.map(deployment => `${deployment.getName()}-[[:alnum:]]{9,}-[[:alnum:]]{5}`).join("|");
|
||||||
|
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||||
|
|
||||||
|
return metricsApi.getMetrics({
|
||||||
|
cpuUsage: opts,
|
||||||
|
memoryUsage: opts,
|
||||||
|
fsUsage: opts,
|
||||||
|
networkReceive: opts,
|
||||||
|
networkTransmit: opts,
|
||||||
|
}, {
|
||||||
|
namespace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
interface IContainerProbe {
|
interface IContainerProbe {
|
||||||
httpGet?: {
|
httpGet?: {
|
||||||
path?: string;
|
path?: string;
|
||||||
|
|||||||
@ -26,18 +26,19 @@ import { KubeApi } from "../kube-api";
|
|||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class IngressApi extends KubeApi<Ingress> {
|
export class IngressApi extends KubeApi<Ingress> {
|
||||||
getMetrics(ingress: string, namespace: string): Promise<IIngressMetrics> {
|
}
|
||||||
const opts = { category: "ingress", ingress, namespace };
|
|
||||||
|
|
||||||
return metricsApi.getMetrics({
|
export function getMetricsForIngress(ingress: string, namespace: string): Promise<IIngressMetrics> {
|
||||||
bytesSentSuccess: opts,
|
const opts = { category: "ingress", ingress };
|
||||||
bytesSentFailure: opts,
|
|
||||||
requestDurationSeconds: opts,
|
return metricsApi.getMetrics({
|
||||||
responseDurationSeconds: opts
|
bytesSentSuccess: opts,
|
||||||
}, {
|
bytesSentFailure: opts,
|
||||||
namespace,
|
requestDurationSeconds: opts,
|
||||||
});
|
responseDurationSeconds: opts
|
||||||
}
|
}, {
|
||||||
|
namespace,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IIngressMetrics<T = IMetrics> {
|
export interface IIngressMetrics<T = IMetrics> {
|
||||||
|
|||||||
@ -22,10 +22,11 @@
|
|||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import { autoBind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import type { IPodContainer } from "./pods.api";
|
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import { metricsApi } from "./metrics.api";
|
||||||
import type { JsonApiParams } from "../json-api";
|
import type { JsonApiParams } from "../json-api";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
import type { IPodContainer, IPodMetrics } from "./pods.api";
|
||||||
|
|
||||||
export class Job extends WorkloadKubeObject {
|
export class Job extends WorkloadKubeObject {
|
||||||
static kind = "Job";
|
static kind = "Job";
|
||||||
@ -129,6 +130,24 @@ export class Job extends WorkloadKubeObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const jobApi = new KubeApi({
|
export class JobApi extends KubeApi<Job> {
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMetricsForJobs(jobs: Job[], namespace: string, selector = ""): Promise<IPodMetrics> {
|
||||||
|
const podSelector = jobs.map(job => `${job.getName()}-[[:alnum:]]{5}`).join("|");
|
||||||
|
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||||
|
|
||||||
|
return metricsApi.getMetrics({
|
||||||
|
cpuUsage: opts,
|
||||||
|
memoryUsage: opts,
|
||||||
|
fsUsage: opts,
|
||||||
|
networkReceive: opts,
|
||||||
|
networkTransmit: opts,
|
||||||
|
}, {
|
||||||
|
namespace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const jobApi = new JobApi({
|
||||||
objectConstructor: Job,
|
objectConstructor: Job,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -60,6 +60,15 @@ export interface IMetricsReqParams {
|
|||||||
namespace?: string; // rbac-proxy validation param
|
namespace?: string; // rbac-proxy validation param
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IResourceMetrics<T extends IMetrics> {
|
||||||
|
[metric: string]: T;
|
||||||
|
cpuUsage: T;
|
||||||
|
memoryUsage: T;
|
||||||
|
fsUsage: T;
|
||||||
|
networkReceive: T;
|
||||||
|
networkTransmit: T;
|
||||||
|
}
|
||||||
|
|
||||||
export const metricsApi = {
|
export const metricsApi = {
|
||||||
async getMetrics<T = IMetricsQuery>(query: T, reqParams: IMetricsReqParams = {}): Promise<T extends object ? { [K in keyof T]: IMetrics } : IMetrics> {
|
async getMetrics<T = IMetricsQuery>(query: T, reqParams: IMetricsReqParams = {}): Promise<T extends object ? { [K in keyof T]: IMetrics } : IMetrics> {
|
||||||
const { range = 3600, step = 60, namespace } = reqParams;
|
const { range = 3600, step = 60, namespace } = reqParams;
|
||||||
|
|||||||
@ -22,6 +22,8 @@
|
|||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { autoBind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
|
import { metricsApi } from "./metrics.api";
|
||||||
|
import type { IPodMetrics } from "./pods.api";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export enum NamespaceStatus {
|
export enum NamespaceStatus {
|
||||||
@ -50,6 +52,23 @@ export class Namespace extends KubeObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const namespacesApi = new KubeApi({
|
export class NamespaceApi extends KubeApi<Namespace> {
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMetricsForNamespace(namespace: string, selector = ""): Promise<IPodMetrics> {
|
||||||
|
const opts = { category: "pods", pods: ".*", namespace, selector };
|
||||||
|
|
||||||
|
return metricsApi.getMetrics({
|
||||||
|
cpuUsage: opts,
|
||||||
|
memoryUsage: opts,
|
||||||
|
fsUsage: opts,
|
||||||
|
networkReceive: opts,
|
||||||
|
networkTransmit: opts,
|
||||||
|
}, {
|
||||||
|
namespace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const namespacesApi = new NamespaceApi({
|
||||||
objectConstructor: Namespace,
|
objectConstructor: Namespace,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -26,20 +26,21 @@ import { KubeApi } from "../kube-api";
|
|||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class NodesApi extends KubeApi<Node> {
|
export class NodesApi extends KubeApi<Node> {
|
||||||
getMetrics(): Promise<INodeMetrics> {
|
}
|
||||||
const opts = { category: "nodes" };
|
|
||||||
|
|
||||||
return metricsApi.getMetrics({
|
export function getMetricsForAllNodes(): Promise<INodeMetrics> {
|
||||||
memoryUsage: opts,
|
const opts = { category: "nodes"};
|
||||||
workloadMemoryUsage: opts,
|
|
||||||
memoryCapacity: opts,
|
return metricsApi.getMetrics({
|
||||||
memoryAllocatableCapacity: opts,
|
memoryUsage: opts,
|
||||||
cpuUsage: opts,
|
workloadMemoryUsage: opts,
|
||||||
cpuCapacity: opts,
|
memoryCapacity: opts,
|
||||||
fsSize: opts,
|
memoryAllocatableCapacity: opts,
|
||||||
fsUsage: opts
|
cpuUsage: opts,
|
||||||
});
|
cpuCapacity: opts,
|
||||||
}
|
fsSize: opts,
|
||||||
|
fsUsage: opts
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INodeMetrics<T = IMetrics> {
|
export interface INodeMetrics<T = IMetrics> {
|
||||||
|
|||||||
@ -27,14 +27,15 @@ import { KubeApi } from "../kube-api";
|
|||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
|
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
|
||||||
getMetrics(pvcName: string, namespace: string): Promise<IPvcMetrics> {
|
}
|
||||||
return metricsApi.getMetrics({
|
|
||||||
diskUsage: { category: "pvc", pvc: pvcName, namespace },
|
export function getMetricsForPvc(pvc: PersistentVolumeClaim): Promise<IPvcMetrics> {
|
||||||
diskCapacity: { category: "pvc", pvc: pvcName, namespace }
|
return metricsApi.getMetrics({
|
||||||
}, {
|
diskUsage: { category: "pvc", pvc: pvc.getName() },
|
||||||
namespace
|
diskCapacity: { category: "pvc", pvc: pvc.getName() }
|
||||||
});
|
}, {
|
||||||
}
|
namespace: pvc.getNs()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPvcMetrics<T = IMetrics> {
|
export interface IPvcMetrics<T = IMetrics> {
|
||||||
|
|||||||
@ -31,38 +31,38 @@ export class PodsApi extends KubeApi<Pod> {
|
|||||||
|
|
||||||
return this.request.get(path, { query });
|
return this.request.get(path, { query });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise<IPodMetrics> {
|
export function getMetricsForPods(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise<IPodMetrics> {
|
||||||
const podSelector = pods.map(pod => pod.getName()).join("|");
|
const podSelector = pods.map(pod => pod.getName()).join("|");
|
||||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||||
|
|
||||||
return metricsApi.getMetrics({
|
return metricsApi.getMetrics({
|
||||||
cpuUsage: opts,
|
cpuUsage: opts,
|
||||||
cpuRequests: opts,
|
cpuRequests: opts,
|
||||||
cpuLimits: opts,
|
cpuLimits: opts,
|
||||||
memoryUsage: opts,
|
memoryUsage: opts,
|
||||||
memoryRequests: opts,
|
memoryRequests: opts,
|
||||||
memoryLimits: opts,
|
memoryLimits: opts,
|
||||||
fsUsage: opts,
|
fsUsage: opts,
|
||||||
networkReceive: opts,
|
networkReceive: opts,
|
||||||
networkTransmit: opts,
|
networkTransmit: opts,
|
||||||
}, {
|
}, {
|
||||||
namespace,
|
namespace,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPodMetrics<T = IMetrics> {
|
export interface IPodMetrics<T = IMetrics> {
|
||||||
[metric: string]: T;
|
[metric: string]: T;
|
||||||
cpuUsage: T;
|
cpuUsage: T;
|
||||||
cpuRequests: T;
|
|
||||||
cpuLimits: T;
|
|
||||||
memoryUsage: T;
|
memoryUsage: T;
|
||||||
memoryRequests: T;
|
|
||||||
memoryLimits: T;
|
|
||||||
fsUsage: T;
|
fsUsage: T;
|
||||||
networkReceive: T;
|
networkReceive: T;
|
||||||
networkTransmit: T;
|
networkTransmit: T;
|
||||||
|
cpuRequests?: T;
|
||||||
|
cpuLimits?: T;
|
||||||
|
memoryRequests?: T;
|
||||||
|
memoryLimits?: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#read-log-pod-v1-core
|
// Reference: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#read-log-pod-v1-core
|
||||||
|
|||||||
@ -22,8 +22,9 @@
|
|||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import { autoBind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { WorkloadKubeObject } from "../workload-kube-object";
|
import { WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import type { IPodContainer, Pod } from "./pods.api";
|
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import { metricsApi } from "./metrics.api";
|
||||||
|
import type { IPodContainer, IPodMetrics, Pod } from "./pods.api";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||||
@ -49,6 +50,21 @@ export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMetricsForReplicaSets(replicasets: ReplicaSet[], namespace: string, selector = ""): Promise<IPodMetrics> {
|
||||||
|
const podSelector = replicasets.map(replicaset => `${replicaset.getName()}-[[:alnum:]]{5}`).join("|");
|
||||||
|
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||||
|
|
||||||
|
return metricsApi.getMetrics({
|
||||||
|
cpuUsage: opts,
|
||||||
|
memoryUsage: opts,
|
||||||
|
fsUsage: opts,
|
||||||
|
networkReceive: opts,
|
||||||
|
networkTransmit: opts,
|
||||||
|
}, {
|
||||||
|
namespace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export class ReplicaSet extends WorkloadKubeObject {
|
export class ReplicaSet extends WorkloadKubeObject {
|
||||||
static kind = "ReplicaSet";
|
static kind = "ReplicaSet";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
|
|||||||
@ -20,10 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import type { IPodContainer } from "./pods.api";
|
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import { autoBind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import { metricsApi } from "./metrics.api";
|
||||||
|
import type { IPodContainer, IPodMetrics } from "./pods.api";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class StatefulSetApi extends KubeApi<StatefulSet> {
|
export class StatefulSetApi extends KubeApi<StatefulSet> {
|
||||||
@ -49,6 +50,21 @@ export class StatefulSetApi extends KubeApi<StatefulSet> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMetricsForStatefulSets(statefulSets: StatefulSet[], namespace: string, selector = ""): Promise<IPodMetrics> {
|
||||||
|
const podSelector = statefulSets.map(statefulset => `${statefulset.getName()}-[[:digit:]]+`).join("|");
|
||||||
|
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||||
|
|
||||||
|
return metricsApi.getMetrics({
|
||||||
|
cpuUsage: opts,
|
||||||
|
memoryUsage: opts,
|
||||||
|
fsUsage: opts,
|
||||||
|
networkReceive: opts,
|
||||||
|
networkTransmit: opts,
|
||||||
|
}, {
|
||||||
|
namespace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export class StatefulSet extends WorkloadKubeObject {
|
export class StatefulSet extends WorkloadKubeObject {
|
||||||
static kind = "StatefulSet";
|
static kind = "StatefulSet";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import { action, observable, reaction, when, makeObservable } from "mobx";
|
import { action, observable, reaction, when, makeObservable } from "mobx";
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
import { Cluster, clusterApi, IClusterMetrics } from "../../api/endpoints";
|
import { Cluster, clusterApi, getMetricsByNodeNames, IClusterMetrics } from "../../api/endpoints";
|
||||||
import { autoBind, createStorage } from "../../utils";
|
import { autoBind, createStorage } from "../../utils";
|
||||||
import { IMetricsReqParams, normalizeMetrics } from "../../api/endpoints/metrics.api";
|
import { IMetricsReqParams, normalizeMetrics } from "../../api/endpoints/metrics.api";
|
||||||
import { nodesStore } from "../+nodes/nodes.store";
|
import { nodesStore } from "../+nodes/nodes.store";
|
||||||
@ -101,7 +101,7 @@ export class ClusterOverviewStore extends KubeObjectStore<Cluster> implements Cl
|
|||||||
const { masterNodes, workerNodes } = nodesStore;
|
const { masterNodes, workerNodes } = nodesStore;
|
||||||
const nodes = this.metricNodeRole === MetricNodeRole.MASTER && masterNodes.length ? masterNodes : workerNodes;
|
const nodes = this.metricNodeRole === MetricNodeRole.MASTER && masterNodes.length ? masterNodes : workerNodes;
|
||||||
|
|
||||||
this.metrics = await clusterApi.getMetrics(nodes.map(node => node.getName()), params);
|
this.metrics = await getMetricsByNodeNames(nodes.map(node => node.getName()), params);
|
||||||
this.metricsLoaded = true;
|
this.metricsLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,28 +22,44 @@
|
|||||||
import "./namespace-details.scss";
|
import "./namespace-details.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { computed, makeObservable } from "mobx";
|
import { computed, makeObservable, observable, reaction } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { DrawerItem } from "../drawer";
|
import { DrawerItem } from "../drawer";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import type { Namespace } from "../../api/endpoints";
|
import { getMetricsForNamespace, IPodMetrics, Namespace } from "../../api/endpoints";
|
||||||
import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object";
|
import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Spinner } from "../spinner";
|
import { Spinner } from "../spinner";
|
||||||
import { resourceQuotaStore } from "../+config-resource-quotas/resource-quotas.store";
|
import { resourceQuotaStore } from "../+config-resource-quotas/resource-quotas.store";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
import { limitRangeStore } from "../+config-limit-ranges/limit-ranges.store";
|
import { limitRangeStore } from "../+config-limit-ranges/limit-ranges.store";
|
||||||
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
|
|
||||||
interface Props extends KubeObjectDetailsProps<Namespace> {
|
interface Props extends KubeObjectDetailsProps<Namespace> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class NamespaceDetails extends React.Component<Props> {
|
export class NamespaceDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPodMetrics = null;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@disposeOnUnmount
|
||||||
|
clean = reaction(() => this.props.object, () => {
|
||||||
|
this.metrics = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
resourceQuotaStore.reloadAll();
|
||||||
|
limitRangeStore.reloadAll();
|
||||||
|
}
|
||||||
|
|
||||||
@computed get quotas() {
|
@computed get quotas() {
|
||||||
const namespace = this.props.object.getName();
|
const namespace = this.props.object.getName();
|
||||||
|
|
||||||
@ -56,9 +72,8 @@ export class NamespaceDetails extends React.Component<Props> {
|
|||||||
return limitRangeStore.getAllByNs(namespace);
|
return limitRangeStore.getAllByNs(namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
async loadMetrics() {
|
||||||
resourceQuotaStore.reloadAll();
|
this.metrics = await getMetricsForNamespace(this.props.object.getName(), "");
|
||||||
limitRangeStore.reloadAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -66,9 +81,18 @@ export class NamespaceDetails extends React.Component<Props> {
|
|||||||
|
|
||||||
if (!namespace) return null;
|
if (!namespace) return null;
|
||||||
const status = namespace.getStatus();
|
const status = namespace.getStatus();
|
||||||
|
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Namespace);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="NamespaceDetails">
|
<div className="NamespaceDetails">
|
||||||
|
{!isMetricHidden && (
|
||||||
|
<ResourceMetrics
|
||||||
|
loader={this.loadMetrics}
|
||||||
|
tabs={podMetricTabs} object={namespace} params={{ metrics: this.metrics }}
|
||||||
|
>
|
||||||
|
<PodCharts />
|
||||||
|
</ResourceMetrics>
|
||||||
|
)}
|
||||||
<KubeObjectMeta object={namespace}/>
|
<KubeObjectMeta object={namespace}/>
|
||||||
|
|
||||||
<DrawerItem name="Status">
|
<DrawerItem name="Status">
|
||||||
|
|||||||
@ -23,16 +23,15 @@ import "./ingress-details.scss";
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { reaction } from "mobx";
|
import { observable, reaction } from "mobx";
|
||||||
import { DrawerItem, DrawerTitle } from "../drawer";
|
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||||
import type { ILoadBalancerIngress, Ingress } from "../../api/endpoints";
|
import type { ILoadBalancerIngress, Ingress } from "../../api/endpoints";
|
||||||
import { Table, TableCell, TableHead, TableRow } from "../table";
|
import { Table, TableCell, TableHead, TableRow } from "../table";
|
||||||
import { ingressStore } from "./ingress.store";
|
|
||||||
import { ResourceMetrics } from "../resource-metrics";
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
import type { KubeObjectDetailsProps } from "../kube-object";
|
import type { KubeObjectDetailsProps } from "../kube-object";
|
||||||
import { IngressCharts } from "./ingress-charts";
|
import { IngressCharts } from "./ingress-charts";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
import { getBackendServiceNamePort } from "../../api/endpoints/ingress.api";
|
import { getBackendServiceNamePort, getMetricsForIngress, IIngressMetrics } from "../../api/endpoints/ingress.api";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
|
||||||
@ -41,13 +40,17 @@ interface Props extends KubeObjectDetailsProps<Ingress> {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class IngressDetails extends React.Component<Props> {
|
export class IngressDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IIngressMetrics = null;
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
clean = reaction(() => this.props.object, () => {
|
clean = reaction(() => this.props.object, () => {
|
||||||
ingressStore.reset();
|
this.metrics = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
componentWillUnmount() {
|
async loadMetrics() {
|
||||||
ingressStore.reset();
|
const { object: ingress } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsForIngress(ingress.getName(), ingress.getNs());
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPaths(ingress: Ingress) {
|
renderPaths(ingress: Ingress) {
|
||||||
@ -124,7 +127,7 @@ export class IngressDetails extends React.Component<Props> {
|
|||||||
|
|
||||||
const { spec, status } = ingress;
|
const { spec, status } = ingress;
|
||||||
const ingressPoints = status?.loadBalancer?.ingress;
|
const ingressPoints = status?.loadBalancer?.ingress;
|
||||||
const { metrics } = ingressStore;
|
const { metrics } = this;
|
||||||
const metricTabs = [
|
const metricTabs = [
|
||||||
"Network",
|
"Network",
|
||||||
"Duration",
|
"Duration",
|
||||||
@ -136,7 +139,7 @@ export class IngressDetails extends React.Component<Props> {
|
|||||||
<div className="IngressDetails">
|
<div className="IngressDetails">
|
||||||
{!isMetricHidden && (
|
{!isMetricHidden && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => ingressStore.loadMetrics(ingress)}
|
loader={this.loadMetrics}
|
||||||
tabs={metricTabs} object={ingress} params={{ metrics }}
|
tabs={metricTabs} object={ingress} params={{ metrics }}
|
||||||
>
|
>
|
||||||
<IngressCharts/>
|
<IngressCharts/>
|
||||||
|
|||||||
@ -18,31 +18,12 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { observable, makeObservable } from "mobx";
|
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
|
||||||
import { autoBind } from "../../utils";
|
|
||||||
import { IIngressMetrics, Ingress, ingressApi } from "../../api/endpoints";
|
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
import { Ingress, ingressApi } from "../../api/endpoints";
|
||||||
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
|
|
||||||
export class IngressStore extends KubeObjectStore<Ingress> {
|
export class IngressStore extends KubeObjectStore<Ingress> {
|
||||||
api = ingressApi;
|
api = ingressApi;
|
||||||
@observable metrics: IIngressMetrics = null;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
makeObservable(this);
|
|
||||||
autoBind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadMetrics(ingress: Ingress) {
|
|
||||||
this.metrics = await this.api.getMetrics(ingress.getName(), ingress.getNs());
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.metrics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ingressStore = new IngressStore();
|
export const ingressStore = new IngressStore();
|
||||||
|
|||||||
@ -27,36 +27,46 @@ import kebabCase from "lodash/kebabCase";
|
|||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { DrawerItem, DrawerItemLabels } from "../drawer";
|
import { DrawerItem, DrawerItemLabels } from "../drawer";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import { nodesStore } from "./nodes.store";
|
|
||||||
import { ResourceMetrics } from "../resource-metrics";
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import type { KubeObjectDetailsProps } from "../kube-object";
|
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 { NodeCharts } from "./node-charts";
|
||||||
import { reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
import { NodeDetailsResources } from "./node-details-resources";
|
import { NodeDetailsResources } from "./node-details-resources";
|
||||||
import { DrawerTitle } from "../drawer/drawer-title";
|
import { DrawerTitle } from "../drawer/drawer-title";
|
||||||
|
import { boundMethod } from "../../utils";
|
||||||
|
|
||||||
interface Props extends KubeObjectDetailsProps<Node> {
|
interface Props extends KubeObjectDetailsProps<Node> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class NodeDetails extends React.Component<Props> {
|
export class NodeDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: Partial<IClusterMetrics>;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
clean = reaction(() => this.props.object.getName(), () => {
|
clean = reaction(() => this.props.object.getName(), () => {
|
||||||
nodesStore.nodeMetrics = null;
|
this.metrics = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
podsStore.reloadAll();
|
podsStore.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
@boundMethod
|
||||||
nodesStore.nodeMetrics = null;
|
async loadMetrics() {
|
||||||
|
const { object: node } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsByNodeNames([node.getName()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -68,7 +78,7 @@ export class NodeDetails extends React.Component<Props> {
|
|||||||
const conditions = node.getActiveConditions();
|
const conditions = node.getActiveConditions();
|
||||||
const taints = node.getTaints();
|
const taints = node.getTaints();
|
||||||
const childPods = podsStore.getPodsByNode(node.getName());
|
const childPods = podsStore.getPodsByNode(node.getName());
|
||||||
const metrics = nodesStore.nodeMetrics;
|
const { metrics } = this;
|
||||||
const metricTabs = [
|
const metricTabs = [
|
||||||
"CPU",
|
"CPU",
|
||||||
"Memory",
|
"Memory",
|
||||||
@ -81,7 +91,7 @@ export class NodeDetails extends React.Component<Props> {
|
|||||||
<div className="NodeDetails">
|
<div className="NodeDetails">
|
||||||
{!isMetricHidden && podsStore.isLoaded && (
|
{!isMetricHidden && podsStore.isLoaded && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => nodesStore.loadMetrics(node.getName())}
|
loader={this.loadMetrics}
|
||||||
tabs={metricTabs} object={node} params={{ metrics }}
|
tabs={metricTabs} object={node} params={{ metrics }}
|
||||||
>
|
>
|
||||||
<NodeCharts/>
|
<NodeCharts/>
|
||||||
|
|||||||
@ -18,22 +18,17 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { sum } from "lodash";
|
import { sum } from "lodash";
|
||||||
import { action, computed, observable, makeObservable } from "mobx";
|
import { computed, makeObservable } from "mobx";
|
||||||
import { clusterApi, IClusterMetrics, INodeMetrics, Node, nodesApi } from "../../api/endpoints";
|
|
||||||
import { autoBind } from "../../utils";
|
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
|
||||||
import { apiManager } from "../../api/api-manager";
|
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> {
|
export class NodesStore extends KubeObjectStore<Node> {
|
||||||
api = nodesApi;
|
api = nodesApi;
|
||||||
|
|
||||||
@observable metrics: Partial<INodeMetrics> = {};
|
|
||||||
@observable nodeMetrics: Partial<IClusterMetrics> = null;
|
|
||||||
@observable metricsLoading = false;
|
|
||||||
@observable metricsLoaded = false;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -41,23 +36,6 @@ export class NodesStore extends KubeObjectStore<Node> {
|
|||||||
autoBind(this);
|
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() {
|
@computed get masterNodes() {
|
||||||
return this.items.filter(node => node.getRoleLabels().includes("master"));
|
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"));
|
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 {
|
getWarningsCount(): number {
|
||||||
return sum(this.items.map((node: Node) => node.getWarningConditions().length));
|
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();
|
export const nodesStore = new NodesStore();
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import { TabLayout } from "../layout/tab-layout";
|
|||||||
import { nodesStore } from "./nodes.store";
|
import { nodesStore } from "./nodes.store";
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { KubeObjectListLayout } from "../kube-object";
|
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 { LineProgress } from "../line-progress";
|
||||||
import { bytesToUnits } from "../../utils/convertMemory";
|
import { bytesToUnits } from "../../utils/convertMemory";
|
||||||
import { Tooltip, TooltipPosition } from "../tooltip";
|
import { Tooltip, TooltipPosition } from "../tooltip";
|
||||||
@ -39,6 +39,8 @@ import { Badge } from "../badge/badge";
|
|||||||
import { kubeWatchApi } from "../../api/kube-watch-api";
|
import { kubeWatchApi } from "../../api/kube-watch-api";
|
||||||
import { eventStore } from "../+events/event.store";
|
import { eventStore } from "../+events/event.store";
|
||||||
import type { NodesRouteParams } from "../../../common/routes";
|
import type { NodesRouteParams } from "../../../common/routes";
|
||||||
|
import { observable } from "mobx";
|
||||||
|
import isEmpty from "lodash/isEmpty";
|
||||||
|
|
||||||
enum columnId {
|
enum columnId {
|
||||||
name = "name",
|
name = "name",
|
||||||
@ -58,7 +60,8 @@ interface Props extends RouteComponentProps<NodesRouteParams> {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Nodes extends React.Component<Props> {
|
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() {
|
componentDidMount() {
|
||||||
this.metricsWatcher.start(true);
|
this.metricsWatcher.start(true);
|
||||||
@ -73,8 +76,32 @@ export class Nodes extends React.Component<Props> {
|
|||||||
this.metricsWatcher.stop();
|
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) {
|
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}/>;
|
if (!metrics || !metrics[1]) return <LineProgress value={0}/>;
|
||||||
const usage = metrics[0];
|
const usage = metrics[0];
|
||||||
@ -97,7 +124,7 @@ export class Nodes extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderMemoryUsage(node: Node) {
|
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}/>;
|
if (!metrics || !metrics[1]) return <LineProgress value={0}/>;
|
||||||
const usage = metrics[0];
|
const usage = metrics[0];
|
||||||
@ -116,7 +143,7 @@ export class Nodes extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderDiskUsage(node: Node): any {
|
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}/>;
|
if (!metrics || !metrics[1]) return <LineProgress value={0}/>;
|
||||||
const usage = metrics[0];
|
const usage = metrics[0];
|
||||||
@ -172,9 +199,9 @@ export class Nodes extends React.Component<Props> {
|
|||||||
isSelectable={false}
|
isSelectable={false}
|
||||||
sortingCallbacks={{
|
sortingCallbacks={{
|
||||||
[columnId.name]: (node: Node) => node.getName(),
|
[columnId.name]: (node: Node) => node.getName(),
|
||||||
[columnId.cpu]: (node: Node) => nodesStore.getLastMetricValues(node, ["cpuUsage"]),
|
[columnId.cpu]: (node: Node) => this.getLastMetricValues(node, ["cpuUsage"]),
|
||||||
[columnId.memory]: (node: Node) => nodesStore.getLastMetricValues(node, ["memoryUsage"]),
|
[columnId.memory]: (node: Node) => this.getLastMetricValues(node, ["memoryUsage"]),
|
||||||
[columnId.disk]: (node: Node) => nodesStore.getLastMetricValues(node, ["fsUsage"]),
|
[columnId.disk]: (node: Node) => this.getLastMetricValues(node, ["fsUsage"]),
|
||||||
[columnId.conditions]: (node: Node) => node.getNodeConditionText(),
|
[columnId.conditions]: (node: Node) => node.getNodeConditionText(),
|
||||||
[columnId.taints]: (node: Node) => node.getTaints().length,
|
[columnId.taints]: (node: Node) => node.getTaints().length,
|
||||||
[columnId.roles]: (node: Node) => node.getRoleLabels(),
|
[columnId.roles]: (node: Node) => node.getRoleLabels(),
|
||||||
|
|||||||
@ -22,17 +22,16 @@
|
|||||||
import "./volume-claim-details.scss";
|
import "./volume-claim-details.scss";
|
||||||
|
|
||||||
import React, { Fragment } from "react";
|
import React, { Fragment } from "react";
|
||||||
import { reaction } from "mobx";
|
import { action, observable, reaction } from "mobx";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { DrawerItem, DrawerTitle } from "../drawer";
|
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { volumeClaimStore } from "./volume-claim.store";
|
|
||||||
import { ResourceMetrics } from "../resource-metrics";
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
import { VolumeClaimDiskChart } from "./volume-claim-disk-chart";
|
import { VolumeClaimDiskChart } from "./volume-claim-disk-chart";
|
||||||
import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object";
|
import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object";
|
||||||
import type { PersistentVolumeClaim } from "../../api/endpoints";
|
import { getMetricsForPvc, IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
|
||||||
@ -41,13 +40,18 @@ interface Props extends KubeObjectDetailsProps<PersistentVolumeClaim> {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class PersistentVolumeClaimDetails extends React.Component<Props> {
|
export class PersistentVolumeClaimDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPvcMetrics = null;
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
clean = reaction(() => this.props.object, () => {
|
clean = reaction(() => this.props.object, () => {
|
||||||
volumeClaimStore.reset();
|
this.metrics = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
componentWillUnmount() {
|
@action
|
||||||
volumeClaimStore.reset();
|
async loadMetrics() {
|
||||||
|
const { object: volumeClaim } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsForPvc(volumeClaim);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -57,7 +61,7 @@ export class PersistentVolumeClaimDetails extends React.Component<Props> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { storageClassName, accessModes } = volumeClaim.spec;
|
const { storageClassName, accessModes } = volumeClaim.spec;
|
||||||
const { metrics } = volumeClaimStore;
|
const { metrics } = this;
|
||||||
const pods = volumeClaim.getPods(podsStore.items);
|
const pods = volumeClaim.getPods(podsStore.items);
|
||||||
const metricTabs = [
|
const metricTabs = [
|
||||||
"Disk"
|
"Disk"
|
||||||
@ -68,7 +72,7 @@ export class PersistentVolumeClaimDetails extends React.Component<Props> {
|
|||||||
<div className="PersistentVolumeClaimDetails">
|
<div className="PersistentVolumeClaimDetails">
|
||||||
{!isMetricHidden && (
|
{!isMetricHidden && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => volumeClaimStore.loadMetrics(volumeClaim)}
|
loader={this.loadMetrics}
|
||||||
tabs={metricTabs} object={volumeClaim} params={{ metrics }}
|
tabs={metricTabs} object={volumeClaim} params={{ metrics }}
|
||||||
>
|
>
|
||||||
<VolumeClaimDiskChart/>
|
<VolumeClaimDiskChart/>
|
||||||
|
|||||||
@ -18,32 +18,12 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, observable, makeObservable } from "mobx";
|
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
|
||||||
import { autoBind } from "../../utils";
|
|
||||||
import { IPvcMetrics, PersistentVolumeClaim, pvcApi } from "../../api/endpoints";
|
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
import { PersistentVolumeClaim, pvcApi } from "../../api/endpoints";
|
||||||
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
|
|
||||||
export class VolumeClaimStore extends KubeObjectStore<PersistentVolumeClaim> {
|
export class VolumeClaimStore extends KubeObjectStore<PersistentVolumeClaim> {
|
||||||
api = pvcApi;
|
api = pvcApi;
|
||||||
@observable metrics: IPvcMetrics = null;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
makeObservable(this);
|
|
||||||
autoBind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
async loadMetrics(pvc: PersistentVolumeClaim) {
|
|
||||||
this.metrics = await pvcApi.getMetrics(pvc.getName(), pvc.getNs());
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.metrics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const volumeClaimStore = new VolumeClaimStore();
|
export const volumeClaimStore = new VolumeClaimStore();
|
||||||
|
|||||||
@ -31,31 +31,42 @@ import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"
|
|||||||
import { daemonSetStore } from "./daemonsets.store";
|
import { daemonSetStore } from "./daemonsets.store";
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import type { KubeObjectDetailsProps } from "../kube-object";
|
import type { KubeObjectDetailsProps } from "../kube-object";
|
||||||
import type { DaemonSet } from "../../api/endpoints";
|
import { DaemonSet, getMetricsForDaemonSets, IPodMetrics } from "../../api/endpoints";
|
||||||
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
||||||
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
import { reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
import { boundMethod } from "../../utils";
|
||||||
|
|
||||||
interface Props extends KubeObjectDetailsProps<DaemonSet> {
|
interface Props extends KubeObjectDetailsProps<DaemonSet> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class DaemonSetDetails extends React.Component<Props> {
|
export class DaemonSetDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPodMetrics = null;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
clean = reaction(() => this.props.object, () => {
|
clean = reaction(() => this.props.object, () => {
|
||||||
daemonSetStore.reset();
|
this.metrics = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
podsStore.reloadAll();
|
podsStore.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
@boundMethod
|
||||||
daemonSetStore.reset();
|
async loadMetrics() {
|
||||||
|
const { object: daemonSet } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsForDaemonSets([daemonSet], daemonSet.getNs(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -67,15 +78,14 @@ export class DaemonSetDetails extends React.Component<Props> {
|
|||||||
const images = daemonSet.getImages();
|
const images = daemonSet.getImages();
|
||||||
const nodeSelector = daemonSet.getNodeSelectors();
|
const nodeSelector = daemonSet.getNodeSelectors();
|
||||||
const childPods = daemonSetStore.getChildPods(daemonSet);
|
const childPods = daemonSetStore.getChildPods(daemonSet);
|
||||||
const metrics = daemonSetStore.metrics;
|
|
||||||
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.DaemonSet);
|
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.DaemonSet);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="DaemonSetDetails">
|
<div className="DaemonSetDetails">
|
||||||
{!isMetricHidden && podsStore.isLoaded && (
|
{!isMetricHidden && podsStore.isLoaded && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => daemonSetStore.loadMetrics(daemonSet)}
|
loader={this.loadMetrics}
|
||||||
tabs={podMetricTabs} object={daemonSet} params={{ metrics }}
|
tabs={podMetricTabs} object={daemonSet} params={{ metrics: this.metrics }}
|
||||||
>
|
>
|
||||||
<PodCharts/>
|
<PodCharts/>
|
||||||
</ResourceMetrics>
|
</ResourceMetrics>
|
||||||
@ -110,7 +120,7 @@ export class DaemonSetDetails extends React.Component<Props> {
|
|||||||
<DrawerItem name="Pod Status" className="pod-status">
|
<DrawerItem name="Pod Status" className="pod-status">
|
||||||
<PodDetailsStatuses pods={childPods}/>
|
<PodDetailsStatuses pods={childPods}/>
|
||||||
</DrawerItem>
|
</DrawerItem>
|
||||||
<ResourceMetricsText metrics={metrics}/>
|
<ResourceMetricsText metrics={this.metrics}/>
|
||||||
<PodDetailsList pods={childPods} owner={daemonSet}/>
|
<PodDetailsList pods={childPods} owner={daemonSet}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -18,19 +18,17 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
import { makeObservable } from "mobx";
|
||||||
|
|
||||||
import { observable, makeObservable } from "mobx";
|
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
|
||||||
import { autoBind } from "../../utils";
|
|
||||||
import { DaemonSet, daemonSetApi, IPodMetrics, Pod, podsApi, PodStatus } from "../../api/endpoints";
|
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
import { DaemonSet, daemonSetApi, Pod, PodStatus } from "../../api/endpoints";
|
||||||
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
|
import { autoBind } from "../../utils";
|
||||||
|
|
||||||
export class DaemonSetStore extends KubeObjectStore<DaemonSet> {
|
export class DaemonSetStore extends KubeObjectStore<DaemonSet> {
|
||||||
api = daemonSetApi;
|
api = daemonSetApi;
|
||||||
|
|
||||||
@observable metrics: IPodMetrics = null;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -38,12 +36,6 @@ export class DaemonSetStore extends KubeObjectStore<DaemonSet> {
|
|||||||
autoBind(this);
|
autoBind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadMetrics(daemonSet: DaemonSet) {
|
|
||||||
const pods = this.getChildPods(daemonSet);
|
|
||||||
|
|
||||||
this.metrics = await podsApi.getMetrics(pods, daemonSet.getNs(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
getChildPods(daemonSet: DaemonSet): Pod[] {
|
getChildPods(daemonSet: DaemonSet): Pod[] {
|
||||||
return podsStore.getPodsByOwnerId(daemonSet.getId());
|
return podsStore.getPodsByOwnerId(daemonSet.getId());
|
||||||
}
|
}
|
||||||
@ -67,10 +59,6 @@ export class DaemonSetStore extends KubeObjectStore<DaemonSet> {
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.metrics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const daemonSetStore = new DaemonSetStore();
|
export const daemonSetStore = new DaemonSetStore();
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import kebabCase from "lodash/kebabCase";
|
|||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { DrawerItem } from "../drawer";
|
import { DrawerItem } from "../drawer";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import type { Deployment } from "../../api/endpoints";
|
import { Deployment, getMetricsForDeployments, IPodMetrics } from "../../api/endpoints";
|
||||||
import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations";
|
import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations";
|
||||||
import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities";
|
import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities";
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
@ -34,22 +34,30 @@ import type { KubeObjectDetailsProps } from "../kube-object";
|
|||||||
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
||||||
import { deploymentStore } from "./deployments.store";
|
import { deploymentStore } from "./deployments.store";
|
||||||
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
import { reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
import { replicaSetStore } from "../+workloads-replicasets/replicasets.store";
|
import { replicaSetStore } from "../+workloads-replicasets/replicasets.store";
|
||||||
import { DeploymentReplicaSets } from "./deployment-replicasets";
|
import { DeploymentReplicaSets } from "./deployment-replicasets";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
import { boundMethod } from "../../utils";
|
||||||
|
|
||||||
interface Props extends KubeObjectDetailsProps<Deployment> {
|
interface Props extends KubeObjectDetailsProps<Deployment> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class DeploymentDetails extends React.Component<Props> {
|
export class DeploymentDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPodMetrics = null;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
clean = reaction(() => this.props.object, () => {
|
clean = reaction(() => this.props.object, () => {
|
||||||
deploymentStore.reset();
|
this.metrics = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -57,8 +65,11 @@ export class DeploymentDetails extends React.Component<Props> {
|
|||||||
replicaSetStore.reloadAll();
|
replicaSetStore.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
@boundMethod
|
||||||
deploymentStore.reset();
|
async loadMetrics() {
|
||||||
|
const { object: deployment } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsForDeployments([deployment], deployment.getNs(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -70,15 +81,14 @@ export class DeploymentDetails extends React.Component<Props> {
|
|||||||
const selectors = deployment.getSelectors();
|
const selectors = deployment.getSelectors();
|
||||||
const childPods = deploymentStore.getChildPods(deployment);
|
const childPods = deploymentStore.getChildPods(deployment);
|
||||||
const replicaSets = replicaSetStore.getReplicaSetsByOwner(deployment);
|
const replicaSets = replicaSetStore.getReplicaSetsByOwner(deployment);
|
||||||
const metrics = deploymentStore.metrics;
|
|
||||||
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Deployment);
|
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Deployment);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="DeploymentDetails">
|
<div className="DeploymentDetails">
|
||||||
{!isMetricHidden && podsStore.isLoaded && (
|
{!isMetricHidden && podsStore.isLoaded && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => deploymentStore.loadMetrics(deployment)}
|
loader={this.loadMetrics}
|
||||||
tabs={podMetricTabs} object={deployment} params={{ metrics }}
|
tabs={podMetricTabs} object={deployment} params={{ metrics: this.metrics }}
|
||||||
>
|
>
|
||||||
<PodCharts/>
|
<PodCharts/>
|
||||||
</ResourceMetrics>
|
</ResourceMetrics>
|
||||||
@ -132,7 +142,7 @@ export class DeploymentDetails extends React.Component<Props> {
|
|||||||
</DrawerItem>
|
</DrawerItem>
|
||||||
<PodDetailsTolerations workload={deployment}/>
|
<PodDetailsTolerations workload={deployment}/>
|
||||||
<PodDetailsAffinities workload={deployment}/>
|
<PodDetailsAffinities workload={deployment}/>
|
||||||
<ResourceMetricsText metrics={metrics}/>
|
<ResourceMetricsText metrics={this.metrics}/>
|
||||||
<DeploymentReplicaSets replicaSets={replicaSets}/>
|
<DeploymentReplicaSets replicaSets={replicaSets}/>
|
||||||
<PodDetailsList pods={childPods} owner={deployment}/>
|
<PodDetailsList pods={childPods} owner={deployment}/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,17 +18,16 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
import { makeObservable } from "mobx";
|
||||||
|
|
||||||
import { observable, makeObservable } from "mobx";
|
|
||||||
import { Deployment, deploymentApi, IPodMetrics, podsApi, PodStatus } from "../../api/endpoints";
|
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
|
||||||
import { autoBind } from "../../utils";
|
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
import { Deployment, deploymentApi, PodStatus } from "../../api/endpoints";
|
||||||
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
|
import { autoBind } from "../../utils";
|
||||||
|
|
||||||
export class DeploymentStore extends KubeObjectStore<Deployment> {
|
export class DeploymentStore extends KubeObjectStore<Deployment> {
|
||||||
api = deploymentApi;
|
api = deploymentApi;
|
||||||
@observable metrics: IPodMetrics = null;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -43,12 +42,6 @@ export class DeploymentStore extends KubeObjectStore<Deployment> {
|
|||||||
], "desc");
|
], "desc");
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadMetrics(deployment: Deployment) {
|
|
||||||
const pods = this.getChildPods(deployment);
|
|
||||||
|
|
||||||
this.metrics = await podsApi.getMetrics(pods, deployment.getNs(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
getStatuses(deployments?: Deployment[]) {
|
getStatuses(deployments?: Deployment[]) {
|
||||||
const status = { failed: 0, pending: 0, running: 0 };
|
const status = { failed: 0, pending: 0, running: 0 };
|
||||||
|
|
||||||
@ -74,10 +67,6 @@ export class DeploymentStore extends KubeObjectStore<Deployment> {
|
|||||||
.getByLabel(deployment.getTemplateLabels())
|
.getByLabel(deployment.getTemplateLabels())
|
||||||
.filter(pod => pod.getNs() === deployment.getNs());
|
.filter(pod => pod.getNs() === deployment.getNs());
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.metrics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deploymentStore = new DeploymentStore();
|
export const deploymentStore = new DeploymentStore();
|
||||||
|
|||||||
@ -33,20 +33,40 @@ import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"
|
|||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { jobStore } from "./job.store";
|
import { jobStore } from "./job.store";
|
||||||
import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object";
|
import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object";
|
||||||
import type { Job } from "../../api/endpoints";
|
import { getMetricsForJobs, IPodMetrics, Job } from "../../api/endpoints";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { lookupApiLink } from "../../api/kube-api";
|
import { lookupApiLink } from "../../api/kube-api";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
|
import { makeObservable, observable } from "mobx";
|
||||||
|
import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts";
|
||||||
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
|
import { boundMethod } from "autobind-decorator";
|
||||||
|
|
||||||
interface Props extends KubeObjectDetailsProps<Job> {
|
interface Props extends KubeObjectDetailsProps<Job> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class JobDetails extends React.Component<Props> {
|
export class JobDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPodMetrics = null;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
podsStore.reloadAll();
|
podsStore.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@boundMethod
|
||||||
|
async loadMetrics() {
|
||||||
|
const { object: job } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsForJobs([job], job.getNs(), "");
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: job } = this.props;
|
const { object: job } = this.props;
|
||||||
|
|
||||||
@ -57,9 +77,18 @@ export class JobDetails extends React.Component<Props> {
|
|||||||
const childPods = jobStore.getChildPods(job);
|
const childPods = jobStore.getChildPods(job);
|
||||||
const ownerRefs = job.getOwnerRefs();
|
const ownerRefs = job.getOwnerRefs();
|
||||||
const condition = job.getCondition();
|
const condition = job.getCondition();
|
||||||
|
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Job);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="JobDetails">
|
<div className="JobDetails">
|
||||||
|
{!isMetricHidden && (
|
||||||
|
<ResourceMetrics
|
||||||
|
loader={this.loadMetrics}
|
||||||
|
tabs={podMetricTabs} object={job} params={{ metrics: this.metrics }}
|
||||||
|
>
|
||||||
|
<PodCharts />
|
||||||
|
</ResourceMetrics>
|
||||||
|
)}
|
||||||
<KubeObjectMeta object={job}/>
|
<KubeObjectMeta object={job}/>
|
||||||
<DrawerItem name="Selector" labelsOnly>
|
<DrawerItem name="Selector" labelsOnly>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -25,18 +25,17 @@ import React from "react";
|
|||||||
import kebabCase from "lodash/kebabCase";
|
import kebabCase from "lodash/kebabCase";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { autorun, observable, reaction, makeObservable } from "mobx";
|
import { observable, reaction, makeObservable } from "mobx";
|
||||||
import { IPodMetrics, nodesApi, Pod, pvcApi, configMapApi } from "../../api/endpoints";
|
import { IPodMetrics, nodesApi, Pod, pvcApi, configMapApi, getMetricsForPods } from "../../api/endpoints";
|
||||||
import { DrawerItem, DrawerTitle } from "../drawer";
|
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import { boundMethod, cssNames, interval, toJS } from "../../utils";
|
import { boundMethod, cssNames, toJS } from "../../utils";
|
||||||
import { PodDetailsContainer } from "./pod-details-container";
|
import { PodDetailsContainer } from "./pod-details-container";
|
||||||
import { PodDetailsAffinities } from "./pod-details-affinities";
|
import { PodDetailsAffinities } from "./pod-details-affinities";
|
||||||
import { PodDetailsTolerations } from "./pod-details-tolerations";
|
import { PodDetailsTolerations } from "./pod-details-tolerations";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { PodDetailsSecrets } from "./pod-details-secrets";
|
import { PodDetailsSecrets } from "./pod-details-secrets";
|
||||||
import { ResourceMetrics } from "../resource-metrics";
|
import { ResourceMetrics } from "../resource-metrics";
|
||||||
import { podsStore } from "./pods.store";
|
|
||||||
import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object";
|
import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object";
|
||||||
import { getItemMetrics } from "../../api/endpoints/metrics.api";
|
import { getItemMetrics } from "../../api/endpoints/metrics.api";
|
||||||
import { PodCharts, podMetricTabs } from "./pod-charts";
|
import { PodCharts, podMetricTabs } from "./pod-charts";
|
||||||
@ -49,10 +48,9 @@ interface Props extends KubeObjectDetailsProps<Pod> {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class PodDetails extends React.Component<Props> {
|
export class PodDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPodMetrics;
|
||||||
@observable containerMetrics: IPodMetrics;
|
@observable containerMetrics: IPodMetrics;
|
||||||
|
|
||||||
private watcher = interval(60, () => this.loadMetrics());
|
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
@ -60,26 +58,19 @@ export class PodDetails extends React.Component<Props> {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
disposeOnUnmount(this, [
|
disposeOnUnmount(this, [
|
||||||
autorun(() => {
|
|
||||||
this.containerMetrics = null;
|
|
||||||
this.loadMetrics();
|
|
||||||
}),
|
|
||||||
reaction(() => this.props.object, () => {
|
reaction(() => this.props.object, () => {
|
||||||
podsStore.reset();
|
this.metrics = null;
|
||||||
|
this.containerMetrics = null;
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
this.watcher.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
podsStore.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
async loadMetrics() {
|
async loadMetrics() {
|
||||||
const { object: pod } = this.props;
|
const { object: pod } = this.props;
|
||||||
|
|
||||||
this.containerMetrics = await podsStore.loadContainerMetrics(pod);
|
this.metrics = await getMetricsForPods([pod], pod.getNs());
|
||||||
|
this.containerMetrics = await getMetricsForPods([pod], pod.getNs(), "container, namespace");
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -92,15 +83,14 @@ export class PodDetails extends React.Component<Props> {
|
|||||||
const { nodeName } = spec;
|
const { nodeName } = spec;
|
||||||
const nodeSelector = pod.getNodeSelectors();
|
const nodeSelector = pod.getNodeSelectors();
|
||||||
const volumes = pod.getVolumes();
|
const volumes = pod.getVolumes();
|
||||||
const metrics = podsStore.metrics;
|
|
||||||
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Pod);
|
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Pod);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="PodDetails">
|
<div className="PodDetails">
|
||||||
{!isMetricHidden && (
|
{!isMetricHidden && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => podsStore.loadMetrics(pod)}
|
loader={this.loadMetrics}
|
||||||
tabs={podMetricTabs} object={pod} params={{ metrics }}
|
tabs={podMetricTabs} object={pod} params={{ metrics: this.metrics }}
|
||||||
>
|
>
|
||||||
<PodCharts/>
|
<PodCharts/>
|
||||||
</ResourceMetrics>
|
</ResourceMetrics>
|
||||||
|
|||||||
@ -20,17 +20,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import countBy from "lodash/countBy";
|
import countBy from "lodash/countBy";
|
||||||
import { action, observable, makeObservable } from "mobx";
|
import { observable, makeObservable } from "mobx";
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
import { autoBind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
|
import { autoBind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
|
||||||
import { IPodMetrics, Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints";
|
import { Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
import type { WorkloadKubeObject } from "../../api/workload-kube-object";
|
import type { WorkloadKubeObject } from "../../api/workload-kube-object";
|
||||||
|
|
||||||
export class PodsStore extends KubeObjectStore<Pod> {
|
export class PodsStore extends KubeObjectStore<Pod> {
|
||||||
api = podsApi;
|
api = podsApi;
|
||||||
|
|
||||||
@observable metrics: IPodMetrics = null;
|
|
||||||
@observable kubeMetrics = observable.array<PodMetrics>([]);
|
@observable kubeMetrics = observable.array<PodMetrics>([]);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -40,15 +39,6 @@ export class PodsStore extends KubeObjectStore<Pod> {
|
|||||||
autoBind(this);
|
autoBind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
async loadMetrics(pod: Pod) {
|
|
||||||
this.metrics = await podsApi.getMetrics([pod], pod.getNs());
|
|
||||||
}
|
|
||||||
|
|
||||||
loadContainerMetrics(pod: Pod) {
|
|
||||||
return podsApi.getMetrics([pod], pod.getNs(), "container, namespace");
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadKubeMetrics(namespace?: string) {
|
async loadKubeMetrics(namespace?: string) {
|
||||||
try {
|
try {
|
||||||
this.kubeMetrics.replace(await podMetricsApi.list({ namespace }));
|
this.kubeMetrics.replace(await podMetricsApi.list({ namespace }));
|
||||||
@ -111,10 +101,6 @@ export class PodsStore extends KubeObjectStore<Pod> {
|
|||||||
};
|
};
|
||||||
}, empty);
|
}, empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.metrics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const podsStore = new PodsStore();
|
export const podsStore = new PodsStore();
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import "./replicaset-details.scss";
|
import "./replicaset-details.scss";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { DrawerItem } from "../drawer";
|
import { DrawerItem } from "../drawer";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import { replicaSetStore } from "./replicasets.store";
|
import { replicaSetStore } from "./replicasets.store";
|
||||||
@ -31,37 +31,48 @@ import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"
|
|||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import type { KubeObjectDetailsProps } from "../kube-object";
|
import type { KubeObjectDetailsProps } from "../kube-object";
|
||||||
import type { ReplicaSet } from "../../api/endpoints";
|
import { getMetricsForReplicaSets, IPodMetrics, ReplicaSet } from "../../api/endpoints";
|
||||||
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
||||||
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
import { boundMethod } from "../../utils";
|
||||||
|
|
||||||
interface Props extends KubeObjectDetailsProps<ReplicaSet> {
|
interface Props extends KubeObjectDetailsProps<ReplicaSet> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ReplicaSetDetails extends React.Component<Props> {
|
export class ReplicaSetDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPodMetrics = null;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
clean = reaction(() => this.props.object, () => {
|
clean = reaction(() => this.props.object, () => {
|
||||||
replicaSetStore.reset();
|
this.metrics = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
podsStore.reloadAll();
|
podsStore.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
@boundMethod
|
||||||
replicaSetStore.reset();
|
async loadMetrics() {
|
||||||
|
const { object: replicaSet } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsForReplicaSets([replicaSet], replicaSet.getNs(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { object: replicaSet } = this.props;
|
const { object: replicaSet } = this.props;
|
||||||
|
|
||||||
if (!replicaSet) return null;
|
if (!replicaSet) return null;
|
||||||
const { metrics } = replicaSetStore;
|
const { metrics } = this;
|
||||||
const { status } = replicaSet;
|
const { status } = replicaSet;
|
||||||
const { availableReplicas, replicas } = status;
|
const { availableReplicas, replicas } = status;
|
||||||
const selectors = replicaSet.getSelectors();
|
const selectors = replicaSet.getSelectors();
|
||||||
@ -74,7 +85,7 @@ export class ReplicaSetDetails extends React.Component<Props> {
|
|||||||
<div className="ReplicaSetDetails">
|
<div className="ReplicaSetDetails">
|
||||||
{!isMetricHidden && podsStore.isLoaded && (
|
{!isMetricHidden && podsStore.isLoaded && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => replicaSetStore.loadMetrics(replicaSet)}
|
loader={this.loadMetrics}
|
||||||
tabs={podMetricTabs} object={replicaSet} params={{ metrics }}
|
tabs={podMetricTabs} object={replicaSet} params={{ metrics }}
|
||||||
>
|
>
|
||||||
<PodCharts/>
|
<PodCharts/>
|
||||||
|
|||||||
@ -18,18 +18,17 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
import { makeObservable } from "mobx";
|
||||||
|
|
||||||
import { observable, makeObservable } from "mobx";
|
|
||||||
import { autoBind } from "../../utils";
|
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
|
||||||
import { Deployment, IPodMetrics, podsApi, ReplicaSet, replicaSetApi } from "../../api/endpoints";
|
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
import { Deployment, ReplicaSet, replicaSetApi } from "../../api/endpoints";
|
||||||
import { PodStatus } from "../../api/endpoints/pods.api";
|
import { PodStatus } from "../../api/endpoints/pods.api";
|
||||||
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
|
import { autoBind } from "../../utils";
|
||||||
|
|
||||||
export class ReplicaSetStore extends KubeObjectStore<ReplicaSet> {
|
export class ReplicaSetStore extends KubeObjectStore<ReplicaSet> {
|
||||||
api = replicaSetApi;
|
api = replicaSetApi;
|
||||||
@observable metrics: IPodMetrics = null;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -38,12 +37,6 @@ export class ReplicaSetStore extends KubeObjectStore<ReplicaSet> {
|
|||||||
autoBind(this);
|
autoBind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadMetrics(replicaSet: ReplicaSet) {
|
|
||||||
const pods = this.getChildPods(replicaSet);
|
|
||||||
|
|
||||||
this.metrics = await podsApi.getMetrics(pods, replicaSet.getNs(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
getChildPods(replicaSet: ReplicaSet) {
|
getChildPods(replicaSet: ReplicaSet) {
|
||||||
return podsStore.getPodsByOwnerId(replicaSet.getId());
|
return podsStore.getPodsByOwnerId(replicaSet.getId());
|
||||||
}
|
}
|
||||||
@ -73,10 +66,6 @@ export class ReplicaSetStore extends KubeObjectStore<ReplicaSet> {
|
|||||||
!!replicaSet.getOwnerRefs().find(owner => owner.uid === deployment.getId())
|
!!replicaSet.getOwnerRefs().find(owner => owner.uid === deployment.getId())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.metrics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const replicaSetStore = new ReplicaSetStore();
|
export const replicaSetStore = new ReplicaSetStore();
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import "./statefulset-details.scss";
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { reaction } from "mobx";
|
import { makeObservable, observable, reaction } from "mobx";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import { DrawerItem } from "../drawer";
|
import { DrawerItem } from "../drawer";
|
||||||
import { PodDetailsStatuses } from "../+workloads-pods/pod-details-statuses";
|
import { PodDetailsStatuses } from "../+workloads-pods/pod-details-statuses";
|
||||||
@ -32,30 +32,41 @@ import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"
|
|||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { statefulSetStore } from "./statefulset.store";
|
import { statefulSetStore } from "./statefulset.store";
|
||||||
import type { KubeObjectDetailsProps } from "../kube-object";
|
import type { KubeObjectDetailsProps } from "../kube-object";
|
||||||
import type { StatefulSet } from "../../api/endpoints";
|
import { getMetricsForStatefulSets, IPodMetrics, StatefulSet } from "../../api/endpoints";
|
||||||
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics";
|
||||||
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
import { ClusterMetricsResourceType } from "../../../main/cluster";
|
||||||
|
import { boundMethod } from "../../utils";
|
||||||
|
|
||||||
interface Props extends KubeObjectDetailsProps<StatefulSet> {
|
interface Props extends KubeObjectDetailsProps<StatefulSet> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class StatefulSetDetails extends React.Component<Props> {
|
export class StatefulSetDetails extends React.Component<Props> {
|
||||||
|
@observable metrics: IPodMetrics = null;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
clean = reaction(() => this.props.object, () => {
|
clean = reaction(() => this.props.object, () => {
|
||||||
statefulSetStore.reset();
|
this.metrics = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
podsStore.reloadAll();
|
podsStore.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
@boundMethod
|
||||||
statefulSetStore.reset();
|
async loadMetrics() {
|
||||||
|
const { object: statefulSet } = this.props;
|
||||||
|
|
||||||
|
this.metrics = await getMetricsForStatefulSets([statefulSet], statefulSet.getNs(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -66,15 +77,14 @@ export class StatefulSetDetails extends React.Component<Props> {
|
|||||||
const selectors = statefulSet.getSelectors();
|
const selectors = statefulSet.getSelectors();
|
||||||
const nodeSelector = statefulSet.getNodeSelectors();
|
const nodeSelector = statefulSet.getNodeSelectors();
|
||||||
const childPods = statefulSetStore.getChildPods(statefulSet);
|
const childPods = statefulSetStore.getChildPods(statefulSet);
|
||||||
const metrics = statefulSetStore.metrics;
|
|
||||||
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.StatefulSet);
|
const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.StatefulSet);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="StatefulSetDetails">
|
<div className="StatefulSetDetails">
|
||||||
{!isMetricHidden && podsStore.isLoaded && (
|
{!isMetricHidden && podsStore.isLoaded && (
|
||||||
<ResourceMetrics
|
<ResourceMetrics
|
||||||
loader={() => statefulSetStore.loadMetrics(statefulSet)}
|
loader={() => this.loadMetrics}
|
||||||
tabs={podMetricTabs} object={statefulSet} params={{ metrics }}
|
tabs={podMetricTabs} object={statefulSet} params={{ metrics: this.metrics }}
|
||||||
>
|
>
|
||||||
<PodCharts/>
|
<PodCharts/>
|
||||||
</ResourceMetrics>
|
</ResourceMetrics>
|
||||||
@ -108,7 +118,7 @@ export class StatefulSetDetails extends React.Component<Props> {
|
|||||||
<DrawerItem name="Pod Status" className="pod-status">
|
<DrawerItem name="Pod Status" className="pod-status">
|
||||||
<PodDetailsStatuses pods={childPods}/>
|
<PodDetailsStatuses pods={childPods}/>
|
||||||
</DrawerItem>
|
</DrawerItem>
|
||||||
<ResourceMetricsText metrics={metrics}/>
|
<ResourceMetricsText metrics={this.metrics}/>
|
||||||
<PodDetailsList pods={childPods} owner={statefulSet}/>
|
<PodDetailsList pods={childPods} owner={statefulSet}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -18,17 +18,16 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
import { makeObservable } from "mobx";
|
||||||
|
|
||||||
import { observable, makeObservable } from "mobx";
|
|
||||||
import { autoBind } from "../../utils";
|
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
|
||||||
import { IPodMetrics, podsApi, PodStatus, StatefulSet, statefulSetApi } from "../../api/endpoints";
|
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
import { PodStatus, StatefulSet, statefulSetApi } from "../../api/endpoints";
|
||||||
|
import { KubeObjectStore } from "../../kube-object.store";
|
||||||
|
import { autoBind } from "../../utils";
|
||||||
|
|
||||||
export class StatefulSetStore extends KubeObjectStore<StatefulSet> {
|
export class StatefulSetStore extends KubeObjectStore<StatefulSet> {
|
||||||
api = statefulSetApi;
|
api = statefulSetApi;
|
||||||
@observable metrics: IPodMetrics = null;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -37,13 +36,6 @@ export class StatefulSetStore extends KubeObjectStore<StatefulSet> {
|
|||||||
autoBind(this);
|
autoBind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async loadMetrics(statefulSet: StatefulSet) {
|
|
||||||
const pods = this.getChildPods(statefulSet);
|
|
||||||
|
|
||||||
this.metrics = await podsApi.getMetrics(pods, statefulSet.getNs(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
getChildPods(statefulSet: StatefulSet) {
|
getChildPods(statefulSet: StatefulSet) {
|
||||||
return podsStore.getPodsByOwnerId(statefulSet.getId());
|
return podsStore.getPodsByOwnerId(statefulSet.getId());
|
||||||
}
|
}
|
||||||
@ -67,10 +59,6 @@ export class StatefulSetStore extends KubeObjectStore<StatefulSet> {
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.metrics = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const statefulSetStore = new StatefulSetStore();
|
export const statefulSetStore = new StatefulSetStore();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user