@topgroup/diginext
Version:
A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.
95 lines (94 loc) • 5.59 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeploymentReadinessChecker = void 0;
const k8s_1 = __importDefault(require("../../../modules/k8s"));
const plugins_1 = require("../../../plugins");
class DeploymentReadinessChecker {
constructor(context, namespace, appName, appVersion, onUpdate) {
this.context = context;
this.namespace = namespace;
this.appName = appName;
this.appVersion = appVersion;
this.onUpdate = onUpdate;
}
async checkPodHealth(pods) {
const crashedPods = pods.filter((pod) => { var _a, _b; return (_b = (_a = pod.status) === null || _a === void 0 ? void 0 : _a.containerStatuses) === null || _b === void 0 ? void 0 : _b.some((status) => { var _a; return ((_a = status.state.waiting) === null || _a === void 0 ? void 0 : _a.reason) === "CrashLoopBackOff"; }); });
const creatingPods = pods.filter((pod) => { var _a, _b; return (_b = (_a = pod.status) === null || _a === void 0 ? void 0 : _a.containerStatuses) === null || _b === void 0 ? void 0 : _b.some((status) => { var _a; return ((_a = status.state.waiting) === null || _a === void 0 ? void 0 : _a.reason) === "ContainerCreating"; }); });
// const runningPods = pods.filter((pod) => pod.status?.phase === "Running");
const runningPods = pods.filter((pod) => { var _a, _b; return (_b = (_a = pod.status) === null || _a === void 0 ? void 0 : _a.conditions) === null || _b === void 0 ? void 0 : _b.some((c) => c.type === "Ready" && c.status === "True"); });
return {
totalPods: pods.length,
crashedPods: crashedPods.length,
creatingPods: creatingPods.length,
runningPods: runningPods.length,
isHealthy: crashedPods.length === 0 && creatingPods.length === 0,
};
}
async getPods() {
const filterLabel = `main-app=${this.appName}${this.appVersion ? `,app-version=${this.appVersion}` : ""}`;
return k8s_1.default.getPods(this.namespace, {
context: this.context,
filterLabel,
metrics: false,
});
}
/**
* Wait until no creating pods every `interval` seconds (Max wait time is 5 minutes)
* @param interval - Interval time in seconds
* @param maxWaitTime - Max wait time in seconds
*/
async waitUntilNoCreatingPods(interval = 10, maxWaitTime = 5 * 60) {
var _a, _b;
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, `Waiting until new pods of "${this.appName}" are finished creating...`);
await (0, plugins_1.waitUntil)(async () => {
var _a;
const pods = await this.getPods();
const health = await this.checkPodHealth(pods);
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, `Found ${health.creatingPods} creating pods`);
return health.creatingPods === 0;
}, interval, maxWaitTime);
(_b = this.onUpdate) === null || _b === void 0 ? void 0 : _b.call(this, `All new pods of "${this.appName}" are finished creating`);
}
/**
* Wait until at least one new pod is running
*/
async waitUntilAtLeastOnePodIsRunning() {
var _a, _b;
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, `Waiting until at least one new pod of "${this.appName}" is running...`);
await (0, plugins_1.waitUntil)(async () => {
var _a;
const pods = await this.getPods();
const health = await this.checkPodHealth(pods);
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, `Found ${health.runningPods} running pods out of ${health.totalPods}`);
// Check if any pods are crashed and throw an error if so
if (health.crashedPods > 0) {
throw new Error(`Found ${health.crashedPods} crashed pods out of ${health.totalPods}`);
}
return health.runningPods > 0;
}, 5, 5 * 60);
(_b = this.onUpdate) === null || _b === void 0 ? void 0 : _b.call(this, `At least one new pod of "${this.appName}" is running`);
}
async isDeploymentReady(requiredReplicas, options) {
var _a, _b, _c;
const pods = await this.getPods();
if (!pods.length) {
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, `No pods found for ${this.appName}`);
return false;
}
const health = await this.checkPodHealth(pods);
if (!(options === null || options === void 0 ? void 0 : options.skipCrashedPods) && !health.isHealthy) {
(_b = this.onUpdate) === null || _b === void 0 ? void 0 : _b.call(this, `Found ${health.crashedPods} crashed pods out of ${health.totalPods}`);
return false;
}
const readyPods = pods.filter((pod) => { var _a, _b; return (_b = (_a = pod.status) === null || _a === void 0 ? void 0 : _a.conditions) === null || _b === void 0 ? void 0 : _b.some((c) => c.type === "Ready" && c.status === "True"); });
const isReady = readyPods.length >= requiredReplicas;
if (!isReady) {
(_c = this.onUpdate) === null || _c === void 0 ? void 0 : _c.call(this, `Found ${readyPods.length} ready pods out of ${requiredReplicas}`);
}
return isReady;
}
}
exports.DeploymentReadinessChecker = DeploymentReadinessChecker;