1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

improve how metrics are queried & displayed

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen 2021-01-12 12:12:48 +02:00
parent 11595abc93
commit 029694a3ca
18 changed files with 173 additions and 72 deletions

View File

@ -3,6 +3,7 @@ import { 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 { IResourceMetrics, metricsApi } from "./metrics.api";
@autobind() @autobind()
export class DaemonSet extends WorkloadKubeObject { export class DaemonSet extends WorkloadKubeObject {
@ -71,6 +72,24 @@ export class DaemonSet extends WorkloadKubeObject {
} }
} }
export const daemonSetApi = new KubeApi({
export class DaemonSetApi extends KubeApi<DaemonSet> {
getMetrics(daemonsets: DaemonSet[], namespace: string, selector = ""): Promise<IResourceMetrics> {
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,
}); });

View File

@ -3,6 +3,7 @@ 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 { IResourceMetrics, metricsApi } from "./metrics.api";
export class DeploymentApi extends KubeApi<Deployment> { export class DeploymentApi extends KubeApi<Deployment> {
protected getScaleApiUrl(params: { namespace: string; name: string }) { protected getScaleApiUrl(params: { namespace: string; name: string }) {
@ -44,6 +45,21 @@ export class DeploymentApi extends KubeApi<Deployment> {
} }
}); });
} }
getMetrics(deployments: Deployment[], namespace: string, selector = ""): Promise<IResourceMetrics> {
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 {

View File

@ -4,6 +4,7 @@ import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
import { IPodContainer } from "./pods.api"; import { IPodContainer } from "./pods.api";
import { KubeApi } from "../kube-api"; import { KubeApi } from "../kube-api";
import { JsonApiParams } from "../json-api"; import { JsonApiParams } from "../json-api";
import { IResourceMetrics, metricsApi } from "./metrics.api";
@autobind() @autobind()
export class Job extends WorkloadKubeObject { export class Job extends WorkloadKubeObject {
@ -107,6 +108,24 @@ export class Job extends WorkloadKubeObject {
} }
} }
export const jobApi = new KubeApi({
export class JobApi extends KubeApi<Job> {
getMetrics(jobs: Job[], namespace: string, selector = ""): Promise<IResourceMetrics> {
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,
}); });

View File

@ -33,6 +33,15 @@ export interface IMetricsReqParams {
namespace?: string; // rbac-proxy validation param namespace?: string; // rbac-proxy validation param
} }
export interface IResourceMetrics<T = 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;

View File

@ -1,6 +1,7 @@
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 { IResourceMetrics, metricsApi } from "./metrics.api";
export enum NamespaceStatus { export enum NamespaceStatus {
ACTIVE = "Active", ACTIVE = "Active",
@ -22,6 +23,22 @@ export class Namespace extends KubeObject {
} }
} }
export const namespacesApi = new KubeApi({ export class NamespaceApi extends KubeApi<Namespace> {
getMetrics(namespace: string, selector = ""): Promise<IResourceMetrics> {
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,
}); });

View File

@ -3,6 +3,7 @@ import { autobind } from "../../utils";
import { WorkloadKubeObject } from "../workload-kube-object"; import { WorkloadKubeObject } from "../workload-kube-object";
import { IPodContainer, Pod } from "./pods.api"; import { IPodContainer, Pod } from "./pods.api";
import { KubeApi } from "../kube-api"; import { KubeApi } from "../kube-api";
import { IResourceMetrics, metricsApi } from "./metrics.api";
export class ReplicaSetApi extends KubeApi<ReplicaSet> { export class ReplicaSetApi extends KubeApi<ReplicaSet> {
protected getScaleApiUrl(params: { namespace: string; name: string }) { protected getScaleApiUrl(params: { namespace: string; name: string }) {
@ -25,6 +26,21 @@ export class ReplicaSetApi extends KubeApi<ReplicaSet> {
} }
}); });
} }
getMetrics(replicasets: ReplicaSet[], namespace: string, selector = ""): Promise<IResourceMetrics> {
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,
});
}
} }
@autobind() @autobind()

View File

@ -3,6 +3,7 @@ import { 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 { IResourceMetrics, metricsApi } from "./metrics.api";
export class StatefulSetApi extends KubeApi<StatefulSet> { export class StatefulSetApi extends KubeApi<StatefulSet> {
protected getScaleApiUrl(params: { namespace: string; name: string }) { protected getScaleApiUrl(params: { namespace: string; name: string }) {
@ -25,6 +26,21 @@ export class StatefulSetApi extends KubeApi<StatefulSet> {
} }
}); });
} }
getMetrics(statefulSets: StatefulSet[], namespace: string, selector = ""): Promise<IResourceMetrics> {
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,
});
}
} }
@autobind() @autobind()

View File

@ -12,6 +12,9 @@ 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 { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { namespaceStore } from "./namespace.store";
import { ResourceMetrics } from "../resource-metrics";
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
interface Props extends KubeObjectDetailsProps<Namespace> { interface Props extends KubeObjectDetailsProps<Namespace> {
} }
@ -33,9 +36,18 @@ export class NamespaceDetails extends React.Component<Props> {
if (!namespace) return; if (!namespace) return;
const status = namespace.getStatus(); const status = namespace.getStatus();
const metrics = namespaceStore.metrics;
return ( return (
<div className="NamespaceDetails"> <div className="NamespaceDetails">
{namespaceStore.isLoaded && (
<ResourceMetrics
loader={() => namespaceStore.loadMetrics(namespace)}
tabs={podMetricTabs} object={namespace} params={{ metrics }}
>
<PodCharts />
</ResourceMetrics>
)}
<KubeObjectMeta object={namespace}/> <KubeObjectMeta object={namespace}/>
<DrawerItem name="Status"> <DrawerItem name="Status">

View File

@ -1,7 +1,7 @@
import { action, comparer, observable, reaction } from "mobx"; import { action, comparer, observable, reaction } from "mobx";
import { autobind, createStorage } from "../../utils"; import { autobind, createStorage } from "../../utils";
import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectStore } from "../../kube-object.store";
import { Namespace, namespacesApi } from "../../api/endpoints"; import { INamespaceMetrics, Namespace, namespacesApi } from "../../api/endpoints";
import { createPageParam } from "../../navigation"; import { createPageParam } from "../../navigation";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
import { isAllowedResource } from "../../../common/rbac"; import { isAllowedResource } from "../../../common/rbac";
@ -22,12 +22,17 @@ export const namespaceUrlParam = createPageParam<string[]>({
export class NamespaceStore extends KubeObjectStore<Namespace> { export class NamespaceStore extends KubeObjectStore<Namespace> {
api = namespacesApi; api = namespacesApi;
contextNs = observable.array<string>(); contextNs = observable.array<string>();
@observable metrics: INamespaceMetrics = null;
constructor() { constructor() {
super(); super();
this.init(); this.init();
} }
async loadMetrics(namespace: Namespace) {
this.metrics = await namespacesApi.getMetrics(namespace.getName(), "");
}
private init() { private init() {
this.setContext(this.initNamespaces); this.setContext(this.initNamespaces);

View File

@ -1,7 +1,7 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectStore } from "../../kube-object.store";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { DaemonSet, daemonSetApi, IPodMetrics, Pod, podsApi, PodStatus } from "../../api/endpoints"; import { DaemonSet, daemonSetApi, IDaemonSetMetrics, Pod, 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";
@ -9,12 +9,10 @@ import { apiManager } from "../../api/api-manager";
export class DaemonSetStore extends KubeObjectStore<DaemonSet> { export class DaemonSetStore extends KubeObjectStore<DaemonSet> {
api = daemonSetApi; api = daemonSetApi;
@observable metrics: IPodMetrics = null; @observable metrics: IDaemonSetMetrics = null;
async loadMetrics(daemonSet: DaemonSet) { async loadMetrics(daemonSet: DaemonSet) {
const pods = this.getChildPods(daemonSet); this.metrics = await daemonSetApi.getMetrics([daemonSet], daemonSet.getNs(), "");
this.metrics = await podsApi.getMetrics(pods, daemonSet.getNs(), "");
} }
getChildPods(daemonSet: DaemonSet): Pod[] { getChildPods(daemonSet: DaemonSet): Pod[] {

View File

@ -1,5 +1,5 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { Deployment, deploymentApi, IPodMetrics, podsApi, PodStatus } from "../../api/endpoints"; import { Deployment, deploymentApi, IDeploymentMetrics, PodStatus } from "../../api/endpoints";
import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectStore } from "../../kube-object.store";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { podsStore } from "../+workloads-pods/pods.store"; import { podsStore } from "../+workloads-pods/pods.store";
@ -8,7 +8,7 @@ import { apiManager } from "../../api/api-manager";
@autobind() @autobind()
export class DeploymentStore extends KubeObjectStore<Deployment> { export class DeploymentStore extends KubeObjectStore<Deployment> {
api = deploymentApi; api = deploymentApi;
@observable metrics: IPodMetrics = null; @observable metrics: IDeploymentMetrics = null;
protected sortItems(items: Deployment[]) { protected sortItems(items: Deployment[]) {
return super.sortItems(items, [ return super.sortItems(items, [
@ -17,9 +17,7 @@ export class DeploymentStore extends KubeObjectStore<Deployment> {
} }
async loadMetrics(deployment: Deployment) { async loadMetrics(deployment: Deployment) {
const pods = this.getChildPods(deployment); this.metrics = await deploymentApi.getMetrics([deployment], deployment.getNs(), "");
this.metrics = await podsApi.getMetrics(pods, deployment.getNs(), "");
} }
getStatuses(deployments?: Deployment[]) { getStatuses(deployments?: Deployment[]) {

View File

@ -18,6 +18,8 @@ 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 { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceMetrics } from "../resource-metrics";
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
interface Props extends KubeObjectDetailsProps<Job> { interface Props extends KubeObjectDetailsProps<Job> {
} }
@ -40,9 +42,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 metrics = jobStore.metrics;
return ( return (
<div className="JobDetails"> <div className="JobDetails">
{jobStore.isLoaded && (
<ResourceMetrics
loader={() => jobStore.loadMetrics(job)}
tabs={podMetricTabs} object={job} params={{ metrics }}
>
<PodCharts />
</ResourceMetrics>
)}
<KubeObjectMeta object={job}/> <KubeObjectMeta object={job}/>
<DrawerItem name="Selector" labelsOnly> <DrawerItem name="Selector" labelsOnly>
{ {

View File

@ -1,14 +1,21 @@
import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectStore } from "../../kube-object.store";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { Job, jobApi } from "../../api/endpoints/job.api"; import { IJobMetrics, Job, jobApi } from "../../api/endpoints/job.api";
import { CronJob, Pod, PodStatus } from "../../api/endpoints"; import { CronJob, Pod, 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 { observable } from "mobx";
@autobind() @autobind()
export class JobStore extends KubeObjectStore<Job> { export class JobStore extends KubeObjectStore<Job> {
api = jobApi; api = jobApi;
@observable metrics: IJobMetrics = null;
async loadMetrics(job: Job) {
this.metrics = await jobApi.getMetrics([job], job.getNs(), "");
}
getChildPods(job: Job): Pod[] { getChildPods(job: Job): Pod[] {
return podsStore.getPodsByOwner(job); return podsStore.getPodsByOwner(job);
} }

View File

@ -6,6 +6,7 @@ import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.ap
import { NoMetrics } from "../resource-metrics/no-metrics"; import { NoMetrics } from "../resource-metrics/no-metrics";
import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics";
import { themeStore } from "../../theme.store"; import { themeStore } from "../../theme.store";
import { mapValues } from "lodash";
type IContext = IResourceMetricsValue<any, { metrics: IPodMetrics }>; type IContext = IResourceMetricsValue<any, { metrics: IPodMetrics }>;
@ -16,10 +17,7 @@ export const ContainerCharts = observer(() => {
if (!metrics) return null; if (!metrics) return null;
if (isMetricsEmpty(metrics)) return <NoMetrics/>; if (isMetricsEmpty(metrics)) return <NoMetrics/>;
const values = Object.values(metrics) const {
.map(normalizeMetrics)
.map(({ data }) => data.result[0].values);
const [
cpuUsage, cpuUsage,
cpuRequests, cpuRequests,
cpuLimits, cpuLimits,
@ -27,7 +25,7 @@ export const ContainerCharts = observer(() => {
memoryRequests, memoryRequests,
memoryLimits, memoryLimits,
fsUsage fsUsage
] = values; } = mapValues(metrics, metric => normalizeMetrics(metric).data.result[0].values);
const datasets = [ const datasets = [
// CPU // CPU

View File

@ -6,7 +6,7 @@ import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.ap
import { NoMetrics } from "../resource-metrics/no-metrics"; import { NoMetrics } from "../resource-metrics/no-metrics";
import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics";
import { WorkloadKubeObject } from "../../api/workload-kube-object"; import { WorkloadKubeObject } from "../../api/workload-kube-object";
import { themeStore } from "../../theme.store"; import { mapValues } from "lodash";
export const podMetricTabs = [ export const podMetricTabs = [
"CPU", "CPU",
@ -19,27 +19,20 @@ type IContext = IResourceMetricsValue<WorkloadKubeObject, { metrics: IPodMetrics
export const PodCharts = observer(() => { export const PodCharts = observer(() => {
const { params: { metrics }, tabId, object } = useContext<IContext>(ResourceMetricsContext); const { params: { metrics }, tabId, object } = useContext<IContext>(ResourceMetricsContext);
const { chartCapacityColor } = themeStore.activeTheme.colors;
const id = object.getId(); const id = object.getId();
if (!metrics) return null; if (!metrics) return null;
if (isMetricsEmpty(metrics)) return <NoMetrics/>; if (isMetricsEmpty(metrics)) return <NoMetrics/>;
const options = tabId == 0 ? cpuOptions : memoryOptions; const options = tabId == 0 ? cpuOptions : memoryOptions;
const values = Object.values(metrics)
.map(normalizeMetrics) const {
.map(({ data }) => data.result[0].values);
const [
cpuUsage, cpuUsage,
cpuRequests,
cpuLimits,
memoryUsage, memoryUsage,
memoryRequests,
memoryLimits,
fsUsage, fsUsage,
networkReceive, networkReceive,
networkTransmit networkTransmit
] = values; } = mapValues(metrics, metric => normalizeMetrics(metric).data.result[0].values);
const datasets = [ const datasets = [
// CPU // CPU
@ -50,20 +43,6 @@ export const PodCharts = observer(() => {
tooltip: `Container CPU cores usage`, tooltip: `Container CPU cores usage`,
borderColor: "#3D90CE", borderColor: "#3D90CE",
data: cpuUsage.map(([x, y]) => ({ x, y })) data: cpuUsage.map(([x, y]) => ({ x, y }))
},
{
id: `${id}-cpuRequests`,
label: `Requests`,
tooltip: `Container CPU requests`,
borderColor: "#30b24d",
data: cpuRequests.map(([x, y]) => ({ x, y }))
},
{
id: `${id}-cpuLimits`,
label: `Limits`,
tooltip: `CPU limits`,
borderColor: chartCapacityColor,
data: cpuLimits.map(([x, y]) => ({ x, y }))
} }
], ],
// Memory // Memory
@ -74,20 +53,6 @@ export const PodCharts = observer(() => {
tooltip: `Container memory usage`, tooltip: `Container memory usage`,
borderColor: "#c93dce", borderColor: "#c93dce",
data: memoryUsage.map(([x, y]) => ({ x, y })) data: memoryUsage.map(([x, y]) => ({ x, y }))
},
{
id: `${id}-memoryRequests`,
label: `Requests`,
tooltip: `Container memory requests`,
borderColor: "#30b24d",
data: memoryRequests.map(([x, y]) => ({ x, y }))
},
{
id: `${id}-memoryLimits`,
label: `Limits`,
tooltip: `Container memory limits`,
borderColor: chartCapacityColor,
data: memoryLimits.map(([x, y]) => ({ x, y }))
} }
], ],
// Network // Network

View File

@ -1,7 +1,7 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectStore } from "../../kube-object.store";
import { Deployment, IPodMetrics, podsApi, ReplicaSet, replicaSetApi } from "../../api/endpoints"; import { Deployment, IReplicaSetMetrics, 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 { PodStatus } from "../../api/endpoints/pods.api"; import { PodStatus } from "../../api/endpoints/pods.api";
@ -9,12 +9,10 @@ import { PodStatus } from "../../api/endpoints/pods.api";
@autobind() @autobind()
export class ReplicaSetStore extends KubeObjectStore<ReplicaSet> { export class ReplicaSetStore extends KubeObjectStore<ReplicaSet> {
api = replicaSetApi; api = replicaSetApi;
@observable metrics: IPodMetrics = null; @observable metrics: IReplicaSetMetrics = null;
async loadMetrics(replicaSet: ReplicaSet) { async loadMetrics(replicaSet: ReplicaSet) {
const pods = this.getChildPods(replicaSet); this.metrics = await replicaSetApi.getMetrics([replicaSet], replicaSet.getNs(), "");
this.metrics = await podsApi.getMetrics(pods, replicaSet.getNs(), "");
} }
getChildPods(replicaSet: ReplicaSet) { getChildPods(replicaSet: ReplicaSet) {

View File

@ -1,19 +1,17 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectStore } from "../../kube-object.store";
import { IPodMetrics, podsApi, PodStatus, StatefulSet, statefulSetApi } from "../../api/endpoints"; import { IStatefulSetMetrics, 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";
@autobind() @autobind()
export class StatefulSetStore extends KubeObjectStore<StatefulSet> { export class StatefulSetStore extends KubeObjectStore<StatefulSet> {
api = statefulSetApi; api = statefulSetApi;
@observable metrics: IPodMetrics = null; @observable metrics: IStatefulSetMetrics = null;
async loadMetrics(statefulSet: StatefulSet) { async loadMetrics(statefulSet: StatefulSet) {
const pods = this.getChildPods(statefulSet); this.metrics = await statefulSetApi.getMetrics([statefulSet], statefulSet.getNs(), "");
this.metrics = await podsApi.getMetrics(pods, statefulSet.getNs(), "");
} }
getChildPods(statefulSet: StatefulSet) { getChildPods(statefulSet: StatefulSet) {

View File

@ -1,12 +1,11 @@
import React from "react"; import React from "react";
import { IPodMetrics } from "../../api/endpoints"; import { getMetricLastPoints, IResourceMetrics, IMetrics } from "../../api/endpoints/metrics.api";
import { getMetricLastPoints, IMetrics } from "../../api/endpoints/metrics.api";
import { bytesToUnits } from "../../utils"; import { bytesToUnits } from "../../utils";
import { Badge } from "../badge"; import { Badge } from "../badge";
import { DrawerItem } from "../drawer"; import { DrawerItem } from "../drawer";
interface Props { interface Props {
metrics: IPodMetrics<IMetrics>; metrics: IResourceMetrics<IMetrics>;
} }
export function ResourceMetricsText(props: Props) { export function ResourceMetricsText(props: Props) {