@apigeeks/fbl-k8s-plugin
Version:
fbl wrapper plugin for helm and kubectl cli utilities
165 lines • 8.02 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
var K8sCleanupService_1;
const minimatch = require("minimatch");
const lodash_1 = require("lodash");
const typedi_1 = require("typedi");
const K8sHelmService_1 = require("./K8sHelmService");
const K8sKubectlService_1 = require("./K8sKubectlService");
let K8sCleanupService = K8sCleanupService_1 = class K8sCleanupService {
/**
* Clean cluster
* @param {IK8sCleanupOptions} options
* @param {IContext} context
* @param {ActionSnapshot} snapshot
* @return {Promise<void>}
*/
cleanup(options, context, snapshot) {
return __awaiter(this, void 0, void 0, function* () {
const kinds = options.kinds || K8sCleanupService_1.defaultKinds;
const registeredHelmReleases = context.entities.registered
.filter(e => e.type === 'helm')
.map(e => e.payload.name);
const allHelmObjects = (lodash_1.flattenDeep(yield Promise.all(registeredHelmReleases.map((name) => __awaiter(this, void 0, void 0, function* () { return yield this.k8sHelmService.getHelmObjects(name); })))));
const deployedHelms = yield this.k8sHelmService.listInstalledHelms();
yield this.cleanUpHelmReleases(options, context, snapshot, registeredHelmReleases, deployedHelms);
for (const kind of kinds) {
const deployedK8sObjects = context.entities.registered
.filter(e => e.type === kind && e.payload.metadata.namespace === options.namespace)
.map(o => o.payload.metadata.name);
const cluster = yield this.k8sKubectlService.listObjects(kind, options.namespace);
yield this.cleanupK8sObjects(options, context, snapshot, kind, allHelmObjects, deployedK8sObjects, cluster, lodash_1.get(options, ['ignored', 'objects', kind], []));
}
});
}
/**
* Cleanup helm releases
* @param {IK8sCleanupOptions} options
* @param {IContext} context
* @param {ActionSnapshot} snapshot
* @param {string[]} registeredHelmReleases
* @param {string[]} deployedHelms
* @return {Promise<void>}
*/
cleanUpHelmReleases(options, context, snapshot, registeredHelmReleases, deployedHelms) {
return __awaiter(this, void 0, void 0, function* () {
const ignoredHelms = registeredHelmReleases;
const ignoredPatterns = lodash_1.get(options, 'ignored.helms', []);
const diff = this.findOrphans(deployedHelms, ignoredHelms).filter(d => {
for (const pattern of ignoredPatterns) {
if (minimatch(d, pattern)) {
return false;
}
}
return true;
});
if (!options.dryRun) {
yield Promise.all(diff.map((name) => __awaiter(this, void 0, void 0, function* () {
try {
yield this.k8sHelmService.remove(name, context);
snapshot.log(`Helm release "${name}" deleted`);
}
catch (e) {
snapshot.log(`Helm release "${name}" failed to delete: ${e.message}`, true);
}
})));
}
else if (diff.length) {
snapshot.log(`Found following helm releases to be cleaned up: ${diff.join(', ')}`);
}
});
}
/**
* @param {IK8sCleanupOptions} options
* @param {IContext} context
* @param {ActionSnapshot} snapshot
* @param {string} kind
* @param {IK8sObject[]} allHelmObjects
* @param {string[]} deployed
* @param {string[]} cluster
* @param {string[]} ignoredPatterns
* @return {Promise<void>}
*/
cleanupK8sObjects(options, context, snapshot, kind, allHelmObjects, deployed, cluster, ignoredPatterns) {
return __awaiter(this, void 0, void 0, function* () {
const ignoredObjects = [
...deployed,
...allHelmObjects
.filter((object) => object.kind === kind)
.map((object) => object.metadata.name),
];
const diff = this.findOrphans(cluster, ignoredObjects).filter(d => {
for (const pattern of ignoredPatterns) {
if (minimatch(d, pattern)) {
return false;
}
}
return true;
});
if (!options.dryRun) {
yield Promise.all(diff.map((name) => __awaiter(this, void 0, void 0, function* () {
try {
yield this.k8sKubectlService.deleteObject({
apiVersion: 'v1',
kind: kind,
metadata: {
name,
namespace: options.namespace,
},
}, context);
snapshot.log(`${kind} "${name}" deleted`);
}
catch (e) {
snapshot.log(`${kind} "${name}" failed to delete: ${e.message}`);
}
})));
}
else if (diff.length) {
snapshot.log(`Found following ${kind}s to be cleaned up: ${diff.join(', ')}`);
}
});
}
/**
* Difference between all objects inside the cluster and ones that were deployed
*
* @param {string[]} inCluster
* @param {string[]} deployed
* @return {string[]}
*/
findOrphans(inCluster, deployed) {
return lodash_1.difference(inCluster, deployed);
}
};
// All k8s Object kinds to be cleaned up
// Note: order matters, PVC should go before SC, or on some environments it will just fail to delete (like AWS)
K8sCleanupService.defaultKinds = ['PersistentVolumeClaim', 'StorageClass', 'Secret', 'ConfigMap'];
__decorate([
typedi_1.Inject(() => K8sKubectlService_1.K8sKubectlService),
__metadata("design:type", K8sKubectlService_1.K8sKubectlService)
], K8sCleanupService.prototype, "k8sKubectlService", void 0);
__decorate([
typedi_1.Inject(() => K8sHelmService_1.K8sHelmService),
__metadata("design:type", K8sHelmService_1.K8sHelmService)
], K8sCleanupService.prototype, "k8sHelmService", void 0);
K8sCleanupService = K8sCleanupService_1 = __decorate([
typedi_1.Service()
], K8sCleanupService);
exports.K8sCleanupService = K8sCleanupService;
//# sourceMappingURL=K8sCleanupService.js.map