UNPKG

@catladder/cli

Version:

Panter cli tool for cloud CI/CD and DevOps

91 lines (90 loc) 4.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.commandMongoDestroyMember = void 0; const child_process_promise_1 = require("child-process-promise"); const defineCommand_1 = require("../../core/defineCommand"); const kubernetes_1 = require("../../kubernetes"); const log_1 = require("../../utils/log"); const projects_1 = require("../../utils/projects"); const ensureCluster_1 = require("../../apps/cli/commands/project/utils/ensureCluster"); const utils_1 = require("../../apps/cli/commands/mongodb/utils"); const autocompletions_1 = require("../../apps/cli/commands/project/utils/autocompletions"); const availability_1 = require("../availability"); const removeFinalizer = async (namespace, type, name) => (0, child_process_promise_1.exec)(`kubectl patch --namespace ${namespace} ${type} ${name} -p '{"metadata":{"finalizers":null}}'`); const deleteResource = async (namespace, type, name) => (0, child_process_promise_1.exec)(`kubectl delete --namespace ${namespace} ${type} ${name}`); const removeFinalizerAndDelete = async (namespace, type, name) => { return Promise.all([removeFinalizer(namespace, type, name), await deleteResource(namespace, type, name)]); }; exports.commandMongoDestroyMember = (0, defineCommand_1.defineCommand)({ name: "project mongo destroy-member", description: "DESTROY a member of a replicaset in order to reinitialize it", group: "mongodb", isAvailable: (0, availability_1.hasDeployType)("kubernetes"), inputs: { envComponent: { type: "string", message: "environment:component", positional: true, choices: async () => (0, autocompletions_1.envAndComponents)() }, podName: { type: "string", message: "Which pod? 🤔", choices: async ctx => { const envComponent = await ctx.get("envComponent"); const mongodbPods = await (0, utils_1.getMongoDbPodsWithReplInfo)(envComponent); const secondaries = mongodbPods.filter(pod => !pod.isMaster); return secondaries.map(p => ({ name: `[ secondary ] ${p.podName}`, value: p.podName })); } } }, execute: async ctx => { const envComponent = await ctx.get("envComponent"); await (0, ensureCluster_1.ensureCluster)(ctx, envComponent); ctx.log("this command tries to delete a (secondary) member of the replicaset, it's persistent volume claim (pvc) and the volume"); ctx.log(""); ctx.log("this is useful, if you update the stateful set with new volume configuration (different size or storage class)"); ctx.log(""); ctx.log("Kubernetes will usually recreate the missing member with the updated config and mongodb will start synchronizing the new member."); ctx.log(""); ctx.log("This works without downtime, but should be done when load on the db is low. Also it has not been tested with large dbs (> 10gi)"); ctx.log(""); ctx.log("Deleting the volume and claim often stuck, just wait or cancel and restart."); ctx.log(""); const understood = await ctx.confirm("DO YOU UNDERSTAND?"); if (!understood) { throw new Error("abort"); } const namespace = await (0, projects_1.getProjectNamespace)(envComponent); const pvcs = await (0, kubernetes_1.getProjectPvcs)(envComponent); const podName = await ctx.get("podName"); const thePvc = pvcs.find(pvc => pvc.metadata.name === `datadir-${podName}`); if (!thePvc) { (0, log_1.logError)(ctx, `sorry, no pvc found for ${podName}`); return; } const shouldContinue = await ctx.confirm("THIS WILL DESTROY THE POD, ITS VOLUME AND ALL ITS DATA 🙀🙀🙀!!! continue? 🤔"); if (!shouldContinue) { throw new Error("abort"); } ctx.log("destroying volume..."); try { await removeFinalizerAndDelete(namespace, "pv", thePvc.spec.volumeName); } catch (e) { ctx.log(e.message); } ctx.log("destroying volume claim..."); try { await removeFinalizerAndDelete(namespace, "pvc", thePvc.metadata.name); } catch (e) { ctx.log(e.message); } ctx.log("destroying pod..."); await removeFinalizerAndDelete(namespace, "pod", podName); } });