1
- import { CoreV1Api , V1Node , V1Pod } from './gen/api' ;
2
- import { add , podsForNode , quantityToScalar , totalCPU , totalMemory } from './util' ;
1
+ import { CoreV1Api , V1Node , V1Pod , V1PodList } from './gen/api' ;
2
+ import { ContainerMetric , Metrics , PodMetric } from './metrics' ;
3
+ import {
4
+ add ,
5
+ podsForNode ,
6
+ quantityToScalar ,
7
+ ResourceStatus ,
8
+ totalCPU ,
9
+ totalCPUForContainer ,
10
+ totalMemory ,
11
+ totalMemoryForContainer ,
12
+ } from './util' ;
3
13
4
14
export class ResourceUsage {
5
15
constructor (
@@ -9,6 +19,14 @@ export class ResourceUsage {
9
19
) { }
10
20
}
11
21
22
+ export class CurrentResourceUsage {
23
+ constructor (
24
+ public readonly CurrentUsage : number | BigInt ,
25
+ public readonly RequestTotal : number | BigInt ,
26
+ public readonly LimitTotal : number | BigInt ,
27
+ ) { }
28
+ }
29
+
12
30
export class NodeStatus {
13
31
constructor (
14
32
public readonly Node : V1Node ,
@@ -17,6 +35,23 @@ export class NodeStatus {
17
35
) { }
18
36
}
19
37
38
+ export class ContainerStatus {
39
+ constructor (
40
+ public readonly Container : string ,
41
+ public readonly CPUUsage : CurrentResourceUsage ,
42
+ public readonly MemoryUsage : CurrentResourceUsage ,
43
+ ) { }
44
+ }
45
+
46
+ export class PodStatus {
47
+ constructor (
48
+ public readonly Pod : V1Pod ,
49
+ public readonly CPU : CurrentResourceUsage ,
50
+ public readonly Memory : CurrentResourceUsage ,
51
+ public readonly Containers : ContainerStatus [ ] ,
52
+ ) { }
53
+ }
54
+
20
55
export async function topNodes ( api : CoreV1Api ) : Promise < NodeStatus [ ] > {
21
56
// TODO: Support metrics APIs in the client and this library
22
57
const nodes = await api . listNode ( ) ;
@@ -46,3 +81,87 @@ export async function topNodes(api: CoreV1Api): Promise<NodeStatus[]> {
46
81
}
47
82
return result ;
48
83
}
84
+
85
+ // Returns the current pod CPU/Memory usage including the CPU/Memory usage of each container
86
+ export async function topPods ( api : CoreV1Api , metrics : Metrics , namespace ?: string ) : Promise < PodStatus [ ] > {
87
+ // Figure out which pod list endpoint to call
88
+ const getPodList = async ( ) : Promise < V1PodList > => {
89
+ if ( namespace ) {
90
+ return ( await api . listNamespacedPod ( namespace ) ) . body ;
91
+ }
92
+ return ( await api . listPodForAllNamespaces ( ) ) . body ;
93
+ } ;
94
+
95
+ const [ podMetrics , podList ] = await Promise . all ( [ metrics . getPodMetrics ( namespace ) , getPodList ( ) ] ) ;
96
+
97
+ // Create a map of pod names to their metric usage
98
+ // to make it easier to look up when we need it later
99
+ const podMetricsMap = podMetrics . items . reduce ( ( accum , next ) => {
100
+ accum . set ( next . metadata . name , next ) ;
101
+ return accum ;
102
+ } , new Map < string , PodMetric > ( ) ) ;
103
+
104
+ const result : PodStatus [ ] = [ ] ;
105
+ for ( const pod of podList . items ) {
106
+ const podMetric = podMetricsMap . get ( pod . metadata ! . name ! ) ;
107
+
108
+ const containerStatuses : ContainerStatus [ ] = [ ] ;
109
+ let currentPodCPU : number | bigint = 0 ;
110
+ let currentPodMem : number | bigint = 0 ;
111
+ let podRequestsCPU : number | bigint = 0 ;
112
+ let podLimitsCPU : number | bigint = 0 ;
113
+ let podRequestsMem : number | bigint = 0 ;
114
+ let podLimitsMem : number | bigint = 0 ;
115
+
116
+ pod . spec ! . containers . forEach ( ( container ) => {
117
+ // get the the container CPU/Memory container.resources.requests/limits
118
+ const containerCpuTotal = totalCPUForContainer ( container ) ;
119
+ const containerMemTotal = totalMemoryForContainer ( container ) ;
120
+
121
+ // sum each container's CPU/Memory container.resources.requests/limits
122
+ // to get the pod's overall requests/limits
123
+ podRequestsCPU = add ( podRequestsCPU , containerCpuTotal . request ) ;
124
+ podLimitsCPU = add ( podLimitsCPU , containerCpuTotal . limit ) ;
125
+
126
+ podRequestsMem = add ( podLimitsMem , containerMemTotal . request ) ;
127
+ podLimitsMem = add ( podLimitsMem , containerMemTotal . limit ) ;
128
+
129
+ // Find the container metrics by container.name
130
+ // if both the pod and container metrics exist
131
+ const containerMetrics =
132
+ podMetric !== undefined
133
+ ? podMetric . containers . find ( ( c ) => c . name === container . name )
134
+ : undefined ;
135
+
136
+ // Store the current usage of each container
137
+ // Sum each container to get the overall pod usage
138
+ if ( containerMetrics !== undefined ) {
139
+ const currentContainerCPUUsage = quantityToScalar ( containerMetrics . usage . cpu ) ;
140
+ const currentContainerMemUsage = quantityToScalar ( containerMetrics . usage . memory ) ;
141
+
142
+ currentPodCPU = add ( currentPodCPU , currentContainerCPUUsage ) ;
143
+ currentPodMem = add ( currentPodMem , currentContainerMemUsage ) ;
144
+
145
+ const containerCpuUsage = new CurrentResourceUsage (
146
+ currentContainerCPUUsage ,
147
+ containerCpuTotal . request ,
148
+ containerCpuTotal . limit ,
149
+ ) ;
150
+ const containerMemUsage = new CurrentResourceUsage (
151
+ currentContainerMemUsage ,
152
+ containerMemTotal . request ,
153
+ containerMemTotal . limit ,
154
+ ) ;
155
+
156
+ containerStatuses . push (
157
+ new ContainerStatus ( containerMetrics . name , containerCpuUsage , containerMemUsage ) ,
158
+ ) ;
159
+ }
160
+ } ) ;
161
+
162
+ const podCpuUsage = new CurrentResourceUsage ( currentPodCPU , podRequestsCPU , podLimitsCPU ) ;
163
+ const podMemUsage = new CurrentResourceUsage ( currentPodMem , podRequestsMem , podLimitsMem ) ;
164
+ result . push ( new PodStatus ( pod , podCpuUsage , podMemUsage , containerStatuses ) ) ;
165
+ }
166
+ return result ;
167
+ }
0 commit comments