import { isNumber } from 'underscore' ; import { CoreV1Api , V1Container , V1Pod } from './gen/api' ; export async function podsForNode ( api , nodeName ) { const allPods = await api . listPodForAllNamespaces ( ) ; return allPods . body . items . filter ( ( pod ) => pod . spec ! . nodeName === nodeName ) ; } export function findSuffix ( quantity ) { let ix = quantity . length - 1 ; while ( ix >= 0 && ! /[\.0-9]/ . test ( quantity . charAt ( ix ) ) ) { ix -- ; } return ix === - 1 ? '' : quantity . substring ( ix + 1 ) ; } export function quantityToScalar ( quantity ) { if ( ! quantity ) { return 0 ; } const suffix = findSuffix ( quantity ) ; if ( suffix === '' ) { const num = Number ( quantity ) . valueOf ( ) ; if ( isNaN ( num ) ) { throw new Error ( 'Unknown quantity ' + quantity ) ; } return num ; } switch ( suffix ) { case 'n' : return Number ( quantity . substr ( 0 , quantity . length - 1 ) ) . valueOf ( ) / 1000000000 ; case 'u' : return Number ( quantity . substr ( 0 , quantity . length - 1 ) ) . valueOf ( ) / 1000000 ; case 'm' : return Number ( quantity . substr ( 0 , quantity . length - 1 ) ) . valueOf ( ) / 1000.0 ; case 'k' : return BigInt ( quantity . substr ( 0 , quantity . length - 1 ) ) * BigInt ( 1000 ) ; case 'M' : return BigInt ( quantity . substr ( 0 , quantity . length - 1 ) ) * BigInt ( 1000 * 1000 ) ; case 'G' : return BigInt ( quantity . substr ( 0 , quantity . length - 1 ) ) * BigInt ( 1000 * 1000 * 1000 ) ; case 'T' : return ( BigInt ( quantity . substr ( 0 , quantity . length - 1 ) ) * BigInt ( 1000 * 1000 * 1000 ) * BigInt ( 1000 ) ) ; case 'P' : return ( BigInt ( quantity . substr ( 0 , quantity . length - 1 ) ) * BigInt ( 1000 * 1000 * 1000 ) * BigInt ( 1000 * 1000 ) ) ; case 'E' : return ( BigInt ( quantity . substr ( 0 , quantity . length - 1 ) ) * BigInt ( 1000 * 1000 * 1000 ) * BigInt ( 1000 * 1000 * 1000 ) ) ; case 'Ki' : return BigInt ( quantity . substr ( 0 , quantity . length - 2 ) ) * BigInt ( 1024 ) ; case 'Mi' : return BigInt ( quantity . substr ( 0 , quantity . length - 2 ) ) * BigInt ( 1024 * 1024 ) ; case 'Gi' : return BigInt ( quantity . substr ( 0 , quantity . length - 2 ) ) * BigInt ( 1024 * 1024 * 1024 ) ; case 'Ti' : return ( BigInt ( quantity . substr ( 0 , quantity . length - 2 ) ) * BigInt ( 1024 * 1024 * 1024 ) * BigInt ( 1024 ) ) ; case 'Pi' : return ( BigInt ( quantity . substr ( 0 , quantity . length - 2 ) ) * BigInt ( 1024 * 1024 * 1024 ) * BigInt ( 1024 * 1024 ) ) ; case 'Ei' : return ( BigInt ( quantity . substr ( 0 , quantity . length - 2 ) ) * BigInt ( 1024 * 1024 * 1024 ) * BigInt ( 1024 * 1024 * 1024 ) ) ; default : throw new Error ( `Unknown suffix: ${ suffix }` ) ; } } export class ResourceStatus { constructor ( public readonly request , public readonly limit , public readonly resourceType ) { } } export function totalCPUForContainer ( container ) { return containerTotalForResource ( container , 'cpu' ) ; } export function totalMemoryForContainer ( container ) { return containerTotalForResource ( container , 'memory' ) ; } export function totalCPU ( pod ) { return totalForResource ( pod , 'cpu' ) ; } export function totalMemory ( pod ) { return totalForResource ( pod , 'memory' ) ; } export function add ( n1 , n2 ) { if ( isNumber ( n1 ) && isNumber ( n2 ) ) { return n1 + n2 ; } if ( isNumber ( n1 ) ) { return BigInt ( Math . round ( n1 ) ) + ( n2 as bigint ) ; } else if ( isNumber ( n2 ) ) { return ( n1 as bigint ) + BigInt ( Math . round ( n2 ) ) ; } return ( ( n1 as bigint ) + n2 ) as bigint ; } export function containerTotalForResource ( container , resource ) { let reqTotal = 0 ; let limitTotal = 0 ; if ( container . resources ) { if ( container . resources . requests ) { reqTotal = add ( reqTotal , quantityToScalar ( container . resources . requests [ resource ] ) ) ; } if ( container . resources . limits ) { limitTotal = add ( limitTotal , quantityToScalar ( container . resources . limits [ resource ] ) ) ; } } return new ResourceStatus ( reqTotal , limitTotal , resource ) ; } export function totalForResource ( pod , resource ) { let reqTotal = 0 ; let limitTotal = 0 ; pod . spec ! . containers . forEach ( ( container ) => { const containerTotal = containerTotalForResource ( container , resource ) ; reqTotal = add ( reqTotal , containerTotal . request ) ; limitTotal = add ( limitTotal , containerTotal . limit ) ; } ) ; return new ResourceStatus ( reqTotal , limitTotal , resource ) ; }