-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from CodeNow/hotfix.cache
Hotfix.cache
- Loading branch information
Showing
33 changed files
with
980 additions
and
334 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ node_modules | |
layer-cache | ||
image-builder.iml | ||
scripts/*.log | ||
DOCKER_IP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,31 @@ | ||
'use strict'; | ||
|
||
var Docker = require('dockerode'); | ||
var url = require('url'); | ||
|
||
var dockerHost = {}; | ||
module.exports = docker; | ||
|
||
if (~process.env.RUNNABLE_DOCKER.indexOf('unix://')) { | ||
// format: unix:///var/run/docker.sock | ||
dockerHost.socketPath = process.env.RUNNABLE_DOCKER.replace('unix://', ''); | ||
} else if (process.env.RUNNABLE_DOCKER.split(':').length === 2) { | ||
// format: 10.234.129.94:5354 | ||
dockerHost.host = process.env.RUNNABLE_DOCKER.split(':')[0]; | ||
dockerHost.port = process.env.RUNNABLE_DOCKER.split(':')[1]; | ||
} | ||
function docker () { | ||
if (!process.env.RUNNABLE_DOCKER) { | ||
throw new Error('RUNNABLE_DOCKER required'); | ||
} | ||
var uri = url.parse(process.env.RUNNABLE_DOCKER); | ||
|
||
var dockerHost = {}; | ||
if (uri.protocol === 'unix:' && uri.slashes) { | ||
// format: unix:///var/run/docker.sock | ||
dockerHost.socketPath = uri.path; | ||
} else { | ||
// format: tcp://10.234.129.94:5354 | ||
if (uri.port && uri.hostname) { | ||
dockerHost.host = uri.hostname; | ||
dockerHost.port = uri.port; | ||
} | ||
} | ||
|
||
module.exports = new Docker(dockerHost); | ||
if (Object.keys(dockerHost).length === 0) { | ||
throw new Error('dockerhost not set'); | ||
} | ||
|
||
return new Docker(dockerHost); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,59 @@ | ||
'use strict'; | ||
|
||
var conire = require('conire'); | ||
var Driver = conire(process.env.RUNNABLE_NETWORK_DRIVER, { | ||
signal: './signal-client.js', | ||
sauron: 'sauron-client' | ||
}); | ||
|
||
var driver = new Driver( | ||
process.env.RUNNABLE_SAURON_HOST.split(':')[0], | ||
process.env.RUNNABLE_SAURON_HOST.split(':')[1]); | ||
|
||
module.exports = { | ||
// attach network to current container | ||
attach: function(containerId, cb) { | ||
var networkIp = process.env.RUNNABLE_NETWORK_IP; | ||
var hostIp = process.env.RUNNABLE_HOST_IP; | ||
// TODO: emit this as an event | ||
// "containerId" needs network | ||
// message will include hostIp and containerId and dockIp | ||
|
||
// needs to be super robust, retry a few times, and force attach | ||
retryOnError(driver.attachHostToContainer.bind(driver, networkIp, hostIp, { | ||
containerId: containerId, | ||
force: true | ||
}), cb); | ||
|
||
module.exports = Network; | ||
|
||
function Network () { | ||
if (!process.env.RUNNABLE_SAURON_HOST) { | ||
throw new Error('require sauronHost'); | ||
} | ||
}; | ||
if (!process.env.RUNNABLE_NETWORK_IP) { | ||
throw new Error('require networkIp'); | ||
} | ||
if (!process.env.RUNNABLE_HOST_IP) { | ||
throw new Error('require hostIp'); | ||
} | ||
if (!process.env.RUNNABLE_NETWORK_DRIVER) { | ||
throw new Error('require driver'); | ||
} | ||
|
||
this.networkIp = process.env.RUNNABLE_NETWORK_IP; | ||
this.hostIp = process.env.RUNNABLE_HOST_IP; | ||
|
||
function retryOnError(func, cb) { | ||
var Driver = conire(process.env.RUNNABLE_NETWORK_DRIVER, { | ||
signal: './signal-client.js', | ||
sauron: 'sauron-client' | ||
}); | ||
|
||
this.driver = new Driver( | ||
process.env.RUNNABLE_SAURON_HOST.split(':')[0], | ||
process.env.RUNNABLE_SAURON_HOST.split(':')[1]); | ||
} | ||
|
||
// TODO: emit this as an event | ||
// "containerId" needs network | ||
// message will include hostIp and containerId and dockIp | ||
Network.prototype.attach = function(containerId, cb) { | ||
// needs to be super robust, retry a few times, and force attach | ||
var retryCount = 5; | ||
var self = this; | ||
retry(); | ||
function retry (err) { | ||
retryCount--; | ||
if (retryCount <= 0) { | ||
if (retryCount < 0) { | ||
return cb(err); | ||
} | ||
func(function(err, res) { | ||
if (err || res.statusCode >= 500) { | ||
return setTimeout(retry.bind(null, err || res.statusCode), 1000); | ||
|
||
self.driver.attachHostToContainer(self.networkIp, self.hostIp, { | ||
containerId: containerId, | ||
force: true | ||
}, function(err, res) { | ||
if (err) { | ||
return setTimeout(retry.bind(this, err), 1000); | ||
} | ||
|
||
cb(null, res); | ||
}); | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,118 @@ | ||
'use strict'; | ||
|
||
require('colors'); | ||
var tar = require('tar-fs'); | ||
var fs = require('fs'); | ||
var Network = require('../external/network.js'); | ||
|
||
var docker = require('../external/docker.js'); | ||
var network; | ||
// we only need network if we are using weave | ||
if (process.env.RUNNABLE_WAIT_FOR_WEAVE) { | ||
network = require('../external/network.js'); | ||
} | ||
var noop = function () {}; | ||
|
||
module.exports = Builder; | ||
|
||
var noop = function(){}; | ||
function Builder (steps) { | ||
this.dockerContext = steps.dirs.dockerContext; | ||
this.dockerBuildLog = steps.logs.dockerBuild; | ||
this.saveToLogs = steps.saveToLogs; | ||
|
||
module.exports = function runDockerBuild (steps, cb) { | ||
if (!process.env.RUNNABLE_DOCKERTAG) { | ||
return cb(new Error('RUNNABLE_DOCKERTAG is missing.')); | ||
if (process.env.RUNNABLE_DOCKER) { | ||
this.docker = require('../external/docker.js')(); | ||
} | ||
if (!process.env.RUNNABLE_DOCKER_BUILDOPTIONS) { | ||
process.env.RUNNABLE_DOCKER_BUILDOPTIONS = ''; | ||
// we only need network if we are using weave | ||
if (process.env.RUNNABLE_WAIT_FOR_WEAVE) { | ||
this.network = new Network(); | ||
} | ||
} | ||
|
||
Builder.prototype.runDockerBuild = function (cb) { | ||
var self = this; | ||
self.tarContext(function (err) { | ||
if (err) { return cb(err); } | ||
|
||
console.log('Building server...'.bold.yellow); | ||
var tarPath = steps.dirs.dockerContext+'.tar'; | ||
self.startImageBuild(cb); | ||
}); | ||
}; | ||
|
||
Builder.prototype.tarContext = function (cb) { | ||
this.tarPath = this.dockerContext + '.tar'; | ||
tar | ||
.pack(steps.dirs.dockerContext) | ||
.pipe(fs.createWriteStream(tarPath)) | ||
.on('finish', function() { | ||
docker.buildImage(tarPath, { | ||
t: process.env.RUNNABLE_DOCKERTAG | ||
}, function (err, response) { | ||
if (err) { return cb(err); } | ||
|
||
var buildErr = null; | ||
var needAttach = null; | ||
response.on('data', function(data) { | ||
data = JSON.parse(data); | ||
fs.appendFileSync(steps.logs.dockerBuild, data.error || data.stream); | ||
steps.saveToLogs(noop)(null, data.stream || '', data.error || ''); | ||
var out = data.stream; | ||
|
||
// TODO: make this a robust state machine | ||
// we only need to be stateful for one event no need to do it now | ||
if (data.error) { | ||
buildErr = data.error; | ||
out = data.error; | ||
} else if (needAttach) { | ||
needAttach = false; | ||
var containerId = data | ||
.stream | ||
.split('Running in ')[1] | ||
.replace('\n','') | ||
.trim(); | ||
|
||
network.attach(containerId, function(err) { | ||
// something went wrong, kill container to stop the build | ||
if (err) { | ||
process.stderr.write('error attaching to runnable network \n'); | ||
process.stderr.write('please rebuild'); | ||
docker.getContainer(containerId).kill(function() { | ||
process.exit(1); | ||
}); | ||
} | ||
}); | ||
} else if ( | ||
~data.stream.indexOf(process.env.RUNNABLE_WAIT_FOR_WEAVE)) { | ||
out = | ||
data.stream.replace(process.env.RUNNABLE_WAIT_FOR_WEAVE, ''); | ||
needAttach = true; | ||
} | ||
|
||
process.stdout.write(out); | ||
}); | ||
response.on('end', function() { | ||
cb(buildErr); | ||
}); | ||
.pack(this.dockerContext) | ||
.pipe(fs.createWriteStream(this.tarPath)) | ||
.on('finish', cb); | ||
}; | ||
|
||
Builder.prototype.startImageBuild = function (cb) { | ||
var self = this; | ||
this.docker.buildImage(self.tarPath, { | ||
t: process.env.RUNNABLE_DOCKERTAG | ||
}, function (err, response) { | ||
if (err) { return cb(err); } | ||
self.handleBuild(response, cb); | ||
}); | ||
}; | ||
|
||
Builder.prototype.handleBuild = function (response, cb) { | ||
var self = this; | ||
|
||
response.on('error', cb); | ||
response.on('data', function (data) { | ||
self.handleBuildData(data); | ||
}); | ||
response.on('end', function () { | ||
cb(self.buildErr); | ||
}); | ||
}; | ||
|
||
Builder.prototype.handleBuildData = function (data) { | ||
var self = this; | ||
|
||
data = JSON.parse(data); | ||
var out = data.stream || ''; | ||
fs.appendFileSync(self.dockerBuildLog, data.error || out); | ||
self.saveToLogs(noop)(null, out, data.error || ''); | ||
|
||
// TODO: make this a robust state machine | ||
// we only need to be stateful for one event no need to do it now | ||
if (data.error) { | ||
self.buildErr = data.error; | ||
out = data.error; | ||
} else if (this.needAttach) { | ||
this.needAttach = false; | ||
self.handleNetworkAttach(out); | ||
} else if (isWaitForWeaveLine(out)) { | ||
this.needAttach = true; | ||
out = out.replace(process.env.RUNNABLE_WAIT_FOR_WEAVE, ''); | ||
} | ||
|
||
process.stdout.write(out); | ||
}; | ||
|
||
function isWaitForWeaveLine (line) { | ||
return ~line.indexOf(process.env.RUNNABLE_WAIT_FOR_WEAVE); | ||
} | ||
|
||
Builder.prototype.handleNetworkAttach = function (line) { | ||
var self = this; | ||
// ignore if not Running In aka cache line | ||
if (!~line.indexOf('Running in ')) { return; } | ||
|
||
var containerId = line | ||
.split('Running in ')[1] | ||
.replace('\n','') | ||
.trim(); | ||
|
||
self.network.attach(containerId, self.postNetworkAttach(containerId)); | ||
}; | ||
|
||
Builder.prototype.postNetworkAttach = function (containerId) { | ||
var self = this; | ||
return function (err) { | ||
// something went wrong, kill container to stop the build | ||
if (err) { | ||
process.stderr.write('error attaching to runnable network \n'); | ||
process.stderr.write('please rebuild'); | ||
self.docker.getContainer(containerId).kill(function () { | ||
process.exit(1); | ||
}); | ||
}); | ||
}; | ||
} | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.