UNPKG

@topgroup/diginext

Version:

A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.

95 lines (94 loc) 5.59 kB
"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;