check-kubernetes-cluster-fixed
Version:
MCP server to check Kubernetes cluster health and status
167 lines • 8.34 kB
JavaScript
import chaiExec from '@jsdevtools/chai-exec';
import * as chai from 'chai';
import { detailedDiff } from 'deep-object-diff';
import * as jsYaml from 'js-yaml';
import { debugLog } from './logging.js';
import { sleep } from './utils.js';
const expect = chai.expect;
chai.use(chaiExec);
chai.config.truncateThreshold = 4000; // length threshold for actual and expected values in assertion errors
export async function checkKubernetesObject({ context, namespace, kind, k8sObj, yaml }) {
let command = `kubectl --context ${context} -n ${namespace} get ${kind} ${k8sObj} -o json`;
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
let json = jsYaml.load(yaml);
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).to.exit.with.code(0);
expect(cli).stderr.to.be.empty;
let data = JSON.parse(cli.stdout);
debugLog(`Parsed data from CLI: ${JSON.stringify(data)}`);
let diff = detailedDiff(json, data);
debugLog(`Diff between expected and actual object: ${JSON.stringify(diff)}`);
let expectedObject = false;
if (Object.keys(diff.updated).length === 0 && Object.keys(diff.deleted).length === 0) {
expectedObject = true;
}
debugLog(`Expected object found: ${expectedObject}`);
expect(expectedObject, `The following object can't be found or is not as expected:\n${yaml}`).to.be.true;
}
export async function checkDeployment({ context, namespace, k8sObj }) {
let command = `kubectl --context ${context} -n ${namespace} get deploy ${k8sObj} -o jsonpath='{.status}'`;
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).stderr.to.be.empty;
let parsedStatus = JSON.parse(cli.stdout.slice(1, -1));
let readyReplicas = parsedStatus.readyReplicas || 0;
let replicas = parsedStatus.replicas;
debugLog(`Ready replicas: ${readyReplicas}, Total replicas: ${replicas}`);
if (readyReplicas != replicas) {
debugLog(`Deployment ${k8sObj} in ${context} not ready, retrying...`);
await sleep(1000);
}
expect(cli).to.exit.with.code(0);
expect(readyReplicas).to.equal(replicas);
}
export async function checkDeploymentHasPod({ context, namespace, deployment }) {
let command = `kubectl --context ${context} -n ${namespace} get deploy ${deployment} -o name'`;
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).stderr.to.be.empty;
expect(cli).stdout.to.not.be.empty;
expect(cli).stdout.to.contain(deployment);
}
export async function checkDeploymentsWithLabels({ context, namespace, labels, instances }) {
let command = `kubectl --context ${context} -n ${namespace} get deploy -l ${labels} -o jsonpath='{.items}'`;
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).stderr.to.be.empty;
let deployments = JSON.parse(cli.stdout.slice(1, -1));
debugLog(`Found deployments: ${JSON.stringify(deployments)}`);
expect(deployments).to.have.lengthOf(instances);
deployments.forEach((deployment) => {
let readyReplicas = deployment.status.readyReplicas || 0;
let replicas = deployment.status.replicas;
debugLog(`Deployment ${deployment.metadata.name} - Ready replicas: ${readyReplicas}, Total replicas: ${replicas}`);
if (readyReplicas != replicas) {
debugLog(`Deployment ${deployment.metadata.name} in ${context} not ready, retrying...`);
sleep(1000);
}
expect(cli).to.exit.with.code(0);
readyReplicas.should.equal(replicas);
});
}
export async function checkStatefulSet({ context, namespace, k8sObj }) {
let command = `kubectl --context ${context} -n ${namespace} get sts ${k8sObj} -o jsonpath='{.status}'`;
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).stderr.to.be.empty;
let parsedStatus = JSON.parse(cli.stdout.slice(1, -1));
let readyReplicas = parsedStatus.readyReplicas || 0;
let replicas = parsedStatus.replicas;
debugLog(`StatefulSet ${k8sObj} - Ready replicas: ${readyReplicas}, Total replicas: ${replicas}`);
if (readyReplicas != replicas) {
debugLog(`StatefulSet ${k8sObj} in ${context} not ready, retrying...`);
await sleep(1000);
}
expect(cli).to.exit.with.code(0);
readyReplicas.should.equal(replicas);
}
export async function checkDaemonSet({ context, namespace, k8sObj }) {
let command = `kubectl --context ${context} -n ${namespace} get ds ${k8sObj} -o jsonpath='{.status}'`;
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).stderr.to.be.empty;
let parsedStatus = JSON.parse(cli.stdout.slice(1, -1));
let readyReplicas = parsedStatus.numberReady || 0;
let replicas = parsedStatus.desiredNumberScheduled;
debugLog(`DaemonSet ${k8sObj} - Ready replicas: ${readyReplicas}, Total replicas: ${replicas}`);
if (readyReplicas != replicas) {
debugLog(`DaemonSet ${k8sObj} in ${context} not ready, retrying...`);
await sleep(1000);
}
expect(cli).to.exit.with.code(0);
readyReplicas.should.equal(replicas);
}
export function k8sObjectIsPresent({ context, namespace, k8sType, k8sObj }) {
// covers both namespace scoped and cluster scoped objects
let command = `kubectl --context ${context} get ${k8sType} ${k8sObj} -o name`;
if (namespace) {
command = `kubectl --context ${context} -n ${namespace} get ${k8sType} ${k8sObj} -o name`;
}
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).stderr.to.be.empty;
expect(cli).to.exit.with.code(0);
}
export async function genericCommand({ command, responseContains = "" }) {
debugLog(`Executing generic command: ${command}`);
let cli = chaiExec(command);
if (cli.stderr && cli.stderr != "") {
debugLog(`Command ${command} not successful: ${cli.stderr}`);
await sleep(1000);
}
debugLog(`Command output (stdout): ${cli.stdout}`);
debugLog(`Command error (stderr): ${cli.stderr}`);
expect(cli).stderr.to.be.empty;
expect(cli).to.exit.with.code(0);
if (responseContains != "") {
debugLog(`Checking if stdout contains: ${responseContains}`);
expect(cli).stdout.to.contain(responseContains);
}
}
export function getOutputForCommand({ command }) {
debugLog(`Executing command: ${command}`);
let cli = chaiExec(command);
debugLog(`Command output (stdout): ${cli.stdout}`);
return cli.stdout;
}
export function curlInPod({ curlCommand, podName, namespace }) {
debugLog(`Executing curl command: ${curlCommand} on pod: ${podName} in namespace: ${namespace}`);
const cli = chaiExec(curlCommand);
debugLog(`Curl command output (stdout): ${cli.stdout}`);
return cli.stdout;
}
export async function curlInDeployment({ curlCommand, deploymentName, namespace, context }) {
debugLog(`Executing curl command: ${curlCommand} on deployment: ${deploymentName} in namespace: ${namespace} and context: ${context}`);
let getPodCommand = `kubectl --context ${context} -n ${namespace} get pods -l app=${deploymentName} -o jsonpath='{.items[0].metadata.name}'`;
let podName = chaiExec(getPodCommand).stdout.trim();
debugLog(`Pod selected for curl command: ${podName}`);
let execCommand = `kubectl --context ${context} -n ${namespace} exec ${podName} -- ${curlCommand}`;
const cli = chaiExec(execCommand);
debugLog(`Curl command output (stdout): ${cli.stdout}`);
return cli.stdout;
}
//# sourceMappingURL=chai-exec.js.map