-
Notifications
You must be signed in to change notification settings - Fork 0
Wait for dock removed #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c87ac67
7309826
9338b95
28a49a5
84a67f5
2ee07d7
7a429a0
d87ff95
bba8f96
ff37cde
bce051a
6e1f80f
3e62de6
a414d88
fc7bea1
a75ab1f
4b4242f
2dc464e
c923d18
0b40325
a2c8d06
3e7f20b
8468aa3
b3bac2a
3f9e11b
d2f8da8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| dependencies: | ||
| override: | ||
| - nvm install 4.2.2 | ||
| - nvm alias default 4.2.2 | ||
| - npm install -g npm@2.14.7 | ||
| - npm install |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,25 @@ | ||
| PORT=4000 | ||
| REDIS_HOST_KEYS="dockerHosts:" | ||
| BUILD_WEIGHT=10 | ||
| CONTAINER_WEIGHT=1 | ||
| DOCKER_CERT_PATH=/etc/ssl/docker | ||
| HISTORY_WEIGHT=10 | ||
| IMAGE_BUILDER=runnable/image-builder | ||
| IMAGE_BUILDER_LABEL=image-builder-container | ||
| LOG=true | ||
| IMAGE_BUILDER="runnable/image-builder" | ||
| IMAGE_BUILDER_LABEL="image-builder-container" | ||
| RUNNABLE_REGISTRY="registry.runnable.com" | ||
| ROLLBAR_KEY="f4888bcd48be45cabd42627dfed87bba" | ||
| ROLLBAR_OPTIONS_BRANCH="master" | ||
| NEWRELIC_NAME='mavis' | ||
| NEWRELIC_LEVEL='error' | ||
| NEWRELIC_LEVEL=error | ||
| NEWRELIC_NAME=mavis | ||
| PORT=4000 | ||
| REDIS_HOST_KEYS=dockerHosts: | ||
| ROLLBAR_KEY=f4888bcd48be45cabd42627dfed87bba | ||
| ROLLBAR_OPTIONS_BRANCH=master | ||
| RUNNABLE_REGISTRY=registry.runnable.com | ||
|
|
||
| # Monitor-dog configuration | ||
| MONITOR_PREFIX="mavis" | ||
| MONITOR_PREFIX=mavis | ||
| MONITOR_INTERVAL=60000 | ||
|
|
||
| # Logging configuration | ||
| LOG_LEVEL=trace | ||
|
|
||
| # ponos | ||
| WORKER_MAX_RETRY_DELAY=30000 | ||
| WORKER_MIN_RETRY_DELAY=10000 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,11 @@ | ||
| PORT=65213 | ||
| REDIS_PORT=6379 | ||
| REDIS_IPADDRESS=127.0.0.1 | ||
| CONSUL_HOST=consul.com | ||
| CONSUL_PORT=8500 | ||
| DOCKER_CERT_PATH=./test/fixtures/certs | ||
| LOG_LEVEL=fatal | ||
| PORT=65213 | ||
| RABBITMQ_HOSTNAME=localhost | ||
| RABBITMQ_PASSWORD=guest | ||
| RABBITMQ_USERNAME=guest | ||
| RABBITMQ_USERNAME=guest | ||
| REDIS_IPADDRESS=127.0.0.1 | ||
| REDIS_PORT=6379 | ||
| SWARM_CONTAINER_NAME=swarm |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| /** | ||
| * Consul API requests | ||
| * @module lib/models/Consul | ||
| */ | ||
| 'use strict'; | ||
| require('loadenv')('mavis:env'); | ||
|
|
||
| var url = require('url'); | ||
| var ErrorCat = require('error-cat'); | ||
| var error = new ErrorCat(); | ||
|
|
||
| var log = require('../logger').child({ module: 'consul' }); | ||
|
|
||
| module.exports = Consul; | ||
|
|
||
| /** | ||
| * class used to talk to Consul | ||
| */ | ||
| function Consul () {} | ||
|
|
||
| /** | ||
| * singleton consul client | ||
| * @type {Object} | ||
| */ | ||
| Consul._client = require('consul')({ | ||
| host: process.env.CONSUL_HOST, | ||
| port: process.env.CONSUL_PORT | ||
| }); | ||
|
|
||
| /** | ||
| * checks dock host key in consul to see if it exist. | ||
| * will cb with error if dock key still exist | ||
| * @param {String} dockerUrl docker host to check for format: http://10.0.0.1:4242 | ||
| * @param {Function} cb (err) | ||
| */ | ||
| Consul.ensureDockRemoved = function (dockerUrl, cb) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 for using |
||
| var host = url.parse(dockerUrl).host; | ||
| var logData = { host: host }; | ||
| log.info(logData, 'Consul.prototype.ensureDockRemoved'); | ||
| Consul._client.kv.get('swarm/docker/swarm/nodes/' + host, function(err, result) { | ||
| if (err) { return cb(err); } | ||
| // if we have a result that means the key still exist, cb with error | ||
| if (result) { | ||
| return cb(error.create(412, 'dock still exist', result)); | ||
| } | ||
|
|
||
| log.trace(logData, 'ensureDockRemoved dock as been removed'); | ||
| return cb(null); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to pass
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. something Anton showed me, its more clear when you do it this way |
||
| }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| /** | ||
| * Docker API requests | ||
| * @module lib/models/docker | ||
| */ | ||
| 'use strict'; | ||
| require('loadenv')('mavis:env'); | ||
|
|
||
| var Dockerode = require('dockerode'); | ||
| var put = require('101/put'); | ||
| var fs = require('fs'); | ||
| var join = require('path').join; | ||
| var url = require('url'); | ||
|
|
||
| var log = require('../logger').child({ module: 'docker' }); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, use NODE_PATH absolute require paths instead of relative paths |
||
|
|
||
| var certs = {}; | ||
|
|
||
| module.exports = Docker; | ||
|
|
||
| /** | ||
| * class used to talk to docker | ||
| * @param {string} dockerUrl format: http://hostname:hostport | ||
| */ | ||
| function Docker (dockerUrl) { | ||
| var parsedHost = url.parse(dockerUrl); | ||
|
|
||
| this._client = new Dockerode(put({ | ||
| host: parsedHost.hostname, | ||
| port: parsedHost.port | ||
| }, certs)); | ||
|
|
||
| this._logData = { | ||
| dockerUrl: dockerUrl | ||
| }; | ||
| log.trace(this._logData, 'Docker constructor'); | ||
| } | ||
|
|
||
| /** | ||
| * loads certs for docker. does not throw if failed, just logs | ||
| * sync function as this should only happen once on startup | ||
| */ | ||
| Docker.loadCerts = function () { | ||
| // try/catch is a better pattern for this, since checking to see if it exists | ||
| // and then reading files can lead to race conditions (unlikely, but still) | ||
| try { | ||
| var certPath = process.env.DOCKER_CERT_PATH; | ||
| certs.ca = fs.readFileSync(join(certPath, '/ca.pem')); | ||
| certs.cert = fs.readFileSync(join(certPath, '/cert.pem')); | ||
| certs.key = fs.readFileSync(join(certPath, '/key.pem')); | ||
| log.info('Docker.loadCerts docker certificates loaded'); | ||
| } catch (err) { | ||
| log.warn({ err: err }, 'Docker.loadCerts cannot load certificates for docker'); | ||
| throw err; | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * stop swarm docker container | ||
| * @param {Function} cb (err) | ||
| */ | ||
| Docker.prototype.killSwarmContainer = function (cb) { | ||
| var self = this; | ||
| log.info(self._logData, 'Docker.prototype.killSwarmContainer'); | ||
|
|
||
| self._client.getContainer(process.env.SWARM_CONTAINER_NAME).kill(function (err) { | ||
| if (err) { | ||
| log.error(put({ err: err }, self._logData), 'killSwarmContainer error killing container'); | ||
| return cb(err); | ||
| } | ||
|
|
||
| log.trace(self._logData, 'killSwarmContainer killing container success'); | ||
| cb(null); | ||
| }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,21 +3,20 @@ | |
| require('loadenv')('mavis:env'); | ||
| var url = require('url'); | ||
| var keypather = require('keypather')(); | ||
|
|
||
| var dockData = require('../models/dockData.js'); | ||
| var log = require('../logger').child({ module: 'events:docker' }); | ||
|
|
||
| var TaskFatalError = require('ponos').TaskFatalError; | ||
| var TaskError = require('ponos').TaskError; | ||
| var rabbitMQ = require('../rabbitmq.js'); | ||
|
|
||
| var dockData = require('../models/dockData.js'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, use NODE_PATH absolute require paths instead of relative paths |
||
| var Consul = require('../models/consul.js'); | ||
| var Docker = require('../models/docker.js'); | ||
| var rabbitMQ = require('../rabbitmq.js'); | ||
| var log = require('../logger').child({ module: 'events:docker' }); | ||
|
|
||
| /** | ||
| * Module used to handle runnable events | ||
| */ | ||
| var Events = module.exports = {}; | ||
|
|
||
|
|
||
| /** | ||
| * Handles docker `die` events. | ||
| * updates container build counts | ||
|
|
@@ -84,12 +83,45 @@ Events.handleUnhealthy = function (data, cb) { | |
| } | ||
| dockData.deleteHost(data.host, function (err) { | ||
| if (err) { | ||
| var taskErr = new TaskError('Failed to delete host', err); | ||
| var taskErr = new TaskError('handleUnhealthy', 'Failed to delete host', err); | ||
| return cb(taskErr); | ||
| } | ||
| var docker = new Docker(data.host); | ||
| docker.killSwarmContainer(function (err) { | ||
| if (err) { | ||
| var taskErr = new TaskError('handleUnhealthy', 'Failed to kill swarm container', err); | ||
| return cb(taskErr); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. log error |
||
| } | ||
|
|
||
| rabbitMQ.getPublisher().publish('cluster-instance-provision', { | ||
| githubId: data.githubId | ||
| }); | ||
| rabbitMQ.getPublisher().publish('dock.wait-for-removal', { | ||
| dockerUrl: data.host | ||
| }); | ||
| cb(); | ||
| }); | ||
| }); | ||
| }; | ||
|
|
||
| /** | ||
| * waits for dock to be removed form consul | ||
| * then publish dock.removed event | ||
| * @param {Object} data job data | ||
| * @param {String} data.dockerUrl url to check for format: http://10.0.0.1:4242 | ||
| * @param {Function} cb (err) | ||
| */ | ||
| Events.handleEnsureDockRemoved = function (data, cb) { | ||
| log.info({ data: data }, 'Events.handleEnsureDockRemoved'); | ||
| Consul.ensureDockRemoved(data.dockerUrl, function (err) { | ||
| if (err) { | ||
| var taskErr = new TaskError('dock.wait-for-removal', 'dock still exists', err); | ||
| return cb(taskErr); | ||
| } | ||
| rabbitMQ.getPublisher().publish('on-dock-removed', data); | ||
| rabbitMQ.getPublisher().publish('cluster-instance-provision', { | ||
| githubId: data.githubId | ||
|
|
||
| log.trace({ data: data }, 'handleEnsureDockRemoved publishing dock.removed'); | ||
| rabbitMQ.getPublisher().publish('dock.removed', { | ||
| host: data.dockerUrl | ||
| }); | ||
| cb(); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /** | ||
| * Handles `dock.wait-for-removal` event | ||
| * @module lib/workers/dock.wait-for-removal | ||
| */ | ||
| 'use strict'; | ||
|
|
||
| var isString = require('101/is-string'); | ||
| var Promise = require('bluebird'); | ||
| var TaskFatalError = require('ponos').TaskFatalError; | ||
|
|
||
| var Events = Promise.promisifyAll(require('../models/events.js')); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, use NODE_PATH absolute require paths instead of relative paths |
||
| var log = require('../logger').child({ module: 'workers' }); | ||
|
|
||
| module.exports = function (job) { | ||
| return Promise.resolve() | ||
| .then(function validateArguments () { | ||
| if (!isString(job.dockerUrl)) { | ||
| throw new TaskFatalError('missing dockerUrl'); | ||
| } | ||
| }) | ||
| .then(function () { | ||
| return Events.handleEnsureDockRemovedAsync(job); | ||
| }) | ||
| .catch(function (err) { | ||
| log.error({ err: err }, 'dock.wait-for-removal error'); | ||
| throw err; | ||
| }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ca |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| cert |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, use
NODE_PATHabsolute require paths instead of relative pathsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NODE_PATH is not used in this project, keeping it consistent for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? We use it in all the other projects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant it is currently not in this repo, it is also out of scope for this PR, can convert to it later but might not be worth it (mavis is going to be deprecated soon, this is just stop gap patch until swarm provides removal api)