Skip to content

Commit

Permalink
expanded deployment methods
Browse files Browse the repository at this point in the history
  • Loading branch information
achingbrain committed Dec 1, 2014
1 parent 9286eaf commit 38e150b
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 73 deletions.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ container.register('user', require('posix').getpwnam(process.getuid()))
container.register('group', require('posix').getgrnam(process.getgid()))
container.register('formatMemory', require('prettysize'))
container.register('os', require('os'))
container.register('fs', require('fs'))
container.createAndRegister('apps', require('./lib/Apps'))
container.createAndRegister('cluster', require('./lib/Cluster'))
container.createAndRegister('daemon', require('./lib/Daemon'))
Expand Down
12 changes: 9 additions & 3 deletions lib/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,17 @@ Actions.prototype._logBossMessages = function(boss) {
Actions.prototype._withRemoteProcess = function(boss, pid, callback) {
this._logger.debug('Connected, finding process info for pid %d', pid)

boss.findProcessInfoByPid(pid, function(error, processInfo) {
var method = 'findProcessInfoByPid'

if(isNaN(pid)) {
method = 'findProcessInfoByName'
}

boss[method](pid, function(error, processInfo) {
if (error) throw error

if(!processInfo) {
this._logger.error('No process exists for pid %d', pid)
this._logger.error('No process exists for %s', pid)
boss.disconnect()
process.exit(1)
}
Expand All @@ -97,7 +103,7 @@ Actions.prototype._withRemoteProcess = function(boss, pid, callback) {
}

if(error.code == 'ENOENT') {
return this._logger.error('No process was found with pid', pid)
return this._logger.error('No process was found for', pid)
}

if(error.code == 'ECONNREFUSED') {
Expand Down
7 changes: 4 additions & 3 deletions lib/Apps.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Apps.prototype.listApplications = function(options) {
table.addHeader(['Name', 'User', 'URL'])

deployedApplications.forEach(function(app) {
table.addRow([app.name, app.user, app.url])
table.addRow([app.name, app.user, app.url.grey])
})

table.print(console.info)
Expand Down Expand Up @@ -62,6 +62,7 @@ Apps.prototype.runApplication = function(name, ref, options) {
if(error) throw error

options.name = name
options.app = applicationInfo.id

this._processes.start(applicationInfo.path, options)
}.bind(this))
Expand All @@ -77,7 +78,7 @@ Apps.prototype.listRefs = function(name, options) {
table.addHeader(['Name', 'Commit'])

refs.forEach(function(ref) {
table.addRow([ref.name, ref.commit])
table.addRow([ref.name, ref.commit.grey])
})

table.print(console.info)
Expand All @@ -96,7 +97,7 @@ Apps.prototype.updateRefs = function(name, options) {
table.addHeader(['Name', 'Commit'])

refs.forEach(function(ref) {
table.addRow([ref.name, ref.commit])
table.addRow([ref.name, ref.commit.grey])
})

table.print(console.info)
Expand Down
46 changes: 20 additions & 26 deletions lib/CLI.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,62 +35,62 @@ CLI.prototype.afterPropertiesSet = function() {
.action(this._processes.list.bind(this._processes))

this._commander
.command('start <script>')
.command('start <scriptOrAppName>')
.description('Start a process')
.option('-u, --user <user>', 'The user to start a process as')
.option('-g, --group <group>', 'The group to start a process as')
.option('-i, --instances <instances>', 'How many instances of the process to start', parseInt)
.option('-n, --name <name>', 'What name to give the process')
.option('-n, --name <name>', 'What name to give the process (n.b. if starting an app this will be ignored')
.option('-a, --argv <argv>', 'A space separated list of arguments to pass to a process', this._parseList, [])
.option('-e, --execArgv <execArgv>', 'A space separated list of arguments to pass to the node executable', this._parseList, [])
.option('-d, --debug', 'Pause the process at the start of execution and wait for a debugger to be attached')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._processes.start.bind(this._processes))

this._commander
.command('cluster <pid> <workers>')
.command('cluster <pidOrName> <workers>')
.description('Set the number of workers managed by the cluster manager with the passed pid')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._cluster.setClusterWorkers.bind(this._cluster))

this._commander
.command('stop <pid>')
.command('stop <pidOrName>')
.description('Stop a process')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._processes.stop.bind(this._processes))

this._commander
.command('restart <pid>')
.command('restart <pidOrName>')
.description('Restart a process')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._processes.restart.bind(this._processes))

this._commander
.command('send <pid> <event> [args...]')
.command('send <pidOrName> <event> [args...]')
.description('Causes process.emit(event, args[0], args[1]...) to occur in the process')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._processes.send.bind(this._processes))

this._commander
.command('heapdump <pid>')
.command('heapdump <pidOrName>')
.description('Write out a snapshot of the processes memory for inspection')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._processes.heapdump.bind(this._processes))

this._commander
.command('gc <pid>')
.command('gc <pidOrName>')
.description('Force garbage collection to occur in the process with the passed pid')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._processes.gc.bind(this._processes))

this._commander
.command('signal <pid> <signal>')
.command('signal <pidOrName> <signal>')
.description('Sends a signal to a process (SIGUSR1, SIGINT, SIGHUP, SIGTERM, etc)')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._processes.signal.bind(this._processes))

this._commander
.command('logs [pid]')
.command('logs [pidOrName]')
.description('Show realtime process logs, optionally filtering by pid')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._daemon.logs.bind(this._daemon))
Expand Down Expand Up @@ -162,7 +162,7 @@ CLI.prototype.afterPropertiesSet = function() {
.action(this._remote.generateSSLCertificate.bind(this._remote))

this._commander
.command('deploy <name> <url>')
.command('deploy <appName> <url>')
.description('Deploys an application from a git repository')
.option('-u, --user <user>', 'The user to deploy as - n.b. the current user must be able to su to that user')
.option('-v, --verbose', 'Prints detailed internal logging output')
Expand All @@ -175,35 +175,29 @@ CLI.prototype.afterPropertiesSet = function() {
.action(this._apps.listApplications.bind(this._apps))

this._commander
.command('rmapp <name>')
.command('rmapp <appName>')
.description('Remote deployed application')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._apps.removeApplication.bind(this._apps))

this._commander
.command('startapp <name> [ref]')
.description('Start a deployed application at master/HEAD or the passed ref')
.option('-u, --user <user>', 'The user to start a process as')
.option('-g, --group <group>', 'The group to start a process as')
.option('-i, --instances <instances>', 'How many instances of the process to start', parseInt)
.option('-a, --argv <argv>', 'A space separated list of arguments to pass to a process', this._parseList, [])
.option('-e, --execArgv <execArgv>', 'A space separated list of arguments to pass to the node executable', this._parseList, [])
.option('-d, --debug', 'Pause the process at the start of execution and wait for a debugger to be attached')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._apps.runApplication.bind(this._apps))

this._commander
.command('lsrefs <name>')
.command('lsrefs <appName>')
.description('Lists app refs available to be started')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._apps.listRefs.bind(this._apps))

this._commander
.command('updaterefs <name>')
.command('updaterefs <appName>')
.description('Updates app refs available to be started')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._apps.updateRefs.bind(this._apps))

this._commander
.command('setref <appName> <ref>')
.description('Checks out the app at the passed ref')
.option('-v, --verbose', 'Prints detailed internal logging output')
.action(this._apps.updateRefs.bind(this._apps))

this._commander
.command('*')
.description('')
Expand Down
59 changes: 29 additions & 30 deletions lib/Processes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var Processes = function() {

this._moment = Autowire
this._formatMemory = Autowire
this._fs = Autowire
}
util.inherits(Processes, Actions)

Expand All @@ -18,7 +19,7 @@ Processes.prototype.list = function(options) {
if(error) throw error

var table = new Table('No running processes')
table.addHeader(['pid', 'user', 'group', 'name', 'uptime', 'restarts', 'cpu', 'rss', 'heap size', 'heap used', 'status', 'type'])
table.addHeader(['PID', 'User', 'Group', 'Name', 'Uptime', 'Restarts', 'CPU', 'RSS', 'Heap size', 'Heap used', 'Status', 'Type'])

var addProcessToTable = function(proc, type) {
if(!proc) {
Expand Down Expand Up @@ -57,8 +58,12 @@ Processes.prototype.list = function(options) {
}.bind(this))
}

Processes.prototype.start = function(script, options) {
script = path.resolve(script)
Processes.prototype.start = function(scriptOrAppName, options) {
var script = path.resolve(scriptOrAppName)

if(!this._fs.existsSync(script)) {
script = scriptOrAppName
}

var opts = this._parseStartProcessOpts(options)

Expand Down Expand Up @@ -109,18 +114,6 @@ Processes.prototype.start = function(script, options) {
}
})

boss.on('process:restarted', function(restartedProcessInfo) {
if(restartedProcessInfo.id != processInfo.id) {
return
}

if(restartedProcessInfo.status == 'paused') {
this._logger.warn('%s has been started in debug mode.', script)
this._logger.warn('It is paused and listening on port %d for a debugger to attach before continuing.', restartedProcessInfo.debugPort)
this._logger.warn('Please connect a debugger to this port (e.g. node-inspector or node-debugger).')
}
}.bind(this))

boss.on('cluster:online', function(clusterProcessInfo) {
if(clusterProcessInfo.id != processInfo.id) {
return
Expand Down Expand Up @@ -154,9 +147,9 @@ Processes.prototype.start = function(script, options) {
}.bind(this))
}

Processes.prototype.stop = function(pid, options) {
Processes.prototype.stop = function(pidOrName, options) {
this._do(options, function(boss) {
this._withRemoteProcess(boss, pid, function(error, remoteProcess) {
this._withRemoteProcess(boss, pidOrName, function(error, remoteProcess) {
if (error) throw error

this._logger.debug('Killing remote process')
Expand All @@ -167,9 +160,9 @@ Processes.prototype.stop = function(pid, options) {
}.bind(this))
}

Processes.prototype.restart = function(pid, options) {
Processes.prototype.restart = function(pidOrName, options) {
this._do(options, function(boss) {
this._withRemoteProcess(boss, pid, function(error, remoteProcess) {
this._withRemoteProcess(boss, pidOrName, function(error, remoteProcess) {
if (error) throw error

this._logger.debug('Restarting remote process')
Expand All @@ -180,13 +173,13 @@ Processes.prototype.restart = function(pid, options) {
}.bind(this))
}

Processes.prototype.send = function(pid, event, args, options) {
Processes.prototype.send = function(pidOrName, event, args, options) {
if(!args) {
args = []
}

this._do(options, function(boss) {
this._withRemoteProcess(boss, pid, function(error, remoteProcess) {
this._withRemoteProcess(boss, pidOrName, function(error, remoteProcess) {
if (error) throw error

args = [event].concat(args)
Expand All @@ -199,34 +192,40 @@ Processes.prototype.send = function(pid, event, args, options) {
}.bind(this))
}

Processes.prototype.signal = function(pid, signal, options) {
Processes.prototype.signal = function(pidOrName, signal, options) {
this._do(options, function(boss) {

boss.findProcessInfoByPid(pid, function(error, processInfo) {
var method = 'findProcessInfoByPid'

if(isNaN(pidOrName)) {
method = 'findProcessInfoByName'
}

boss[method](pidOrName, function(error, processInfo) {
if (error) throw error

if(!processInfo) {
this._logger.error('No process found for pid %d', pid)
this._logger.error('No process found for pid %d', pidOrName)

boss.disconnect()
}

this._logger.debug('Sending signal %s to %d', signal, pid)
this._logger.debug('Sending signal %s to %d', signal, pidOrName)

boss.sendSignal(processInfo.id, signal, function(error) {
if (error) throw error

this._logger.debug('Sent signal %s to %d', signal, pid)
this._logger.debug('Sent signal %s to %d', signal, pidOrName)

boss.disconnect()
}.bind(this))
}.bind(this))
}.bind(this))
}

Processes.prototype.heapdump = function(pid, options) {
Processes.prototype.heapdump = function(pidOrName, options) {
this._do(options, function(boss) {
this._withRemoteProcess(boss, pid, function(error, remoteProcess, processInfo) {
this._withRemoteProcess(boss, pidOrName, function(error, remoteProcess, processInfo) {
if (error) throw error

this._logger.debug('Writing heap dump')
Expand All @@ -241,9 +240,9 @@ Processes.prototype.heapdump = function(pid, options) {
}.bind(this))
}

Processes.prototype.gc = function(pid, options) {
Processes.prototype.gc = function(pidOrName, options) {
this._do(options, function(boss) {
this._withRemoteProcess(boss, pid, function(error, remoteProcess, processInfo) {
this._withRemoteProcess(boss, pidOrName, function(error, remoteProcess, processInfo) {
if (error) throw error

this._logger.debug('Garbage collecting')
Expand Down
12 changes: 9 additions & 3 deletions test/lib/AppsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ var expect = require('chai').expect,
path = require('path'),
Apps = require('../../lib/Apps')

require('colors')

describe('Apps', function() {
var apps, boss, info, error

Expand Down Expand Up @@ -106,7 +108,9 @@ describe('Apps', function() {
it('should list deployed applications', function(done) {
var options = {}
var applications = [{
name: 'foo'
name: 'foo',
user: 'bar',
url: 'baz'
}]
boss.listApplications = sinon.stub()
boss.listApplications.callsArgWith(0, undefined, applications)
Expand Down Expand Up @@ -238,7 +242,8 @@ describe('Apps', function() {
var app = 'foo'
var options = {}
var refs = [{
name: 'bar'
name: 'bar',
commit: 'baz'
}]
boss.listApplicationRefs = sinon.stub()
boss.listApplicationRefs.withArgs(app, sinon.match.func).callsArgWith(1, undefined, refs)
Expand Down Expand Up @@ -276,7 +281,8 @@ describe('Apps', function() {
var app = 'foo'
var options = {}
var refs = [{
name: 'bar'
name: 'bar',
commit: 'baz'
}]
boss.updateApplicationRefs = sinon.stub()
boss.updateApplicationRefs.withArgs(app, sinon.match.func, sinon.match.func, sinon.match.func).callsArgWith(3, undefined, refs)
Expand Down
Loading

0 comments on commit 38e150b

Please sign in to comment.