|
#!/usr/bin/env node |
|
|
|
import figlet from 'figlet'; |
|
import gradient from 'gradient-string'; |
|
import { checkbox, confirm } from '@inquirer/prompts'; |
|
import shell from 'shelljs'; |
|
import chalk from 'chalk'; |
|
import fs from 'fs'; |
|
|
|
async function main() { |
|
|
|
console.log(gradient.retro(figlet.textSync('Pod Watcher'))); |
|
|
|
console.log('Welcome to use pod watcher, you can choose which pod you want to watch peak cpu and memory usage of pods.') |
|
|
|
const selectedPods = await checkbox({ |
|
message: 'Select which kind pod you want to watch', |
|
choices: [ |
|
{ name: 'gateway', value: 'gateway' }, |
|
{ name: 'sql-engine-coordinator', value: 'sql-engine-coordinator' }, |
|
{ name: 'sql-engine-worker', value: 'sql-engine-worker' }, |
|
{ name: 'vulcan-sql', value: 'vulcan-sql' }, |
|
{ name: 'web', value: 'web' }, |
|
{ name: 'tableau-publish-worker', value: 'tableau-publish-worker' }, |
|
], |
|
}); |
|
|
|
const podNames = []; |
|
const { stdout } = shell.exec('kubectl get pods -o jsonpath={..metadata.name}', { silent: true }) |
|
for (const podName of stdout.split(' ')) { |
|
for (const pod of selectedPods) { |
|
if (podName.startsWith(pod) && !podName.startsWith('vulcan-sql-inject-pat')) { |
|
podNames.push(podName); |
|
} |
|
} |
|
} |
|
podNames.sort(); |
|
|
|
console.log(podNames); |
|
const podPeakCPU = new Map(); |
|
const podPeakMemory = new Map(); |
|
let cpuJob; |
|
let memJob; |
|
|
|
if (await confirm({ message: 'Do you want to ' + chalk.green('START') + ' to watch these memory usages of pods?', default: true })) { |
|
if (!fs.existsSync('calc_cpu.sh')) { |
|
console.log('Download cpu script...'); |
|
downloadCPUScript(); |
|
} |
|
console.log('Copy script into pods...'); |
|
cpScriptIntoPods(podNames); |
|
cpuJob = startCollectCPU(podNames, podPeakCPU); |
|
memJob = startCollectMemory(podNames, podPeakMemory); |
|
} |
|
else { |
|
return; |
|
} |
|
|
|
console.log('Now you can start your process to watch the peak cpu and memory usage of pods, If your process is done, you can stop watcher to look at the results.'); |
|
|
|
if (await confirm({ message: 'Do you want to ' + chalk.red('STOP') + ' watcher to look at the results?', default: true })) { |
|
console.log('Peak of usage of every pod'); |
|
const maxPodNameLength = findMaxPodNameLength(podNames); |
|
const blank = ' '; |
|
console.log(`${'NAME'.padEnd(maxPodNameLength)} ${blank} CPU(cores) ${blank} MEMORY(bytes)`); |
|
podNames.forEach(pod => { |
|
const cpu_usage = formatCPU(podPeakCPU.get(pod)); |
|
const memory_usage = bytesToMB(podPeakMemory.get(pod)); |
|
console.log(`${pod.padEnd(maxPodNameLength)} ${blank} ${cpu_usage.padEnd('CPU(cores)'.length)} ${blank} ${memory_usage}`); |
|
}); |
|
} |
|
|
|
clearTimeout(cpuJob); |
|
clearTimeout(memJob); |
|
} |
|
|
|
function downloadCPUScript() { |
|
shell.exec(`wget https://gist.githubusercontent.com/grieve54706/acd9c1a411adab38c4f61f2b1497769f/raw/da4ecdb005748815a6d9d17facb03b8a1b35b465/calc_cpu.sh`, { silent: true }) |
|
} |
|
|
|
function cpScriptIntoPods(podNames) { |
|
for (const podName of podNames) { |
|
shell.exec(`kubectl cp calc_cpu.sh ${podName}:/`) |
|
} |
|
} |
|
|
|
function startCollectCPU(podNames, podPeakCPU) { |
|
return setInterval(() => { |
|
Promise.all(podNames.map(podName => { |
|
return new Promise((resolve, reject) => { |
|
collectCPU(podName, podPeakCPU); |
|
resolve(); |
|
}); |
|
})); |
|
}, 1000); |
|
} |
|
|
|
function collectCPU(podName, podPeakCPU) { |
|
const { stdout } = shell.exec(`kubectl exec ${podName} -- sh /calc_cpu.sh`, { silent: true }) |
|
const cpu_usage = Number(stdout.trim()); |
|
if (cpu_usage > (podPeakCPU.get(podName) || 0)) { |
|
podPeakCPU.set(podName, cpu_usage); |
|
} |
|
} |
|
|
|
function startCollectMemory(podNames, podPeakMemory) { |
|
return setInterval(() => { |
|
Promise.all(podNames.map(podName => { |
|
return new Promise((resolve, reject) => { |
|
collectMemory(podName, podPeakMemory); |
|
resolve(); |
|
}); |
|
})); |
|
}, 1000); |
|
} |
|
|
|
function collectMemory(podName, podPeakMemory) { |
|
const { stdout } = shell.exec(`kubectl exec ${podName} -- cat /sys/fs/cgroup/memory/memory.usage_in_bytes`, { silent: true }) |
|
const memory_usage = Number(stdout.trim()); |
|
if (memory_usage > (podPeakMemory.get(podName) || 0)) { |
|
podPeakMemory.set(podName, memory_usage); |
|
} |
|
} |
|
|
|
function findMaxPodNameLength(podNames) { |
|
return podNames.reduce((a, b) => { |
|
return a.length > b.length ? a : b; |
|
}).length; |
|
} |
|
|
|
function formatCPU(cpu_usage) { |
|
return `${parseFloat(cpu_usage).toFixed(0)}m` |
|
} |
|
|
|
function bytesToMB(bytes) { |
|
return `${parseFloat(bytes / (1024 ** 2)).toFixed(0)}Mi` |
|
} |
|
|
|
await main(); |
This gist is archived. You can find the new version in this repository: https://github.com/grieve54706/pod-watcher.