mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-02-22 18:12:54 +00:00
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:
parent
378f894da3
commit
5000febf72
@ -3,6 +3,10 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
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
|
## [5.11.0] - 2017-06-19
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -202,57 +202,57 @@ module.exports = {
|
|||||||
tmp.setGracefulCleanup();
|
tmp.setGracefulCleanup();
|
||||||
logs = '';
|
logs = '';
|
||||||
upload = function(token, username, url) {
|
upload = function(token, username, url) {
|
||||||
var docker;
|
return dockerUtils.getDocker(options).then(function(docker) {
|
||||||
docker = dockerUtils.getDocker(options);
|
return parseInput(params, options).then(function(arg) {
|
||||||
return parseInput(params, options).then(function(arg) {
|
var appName, build, imageName, source;
|
||||||
var appName, build, imageName, source;
|
appName = arg[0], build = arg[1], source = arg[2], imageName = arg[3];
|
||||||
appName = arg[0], build = arg[1], source = arg[2], imageName = arg[3];
|
return tmpNameAsync().then(function(bufferFile) {
|
||||||
return tmpNameAsync().then(function(bufferFile) {
|
options = _.assign({}, options, {
|
||||||
options = _.assign({}, options, {
|
appName: appName
|
||||||
appName: appName
|
});
|
||||||
});
|
params = _.assign({}, params, {
|
||||||
params = _.assign({}, params, {
|
source: source
|
||||||
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 Promise["try"](function() {
|
return Promise["try"](function() {
|
||||||
return require('mz/fs').unlink(bufferFile);
|
if (build) {
|
||||||
})["catch"](_.noop);
|
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) {
|
||||||
}).tap(function(arg) {
|
var buildId, imageName;
|
||||||
var buildId, imageName;
|
imageName = arg.image, buildId = arg.buildId;
|
||||||
imageName = arg.image, buildId = arg.buildId;
|
logging.logSuccess(logStreams, "Successfully deployed image: " + (formatImageName(imageName)));
|
||||||
logging.logSuccess(logStreams, "Successfully deployed image: " + (formatImageName(imageName)));
|
return buildId;
|
||||||
return buildId;
|
}).then(function(arg) {
|
||||||
}).then(function(arg) {
|
var buildId, imageName;
|
||||||
var buildId, imageName;
|
imageName = arg.image, buildId = arg.buildId;
|
||||||
imageName = arg.image, buildId = arg.buildId;
|
if (logs === '' || (options.nologupload != null)) {
|
||||||
if (logs === '' || (options.nologupload != null)) {
|
return '';
|
||||||
return '';
|
}
|
||||||
}
|
logging.logInfo(logStreams, 'Uploading logs to dashboard...');
|
||||||
logging.logInfo(logStreams, 'Uploading logs to dashboard...');
|
return Promise.join(logs, token, url, buildId, username, params.appName, uploadLogs)["return"]('Successfully uploaded logs');
|
||||||
return Promise.join(logs, token, url, buildId, username, params.appName, uploadLogs)["return"]('Successfully uploaded logs');
|
}).then(function(msg) {
|
||||||
}).then(function(msg) {
|
if (msg !== '') {
|
||||||
if (msg !== '') {
|
return logging.logSuccess(logStreams, msg);
|
||||||
return logging.logSuccess(logStreams, msg);
|
}
|
||||||
}
|
}).asCallback(done);
|
||||||
}).asCallback(done);
|
});
|
||||||
};
|
};
|
||||||
return Promise.join(resin.auth.getToken(), resin.auth.whoami(), resin.settings.get('resinUrl'), upload);
|
return Promise.join(resin.auth.getToken(), resin.auth.whoami(), resin.settings.get('resinUrl'), upload);
|
||||||
}
|
}
|
||||||
|
@ -58,27 +58,35 @@ exports.appendOptions = function(opts) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.generateConnectOpts = generateConnectOpts = function(opts) {
|
exports.generateConnectOpts = generateConnectOpts = function(opts) {
|
||||||
var connectOpts;
|
var Promise, fs;
|
||||||
connectOpts = {};
|
Promise = require('bluebird');
|
||||||
if ((opts.docker != null) && (opts.dockerHost == null)) {
|
fs = require('mz/fs');
|
||||||
connectOpts.socketPath = opts.docker;
|
return Promise["try"](function() {
|
||||||
} else if ((opts.dockerHost != null) && (opts.docker == null)) {
|
var connectOpts;
|
||||||
connectOpts.host = opts.dockerHost;
|
connectOpts = {};
|
||||||
connectOpts.port = opts.dockerPort || 2376;
|
if ((opts.docker != null) && (opts.dockerHost == null)) {
|
||||||
} else if ((opts.docker != null) && (opts.dockerHost != null)) {
|
connectOpts.socketPath = opts.docker;
|
||||||
throw new Error("Both a local docker socket and docker host have been provided. Don't know how to continue.");
|
} else if ((opts.dockerHost != null) && (opts.docker == null)) {
|
||||||
} else {
|
connectOpts.host = opts.dockerHost;
|
||||||
connectOpts.socketPath = '/var/run/docker.sock';
|
connectOpts.port = opts.dockerPort || 2376;
|
||||||
}
|
} else if ((opts.docker != null) && (opts.dockerHost != null)) {
|
||||||
if ((opts.ca != null) || (opts.cert != null) || (opts.key != null)) {
|
throw new Error("Both a local docker socket and docker host have been provided. Don't know how to continue.");
|
||||||
if (!((opts.ca != null) && (opts.cert != null) && (opts.key != null))) {
|
} else {
|
||||||
throw new Error('You must provide a CA, certificate and key in order to use TLS');
|
connectOpts.socketPath = '/var/run/docker.sock';
|
||||||
}
|
}
|
||||||
connectOpts.ca = opts.ca;
|
if ((opts.ca != null) || (opts.cert != null) || (opts.key != null)) {
|
||||||
connectOpts.cert = opts.cert;
|
if (!((opts.ca != null) && (opts.cert != null) && (opts.key != null))) {
|
||||||
connectOpts.key = opts.key;
|
throw new Error('You must provide a CA, certificate and key in order to use TLS');
|
||||||
}
|
}
|
||||||
return connectOpts;
|
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) {
|
exports.tarDirectory = tarDirectory = function(dir) {
|
||||||
@ -189,7 +197,7 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) {
|
|||||||
return tarDirectory(params.source);
|
return tarDirectory(params.source);
|
||||||
}).then(function(tarStream) {
|
}).then(function(tarStream) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
var builder, connectOpts, hooks, opts;
|
var hooks;
|
||||||
hooks = {
|
hooks = {
|
||||||
buildSuccess: function(image) {
|
buildSuccess: function(image) {
|
||||||
var doodle;
|
var doodle;
|
||||||
@ -252,23 +260,25 @@ exports.runBuild = function(params, options, getBundleInfo, logStreams) {
|
|||||||
return newStream.pipe(logThroughStream).pipe(cacheHighlightStream()).pipe(logStreams.build);
|
return newStream.pipe(logThroughStream).pipe(cacheHighlightStream()).pipe(logStreams.build);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
connectOpts = generateConnectOpts(options);
|
return generateConnectOpts(options).then(function(connectOpts) {
|
||||||
logging.logDebug(logStreams, 'Connecting with the following options:');
|
var builder, opts;
|
||||||
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '));
|
logging.logDebug(logStreams, 'Connecting with the following options:');
|
||||||
builder = new dockerBuild.Builder(connectOpts);
|
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '));
|
||||||
opts = {};
|
builder = new dockerBuild.Builder(connectOpts);
|
||||||
if (options.tag != null) {
|
opts = {};
|
||||||
opts['t'] = options.tag;
|
if (options.tag != null) {
|
||||||
}
|
opts['t'] = options.tag;
|
||||||
if (options.nocache != null) {
|
}
|
||||||
opts['nocache'] = true;
|
if (options.nocache != null) {
|
||||||
}
|
opts['nocache'] = true;
|
||||||
if (options.buildArg != null) {
|
}
|
||||||
opts['buildargs'] = parseBuildArgs(options.buildArg, function(arg) {
|
if (options.buildArg != null) {
|
||||||
return logging.logWarn(logStreams, "Could not parse variable: '" + arg + "'");
|
opts['buildargs'] = parseBuildArgs(options.buildArg, function(arg) {
|
||||||
});
|
return logging.logWarn(logStreams, "Could not parse variable: '" + arg + "'");
|
||||||
}
|
});
|
||||||
return builder.createBuildStream(opts, hooks, reject);
|
}
|
||||||
|
return builder.createBuildStream(opts, hooks, reject);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -287,12 +297,13 @@ exports.bufferImage = function(docker, imageId, bufferFile) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.getDocker = function(options) {
|
exports.getDocker = function(options) {
|
||||||
var Docker, Promise, connectOpts;
|
var Docker, Promise;
|
||||||
Docker = require('dockerode');
|
Docker = require('dockerode');
|
||||||
Promise = require('bluebird');
|
Promise = require('bluebird');
|
||||||
connectOpts = generateConnectOpts(options);
|
return generateConnectOpts(options).then(function(connectOpts) {
|
||||||
connectOpts['Promise'] = Promise;
|
connectOpts['Promise'] = Promise;
|
||||||
return new Docker(connectOpts);
|
return new Docker(connectOpts);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
hasQemu = function() {
|
hasQemu = function() {
|
||||||
|
@ -175,64 +175,65 @@ module.exports =
|
|||||||
logs = ''
|
logs = ''
|
||||||
|
|
||||||
upload = (token, username, url) ->
|
upload = (token, username, url) ->
|
||||||
docker = dockerUtils.getDocker(options)
|
dockerUtils.getDocker(options)
|
||||||
# Check input parameters
|
.then (docker) ->
|
||||||
parseInput(params, options)
|
# Check input parameters
|
||||||
.then ([appName, build, source, imageName]) ->
|
parseInput(params, options)
|
||||||
tmpNameAsync()
|
.then ([appName, build, source, imageName]) ->
|
||||||
.then (bufferFile) ->
|
tmpNameAsync()
|
||||||
|
.then (bufferFile) ->
|
||||||
|
|
||||||
# Setup the build args for how the build routine expects them
|
# Setup the build args for how the build routine expects them
|
||||||
options = _.assign({}, options, { appName })
|
options = _.assign({}, options, { appName })
|
||||||
params = _.assign({}, params, { source })
|
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 ->
|
Promise.try ->
|
||||||
require('mz/fs').unlink(bufferFile)
|
if build
|
||||||
.catch(_.noop)
|
dockerUtils.runBuild(params, options, getBundleInfo, logStreams)
|
||||||
.tap ({ image: imageName, buildId }) ->
|
else
|
||||||
logging.logSuccess(logStreams, "Successfully deployed image: #{formatImageName(imageName)}")
|
{ image: imageName, log: '' }
|
||||||
return buildId
|
.then ({ image: imageName, log: buildLogs }) ->
|
||||||
.then ({ image: imageName, buildId }) ->
|
logging.logInfo(logStreams, 'Initializing deploy...')
|
||||||
if logs is '' or options.nologupload?
|
|
||||||
return ''
|
|
||||||
|
|
||||||
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(
|
logging.logInfo(logStreams, 'Uploading logs to dashboard...')
|
||||||
logs
|
|
||||||
token
|
Promise.join(
|
||||||
url
|
logs
|
||||||
buildId
|
token
|
||||||
username
|
url
|
||||||
params.appName
|
buildId
|
||||||
uploadLogs
|
username
|
||||||
)
|
params.appName
|
||||||
.return('Successfully uploaded logs')
|
uploadLogs
|
||||||
.then (msg) ->
|
)
|
||||||
logging.logSuccess(logStreams, msg) if msg isnt ''
|
.return('Successfully uploaded logs')
|
||||||
.asCallback(done)
|
.then (msg) ->
|
||||||
|
logging.logSuccess(logStreams, msg) if msg isnt ''
|
||||||
|
.asCallback(done)
|
||||||
|
|
||||||
Promise.join(
|
Promise.join(
|
||||||
resin.auth.getToken()
|
resin.auth.getToken()
|
||||||
|
@ -70,36 +70,47 @@ exports.appendOptions = (opts) ->
|
|||||||
]
|
]
|
||||||
|
|
||||||
exports.generateConnectOpts = generateConnectOpts = (opts) ->
|
exports.generateConnectOpts = generateConnectOpts = (opts) ->
|
||||||
connectOpts = {}
|
Promise = require('bluebird')
|
||||||
# Firsly need to decide between a local docker socket
|
fs = require('mz/fs')
|
||||||
# and a host available over a host:port combo
|
_ = require('lodash')
|
||||||
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'
|
|
||||||
|
|
||||||
# Now need to check if the user wants to connect over TLS
|
Promise.try ->
|
||||||
# to the host
|
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...
|
# Now need to check if the user wants to connect over TLS
|
||||||
if (opts.ca? or opts.cert? or opts.key?)
|
# to the host
|
||||||
# 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
|
|
||||||
|
|
||||||
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) ->
|
exports.tarDirectory = tarDirectory = (dir) ->
|
||||||
Promise = require('bluebird')
|
Promise = require('bluebird')
|
||||||
@ -262,24 +273,25 @@ exports.runBuild = (params, options, getBundleInfo, logStreams) ->
|
|||||||
.pipe(logStreams.build)
|
.pipe(logStreams.build)
|
||||||
|
|
||||||
# Create a builder
|
# Create a builder
|
||||||
connectOpts = generateConnectOpts(options)
|
generateConnectOpts(options)
|
||||||
|
.then (connectOpts) ->
|
||||||
|
|
||||||
# Allow degugging output, hidden behind an env var
|
# Allow degugging output, hidden behind an env var
|
||||||
logging.logDebug(logStreams, 'Connecting with the following options:')
|
logging.logDebug(logStreams, 'Connecting with the following options:')
|
||||||
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '))
|
logging.logDebug(logStreams, JSON.stringify(connectOpts, null, ' '))
|
||||||
|
|
||||||
builder = new dockerBuild.Builder(connectOpts)
|
builder = new dockerBuild.Builder(connectOpts)
|
||||||
opts = {}
|
opts = {}
|
||||||
|
|
||||||
if options.tag?
|
if options.tag?
|
||||||
opts['t'] = options.tag
|
opts['t'] = options.tag
|
||||||
if options.nocache?
|
if options.nocache?
|
||||||
opts['nocache'] = true
|
opts['nocache'] = true
|
||||||
if options.buildArg?
|
if options.buildArg?
|
||||||
opts['buildargs'] = parseBuildArgs options.buildArg, (arg) ->
|
opts['buildargs'] = parseBuildArgs options.buildArg, (arg) ->
|
||||||
logging.logWarn(logStreams, "Could not parse variable: '#{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,
|
# Given an image id or tag, export the image to a tar archive,
|
||||||
# gzip the result, and buffer it to disk.
|
# gzip the result, and buffer it to disk.
|
||||||
@ -298,10 +310,12 @@ exports.bufferImage = (docker, imageId, bufferFile) ->
|
|||||||
exports.getDocker = (options) ->
|
exports.getDocker = (options) ->
|
||||||
Docker = require('dockerode')
|
Docker = require('dockerode')
|
||||||
Promise = require('bluebird')
|
Promise = require('bluebird')
|
||||||
connectOpts = generateConnectOpts(options)
|
|
||||||
# Use bluebird's promises
|
generateConnectOpts(options)
|
||||||
connectOpts['Promise'] = Promise
|
.then (connectOpts) ->
|
||||||
new Docker(connectOpts)
|
# Use bluebird's promises
|
||||||
|
connectOpts['Promise'] = Promise
|
||||||
|
new Docker(connectOpts)
|
||||||
|
|
||||||
hasQemu = ->
|
hasQemu = ->
|
||||||
fs = require('mz/fs')
|
fs = require('mz/fs')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user