@catladder/cli
Version:
Panter cli tool for cloud CI/CD and DevOps
91 lines (90 loc) • 4.19 kB
JavaScript
;
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);
}
});