Read ca files and convert to string before passing to the docker daemon

Before this commit, the docker daemon would recieve the filename of the
.pem files, which would be interpreted as the body and would fail. This
commit ensures that the actual body of the pem files are sent to the
daemon.

Change-type: patch
Connects-to: #562
Signed-off-by: Cameron Diver <cameron@resin.io>
This commit is contained in:
Cameron Diver 2017-06-20 11:48:15 +01:00
parent 378f894da3
commit 5000febf72
No known key found for this signature in database
GPG Key ID: 40968281F12927FD
5 changed files with 219 additions and 189 deletions

View File

@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## Fixed
- Ensure to send .pem file contents rather than filename to docker daemon
## [5.11.0] - 2017-06-19
### Added

View File

@ -202,57 +202,57 @@ module.exports = {
tmp.setGracefulCleanup();
logs = '';
upload = function(token, username, url) {
var docker;
docker = dockerUtils.getDocker(options);
return parseInput(params, options).then(function(arg) {
var appName, build, imageName, source;
appName = arg[0], build = arg[1], source = arg[2], imageName = arg[3];
return tmpNameAsync().then(function(bufferFile) {
options = _.assign({}, options, {
appName: appName
});
params = _.assign({}, params, {
source: source
});
return Promise["try"](function() {
if (build) {
return dockerUtils.runBuild(params, options, getBundleInfo, logStreams);
} else {
return {
image: imageName,
log: ''
};
}
}).then(function(arg1) {
var buildLogs, imageName;
imageName = arg1.image, buildLogs = arg1.log;
logging.logInfo(logStreams, 'Initializing deploy...');
logs = buildLogs;
return Promise.all([dockerUtils.bufferImage(docker, imageName, bufferFile), token, username, url, params.appName, logStreams]).spread(performUpload);
})["finally"](function() {
return dockerUtils.getDocker(options).then(function(docker) {
return parseInput(params, options).then(function(arg) {
var appName, build, imageName, source;
appName = arg[0], build = arg[1], source = arg[2], imageName = arg[3];
return tmpNameAsync().then(function(bufferFile) {
options = _.assign({}, options, {
appName: appName
});
params = _.assign({}, params, {
source: source
});
return Promise["try"](function() {
return require('mz/fs').unlink(bufferFile);
})["catch"](_.noop);
if (build) {
return dockerUtils.runBuild(params, options, getBundleInfo, logStreams);
} else {
return {
image: imageName,
log: ''
};
}
}).then(function(arg1) {
var buildLogs, imageName;
imageName = arg1.image, buildLogs = arg1.log;
logging.logInfo(logStreams, 'Initializing deploy...');
logs = buildLogs;
return Promise.all([dockerUtils.bufferImage(docker, imageName, bufferFile), token, username, url, params.appName, logStreams]).spread(performUpload);
})["finally"](function() {
return Promise["try"](function() {
return require('mz/fs').unlink(bufferFile);
})["catch"](_.noop);
});
});
});
}).tap(function(arg) {
var buildId, imageName;
imageName = arg.image, buildId = arg.buildId;
logging.logSuccess(logStreams, "Successfully deployed image: " + (formatImageName(imageName)));
return buildId;
}).then(function(arg) {
var buildId, imageName;
imageName = arg.image, buildId = arg.buildId;
if (logs === '' || (options.nologupload != null)) {
return '';
}
logging.logInfo(logStreams, 'Uploading logs to dashboard...');
return Promise.join(logs, token, url, buildId, username, params.appName, uploadLogs)["return"]('Successfully uploaded logs');
}).then(function(msg) {
if (msg !== '') {
return logging.logSuccess(logStreams, msg);
}
}).asCallback(done);
}).tap(function(arg) {
var buildId, imageName;
imageName = arg.image, buildId = arg.buildId;
logging.logSuccess(logStreams, "Successfully deployed image: " + (formatImageName(imageName)));
return buildId;
}).then(function(arg) {
var buildId, imageName;
imageName = arg.image, buildId = arg.buildId;
if (logs === '' || (options.nologupload != null)) {
return '';
}
logging.logInfo(logStreams, 'Uploading logs to dashboard...');
return Promise.join(logs, token, url, buildId, username, params.appName, uploadLogs)["return"]('Successfully uploaded logs');
}).then(function(msg) {
if (msg !== '') {
return logging.logSuccess(logStreams, msg);
}
}).asCallback(done);
});
};
return Promise.join(resin.auth.getToken(), resin.auth.whoami(), resin.settings.get('resinUrl'), upload);
}

View File

@ -58,27 +58,35 @@ exports.appendOptions = function(opts) {
};
exports.generateConnectOpts = generateConnectOpts = function(opts) {
var connectOpts;
connectOpts = {};
if ((opts.docker != null) && (opts.dockerHost == null)) {
connectOpts.socketPath = opts.docker;
} else if ((opts.dockerHost != null) && (opts.docker == null)) {
connectOpts.host = opts.dockerHost;
connectOpts.port = opts.dockerPort || 2376;
} else if ((opts.docker != null) && (opts.dockerHost != null)) {
throw new Error("Both a local docker socket and docker host have been provided. Don't know how to continue.");
} else {
connectOpts.socketPath = '/var/run/docker.sock';
}
if ((opts.ca != null) || (opts.cert != null) || (opts.key != null)) {
if (!((opts.ca != null) && (opts.cert != null) && (opts.key != null))) {
throw new Error('You must provide a CA, certificate and key in order to use TLS');
var Promise, fs;
Promise = require('bluebird');
fs = require('mz/fs');
return Promise["try"](function() {
var connectOpts;
connectOpts = {};
if ((opts.docker != null) && (opts.dockerHost == null)) {
connectOpts.socketPath = opts.docker;
} else if ((opts.dockerHost != null) && (opts.docker == null)) {
connectOpts.host = opts.dockerHost;
connectOpts.port = opts.dockerPort || 2376;
} else if ((opts.docker != null) && (opts.dockerHost != null)) {
throw new Error("Both a local docker socket and docker host have been provided. Don't know how to continue.");
} else {
connectOpts.socketPath = '/var/run/docker.sock';
}
connectOpts.ca = opts.ca;
connectOpts.cert = opts.cert;
connectOpts.key = opts.key;
}
return connectOpts;
if ((opts.ca != null) || (opts.cert != null) || (opts.key != null)) {
if (!((opts.ca != null) && (opts.cert != null) && (opts.key != null))) {
throw new Error('You must provide a CA, certificate and key in order to use TLS');
}
return Promise.all([fs.readFile(opts.ca), fs.readFile(opts.cert), fs.readFile(opts.key)]).spread(function(ca, cert, key) {
connectOpts.ca = ca.toString();
connectOpts.cert = cert.toString();
connectOpts.key = key.toString();
return connectOpts;
});
}
return connectOpts;
});
};
exports.tarDirectory = tarDirectory = function(dir) {
@ -189,7 +197,7 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) {
return tarDirectory(params.source);
}).then(function(tarStream) {
return new Promise(function(resolve, reject) {
var builder, connectOpts, hooks, opts;
var hooks;
hooks = {
buildSuccess: function(image) {
var doodle;
@ -252,23 +260,25 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) {
return newStream.pipe(logThroughStream).pipe(cacheHighlightStream()).pipe(logStreams.build);
}
};
connectOpts = generateConnectOpts(options);
logging.logDebug(logStreams, 'Connecting with the following options:');
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '));
builder = new dockerBuild.Builder(connectOpts);
opts = {};
if (options.tag != null) {
opts['t'] = options.tag;
}
if (options.nocache != null) {
opts['nocache'] = true;
}
if (options.buildArg != null) {
opts['buildargs'] = parseBuildArgs(options.buildArg, function(arg) {
return logging.logWarn(logStreams, "Could not parse variable: '" + arg + "'");
});
}
return builder.createBuildStream(opts, hooks, reject);
return generateConnectOpts(options).then(function(connectOpts) {
var builder, opts;
logging.logDebug(logStreams, 'Connecting with the following options:');
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '));
builder = new dockerBuild.Builder(connectOpts);
opts = {};
if (options.tag != null) {
opts['t'] = options.tag;
}
if (options.nocache != null) {
opts['nocache'] = true;
}
if (options.buildArg != null) {
opts['buildargs'] = parseBuildArgs(options.buildArg, function(arg) {
return logging.logWarn(logStreams, "Could not parse variable: '" + arg + "'");
});
}
return builder.createBuildStream(opts, hooks, reject);
});
});
});
};
@ -287,12 +297,13 @@ exports.bufferImage = function(docker, imageId, bufferFile) {
};
exports.getDocker = function(options) {
var Docker, Promise, connectOpts;
var Docker, Promise;
Docker = require('dockerode');
Promise = require('bluebird');
connectOpts = generateConnectOpts(options);
connectOpts['Promise'] = Promise;
return new Docker(connectOpts);
return generateConnectOpts(options).then(function(connectOpts) {
connectOpts['Promise'] = Promise;
return new Docker(connectOpts);
});
};
hasQemu = function() {

View File

@ -175,64 +175,65 @@ module.exports =
logs = ''
upload = (token, username, url) ->
docker = dockerUtils.getDocker(options)
# Check input parameters
parseInput(params, options)
.then ([appName, build, source, imageName]) ->
tmpNameAsync()
.then (bufferFile) ->
dockerUtils.getDocker(options)
.then (docker) ->
# Check input parameters
parseInput(params, options)
.then ([appName, build, source, imageName]) ->
tmpNameAsync()
.then (bufferFile) ->
# Setup the build args for how the build routine expects them
options = _.assign({}, options, { appName })
params = _.assign({}, params, { source })
# Setup the build args for how the build routine expects them
options = _.assign({}, options, { appName })
params = _.assign({}, params, { source })
Promise.try ->
if build
dockerUtils.runBuild(params, options, getBundleInfo, logStreams)
else
{ image: imageName, log: '' }
.then ({ image: imageName, log: buildLogs }) ->
logging.logInfo(logStreams, 'Initializing deploy...')
logs = buildLogs
Promise.all [
dockerUtils.bufferImage(docker, imageName, bufferFile)
token
username
url
params.appName
logStreams
]
.spread(performUpload)
.finally ->
# If the file was never written to (for instance because an error
# has occured before any data was written) this call will throw an
# ugly error, just suppress it
Promise.try ->
require('mz/fs').unlink(bufferFile)
.catch(_.noop)
.tap ({ image: imageName, buildId }) ->
logging.logSuccess(logStreams, "Successfully deployed image: #{formatImageName(imageName)}")
return buildId
.then ({ image: imageName, buildId }) ->
if logs is '' or options.nologupload?
return ''
if build
dockerUtils.runBuild(params, options, getBundleInfo, logStreams)
else
{ image: imageName, log: '' }
.then ({ image: imageName, log: buildLogs }) ->
logging.logInfo(logStreams, 'Initializing deploy...')
logging.logInfo(logStreams, 'Uploading logs to dashboard...')
logs = buildLogs
Promise.all [
dockerUtils.bufferImage(docker, imageName, bufferFile)
token
username
url
params.appName
logStreams
]
.spread(performUpload)
.finally ->
# If the file was never written to (for instance because an error
# has occured before any data was written) this call will throw an
# ugly error, just suppress it
Promise.try ->
require('mz/fs').unlink(bufferFile)
.catch(_.noop)
.tap ({ image: imageName, buildId }) ->
logging.logSuccess(logStreams, "Successfully deployed image: #{formatImageName(imageName)}")
return buildId
.then ({ image: imageName, buildId }) ->
if logs is '' or options.nologupload?
return ''
Promise.join(
logs
token
url
buildId
username
params.appName
uploadLogs
)
.return('Successfully uploaded logs')
.then (msg) ->
logging.logSuccess(logStreams, msg) if msg isnt ''
.asCallback(done)
logging.logInfo(logStreams, 'Uploading logs to dashboard...')
Promise.join(
logs
token
url
buildId
username
params.appName
uploadLogs
)
.return('Successfully uploaded logs')
.then (msg) ->
logging.logSuccess(logStreams, msg) if msg isnt ''
.asCallback(done)
Promise.join(
resin.auth.getToken()

View File

@ -70,36 +70,47 @@ exports.appendOptions = (opts) ->
]
exports.generateConnectOpts = generateConnectOpts = (opts) ->
connectOpts = {}
# Firsly need to decide between a local docker socket
# and a host available over a host:port combo
if opts.docker? and not opts.dockerHost?
# good, local docker socket
connectOpts.socketPath = opts.docker
else if opts.dockerHost? and not opts.docker?
# Good a host is provided, and local socket isn't
connectOpts.host = opts.dockerHost
connectOpts.port = opts.dockerPort || 2376
else if opts.docker? and opts.dockerHost?
# Both provided, no obvious way to continue
throw new Error("Both a local docker socket and docker host have been provided. Don't know how to continue.")
else
# None provided, assume default docker local socket
connectOpts.socketPath = '/var/run/docker.sock'
Promise = require('bluebird')
fs = require('mz/fs')
_ = require('lodash')
# Now need to check if the user wants to connect over TLS
# to the host
Promise.try ->
connectOpts = {}
# Firsly need to decide between a local docker socket
# and a host available over a host:port combo
if opts.docker? and not opts.dockerHost?
# good, local docker socket
connectOpts.socketPath = opts.docker
else if opts.dockerHost? and not opts.docker?
# Good a host is provided, and local socket isn't
connectOpts.host = opts.dockerHost
connectOpts.port = opts.dockerPort || 2376
else if opts.docker? and opts.dockerHost?
# Both provided, no obvious way to continue
throw new Error("Both a local docker socket and docker host have been provided. Don't know how to continue.")
else
# None provided, assume default docker local socket
connectOpts.socketPath = '/var/run/docker.sock'
# If any are set...
if (opts.ca? or opts.cert? or opts.key?)
# but not all
if not (opts.ca? and opts.cert? and opts.key?)
throw new Error('You must provide a CA, certificate and key in order to use TLS')
connectOpts.ca = opts.ca
connectOpts.cert = opts.cert
connectOpts.key = opts.key
# Now need to check if the user wants to connect over TLS
# to the host
return connectOpts
# If any are set...
if (opts.ca? or opts.cert? or opts.key?)
# but not all
if not (opts.ca? and opts.cert? and opts.key?)
throw new Error('You must provide a CA, certificate and key in order to use TLS')
certBodies = {
ca: fs.readFile(opts.ca, 'utf-8')
cert: fs.readFile(opts.cert, 'utf-8')
key: fs.readFile(opts.key, 'utf-8')
}
return Promise.props(certBodies)
.then (toMerge) ->
_.merge(connectOpts, toMerge)
return connectOpts
exports.tarDirectory = tarDirectory = (dir) ->
Promise = require('bluebird')
@ -262,24 +273,25 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) ->
.pipe(logStreams.build)
# Create a builder
connectOpts = generateConnectOpts(options)
generateConnectOpts(options)
.then (connectOpts) ->
# Allow degugging output, hidden behind an env var
logging.logDebug(logStreams, 'Connecting with the following options:')
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '))
# Allow degugging output, hidden behind an env var
logging.logDebug(logStreams, 'Connecting with the following options:')
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '))
builder = new dockerBuild.Builder(connectOpts)
opts = {}
builder = new dockerBuild.Builder(connectOpts)
opts = {}
if options.tag?
opts['t'] = options.tag
if options.nocache?
opts['nocache'] = true
if options.buildArg?
opts['buildargs'] = parseBuildArgs options.buildArg, (arg) ->
logging.logWarn(logStreams, "Could not parse variable: '#{arg}'")
if options.tag?
opts['t'] = options.tag
if options.nocache?
opts['nocache'] = true
if options.buildArg?
opts['buildargs'] = parseBuildArgs options.buildArg, (arg) ->
logging.logWarn(logStreams, "Could not parse variable: '#{arg}'")
builder.createBuildStream(opts, hooks, reject)
builder.createBuildStream(opts, hooks, reject)
# Given an image id or tag, export the image to a tar archive,
# gzip the result, and buffer it to disk.
@ -298,10 +310,12 @@ exports.bufferImage = (docker, imageId, bufferFile) ->
exports.getDocker = (options) ->
Docker = require('dockerode')
Promise = require('bluebird')
connectOpts = generateConnectOpts(options)
# Use bluebird's promises
connectOpts['Promise'] = Promise
new Docker(connectOpts)
generateConnectOpts(options)
.then (connectOpts) ->
# Use bluebird's promises
connectOpts['Promise'] = Promise
new Docker(connectOpts)
hasQemu = ->
fs = require('mz/fs')