import { CoreV1Api , V1Node , V1Pod , V1PodList } from './gen/api' ; import { ContainerMetric , Metrics , PodMetric } from './metrics' ; import { add , podsForNode , quantityToScalar , ResourceStatus , totalCPU , totalCPUForContainer , totalMemory , totalMemoryForContainer , } from './util' ; export class ResourceUsage { constructor ( public readonly Capacity , public readonly RequestTotal , public readonly LimitTotal ) { } } export class CurrentResourceUsage { constructor ( public readonly CurrentUsage , public readonly RequestTotal , public readonly LimitTotal ) { } } export class NodeStatus { constructor ( public readonly Node , public readonly CPU , public readonly Memory ) { } } export class ContainerStatus { constructor ( public readonly Container , public readonly CPUUsage , public readonly MemoryUsage ) { } } export class PodStatus { constructor ( public readonly Pod , public readonly CPU , public readonly Memory , public readonly Containers ) { } } export async function topNodes ( api ) { const nodes = await api . listNode ( ) ; const result = [ ] ; for ( const node of nodes . body ! . items ) { const availableCPU = quantityToScalar ( node . status ! . allocatable ! . cpu ) ; const availableMem = quantityToScalar ( node . status ! . allocatable ! . memory ) ; let totalPodCPU = 0 ; let totalPodCPULimit = 0 ; let totalPodMem = 0 ; let totalPodMemLimit = 0 ; let pods = await podsForNode ( api , node . metadata ! . name ! ) ; pods = pods . filter ( ( pod ) => pod . status ! . phase === 'Running' ) ; pods . forEach ( ( pod ) => { const cpuTotal = totalCPU ( pod ) ; totalPodCPU = add ( totalPodCPU , cpuTotal . request ) ; totalPodCPULimit = add ( totalPodCPULimit , cpuTotal . limit ) ; const memTotal = totalMemory ( pod ) ; totalPodMem = add ( totalPodMem , memTotal . request ) ; totalPodMemLimit = add ( totalPodMemLimit , memTotal . limit ) ; } ) ; const cpuUsage = new ResourceUsage ( availableCPU , totalPodCPU , totalPodCPULimit ) ; const memUsage = new ResourceUsage ( availableMem , totalPodMem , totalPodMemLimit ) ; result . push ( new NodeStatus ( node , cpuUsage , memUsage ) ) ; } return result ; } export async function topPods ( api , metrics , namespace ? ) { const getPodList = async ( ) : Promise < V1PodList > => { if ( namespace ) { return ( await api . listNamespacedPod ( namespace ) ) . body ; } return ( await api . listPodForAllNamespaces ( ) ) . body ; } ; const [ podMetrics , podList ] = await Promise . all ( [ metrics . getPodMetrics ( namespace ) , getPodList ( ) ] ) ; const podMetricsMap = podMetrics . items . reduce ( ( accum , next ) => { accum . set ( next . metadata . name , next ) ; return accum ; } , new Map < string , PodMetric > ( ) ) ; const result = [ ] ; for ( const pod of podList . items ) { const podMetric = podMetricsMap . get ( pod . metadata ! . name ! ) ; const containerStatuses = [ ] ; let currentPodCPU = 0 ; let currentPodMem = 0 ; let podRequestsCPU = 0 ; let podLimitsCPU = 0 ; let podRequestsMem = 0 ; let podLimitsMem = 0 ; pod . spec ! . containers . forEach ( ( container ) => { const containerCpuTotal = totalCPUForContainer ( container ) ; const containerMemTotal = totalMemoryForContainer ( container ) ; podRequestsCPU = add ( podRequestsCPU , containerCpuTotal . request ) ; podLimitsCPU = add ( podLimitsCPU , containerCpuTotal . limit ) ; podRequestsMem = add ( podLimitsMem , containerMemTotal . request ) ; podLimitsMem = add ( podLimitsMem , containerMemTotal . limit ) ; const containerMetrics = podMetric !== undefined ? podMetric . containers . find ( ( c ) => c . name === container . name ) : undefined ; if ( containerMetrics !== undefined ) { const currentContainerCPUUsage = quantityToScalar ( containerMetrics . usage . cpu ) ; const currentContainerMemUsage = quantityToScalar ( containerMetrics . usage . memory ) ; currentPodCPU = add ( currentPodCPU , currentContainerCPUUsage ) ; currentPodMem = add ( currentPodMem , currentContainerMemUsage ) ; const containerCpuUsage = new CurrentResourceUsage ( currentContainerCPUUsage , containerCpuTotal . request , containerCpuTotal . limit ) ; const containerMemUsage = new CurrentResourceUsage ( currentContainerMemUsage , containerMemTotal . request , containerMemTotal . limit ) ; containerStatuses . push ( new ContainerStatus ( containerMetrics . name , containerCpuUsage , containerMemUsage ) ) ; } } ) ; const podCpuUsage = new CurrentResourceUsage ( currentPodCPU , podRequestsCPU , podLimitsCPU ) ; const podMemUsage = new CurrentResourceUsage ( currentPodMem , podRequestsMem , podLimitsMem ) ; result . push ( new PodStatus ( pod , podCpuUsage , podMemUsage , containerStatuses ) ) ; } return result ; }