UNPKG

binci

Version:

Utility for running containerized development workflows

163 lines (158 loc) 4.98 kB
/* eslint no-unneeded-ternary: 0 */ 'use strict' const _ = require('halcyon') const command = require('./command') const proc = require('./proc') const services = { /** * @property {array} All running services for this instance */ running: [], /** * @property {array} All services disabled by instance task */ disabled: [], /** * Checks if given task has a 'disable' key, and removes services accordingly * @param {Object} cfg Instance config object * @returns {Object} formatted config object */ filterEnabled: (cfg) => { if (!cfg.run.length) return cfg const tasks = _.values(_.pick(cfg.run, cfg.tasks)) const objs = _.filter(_.isType('object'), tasks) // If any running task doesn't have object config and no services specified in command line, keep all services if ( objs.length !== tasks.length && !services.disabled.length && !services.disableAll ) { return cfg } const allSvcs = _.chain(_.keys, cfg.services) let svcs if (services.disableAll) { svcs = allSvcs } else { svcs = _.chain((t) => (t.disable === '*' ? allSvcs : t.disable), objs) services.disabled.forEach((s) => { if (!_.contains(s, svcs)) svcs.push(s) }) } // Track which services are disabled by running tasks const counts = _.pipe([_.groupBy(_.identity), _.map(_.length)])(svcs) // Add service to list if disabled by all running tasks services.disabled = _.keys(_.filter(_.equals(tasks.length), counts)) /* istanbul ignore if: lots of work, testing doesn't prove anything... */ if (!services.disabled.length) return cfg // Keep service if name is not in disabled list cfg.services = _.filter( (s) => !_.contains(_.head(_.keys(s)), services.disabled), cfg.services ) return cfg }, /** * Returns stopTimeSecs prop from either the (1) service config (2) global config or (3) default * @param {object} cfg Instance config object * @param {object} svc Service config object * @returns {number} */ getStopTimeSecs: (cfg, svc) => { if (_.isType('number', svc.stopTimeSecs)) return svc.stopTimeSecs if (_.isType('number', cfg.stopTimeSecs)) return cfg.stopTimeSecs return 10 }, /** * Gets all services and returns name, persistence, and arguments * @param {Object} cfg Instance config object * @returns {array} Array of services names, persistence and run args */ get: (cfg) => !cfg.services ? false : _.map( _.pipe([ _.toPairs, _.head, ([name, value]) => ({ name, persist: value.persist || false, stopTimeSecs: services.getStopTimeSecs(cfg, value), args: command.get( _.merge(value, { rmOnShutdown: cfg.rmOnShutdown, privileged: cfg.privileged === false ? false : true }), name, null ) }) ]), cfg.services ), /** * Runs services and resolves or rejects * @param {array} svc Array of service command arrays * @returns {object} promise */ run: (svc) => { const errors = [] return Promise.all( _.map((cur) => { let curName = command.getName(cur.name, { persist: cur.persist }) return proc.exec(`docker ps -f name=${curName} -q`).then((res) => { if (res && res.toString().length) return Promise.resolve() // Already running, resolve return proc .run(cur.args, true) .then(() => services.running.push({ name: curName, stopTimeSecs: cur.stopTimeSecs }) ) .catch(() => errors.push(cur.name)) }) }, svc) ).then(() => { const startError = new Error() if (errors.length) { startError.svcs = errors throw startError } }) }, /** * Kills all running, non-persisted services * @returns {object} promise */ stop: (cfg) => { const errors = [] return Promise.all( _.pipe([ _.filter((svc) => _.test(/bc_/, svc.name)), _.map((svc) => proc .run(['stop', '-t', svc.stopTimeSecs, svc.name], true) .then(() => cfg.rmOnShutdown ? proc.run(['rm', svc.name], true) : Promise.resolve() ) .catch(() => { /* istanbul ignore next: difficult to make a container shutdown fail reliably */ errors.push(svc.name) }) ) ])(services.running) ).then(() => { const stopError = new Error() /* istanbul ignore next: this is actually tested, istanbul... */ if (errors.length) { stopError.svcs = errors throw stopError } }) } } module.exports = services