balena-cli/build/actions/deploy.js
Cameron Diver d3772386bf
Add ability to build and deploy image locally using resin-cli
Using `resin build` a user can now build an image on their own docker
daemon. The daemon can be accessed via a local socket, a remote host and
a remote host over a TLS socket. Project type resolution is supported.
Nocache and tagging of images is also supported.

Using `resin deploy` a user can now deploy an image to their fleet. The
image can either be built by `resin-cli`, plain Docker, or from a remote
source.

Change-type: minor
Signed-off-by: Cameron Diver <cameron@resin.io>
2017-04-23 14:31:45 +01:00

167 lines
5.5 KiB
JavaScript

// Generated by CoffeeScript 1.12.5
var Promise, formatImageName, getBuilderPushEndpoint, getBundleInfo, parseInput, performUpload, pushProgress, uploadToPromise;
Promise = require('bluebird');
getBuilderPushEndpoint = function(baseUrl, owner, app) {
var escApp, escOwner;
escOwner = encodeURIComponent(owner);
escApp = encodeURIComponent(app);
return "https://builder." + baseUrl + "/v1/push?owner=" + escOwner + "&app=" + escApp;
};
formatImageName = function(image) {
return image.split('/').pop();
};
parseInput = Promise.method(function(params, options) {
var appName, context, image;
if (params.appName == null) {
throw new Error('Need an application to deploy to!');
}
appName = params.appName;
image = void 0;
if (params.image != null) {
if (options.build || (options.source != null)) {
throw new Error('Build and source parameters are not applicable when specifying an image');
}
options.build = false;
image = params.image;
} else if (options.build) {
context = options.source || '.';
} else {
throw new Error('Need either an image or a build flag!');
}
return [appName, options.build, context, image];
});
pushProgress = function(imageSize, request, timeout) {
var progressReporter;
if (timeout == null) {
timeout = 250;
}
process.stdout.write('Initialising...');
return progressReporter = setInterval(function() {
var percent, sent;
sent = request.req.connection._bytesDispatched;
percent = (sent / imageSize) * 100;
if (percent >= 100) {
clearInterval(progressReporter);
percent = 100;
}
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write("Uploaded " + (percent.toFixed(1)) + "%");
if (percent === 100) {
return console.log();
}
}, timeout);
};
getBundleInfo = function(options) {
var helpers;
helpers = require('../utils/helpers');
return helpers.getAppInfo(options.appName).then(function(app) {
return [app.arch, app.device_type];
});
};
performUpload = function(image, token, username, url, size, appName) {
var post, request;
request = require('request');
url = url || process.env.RESINRC_RESIN_URL;
post = request.post({
url: getBuilderPushEndpoint(url, username, appName),
auth: {
bearer: token
},
body: image
});
return uploadToPromise(post, size);
};
uploadToPromise = function(request, size) {
return new Promise(function(resolve, reject) {
var handleMessage;
handleMessage = function(data) {
var obj;
data = data.toString();
if (process.env.DEBUG) {
console.log("Received data: " + data);
}
obj = JSON.parse(data);
if (obj.type != null) {
switch (obj.type) {
case 'error':
return reject(new Error("Remote error: " + obj.error));
case 'success':
return resolve(obj.image);
case 'status':
return console.log("Remote: " + obj.message);
default:
return reject(new Error("Received unexpected reply from remote: " + data));
}
} else {
return reject(new Error("Received unexpected reply from remote: " + data));
}
};
request.on('error', reject).on('data', handleMessage);
return pushProgress(size, request);
});
};
module.exports = {
signature: 'deploy <appName> [image]',
description: 'Deploy a container to a resin.io application',
help: 'Use this command to deploy and optionally build an image to an application.\n\nUsage: deploy <appName> ([image] | --build [--source build-dir])\n\nNote: If building with this command, all options supported by `resin build`\nare also support with this command.\n\nExamples:\n$ resin deploy myApp --build --source myBuildDir/\n$ resin deploy myApp myApp/myImage',
permission: 'user',
options: [
{
signature: 'build',
boolean: true,
description: 'Build image then deploy',
alias: 'b'
}, {
signature: 'source',
parameter: 'source',
description: 'The source directory to use when building the image',
alias: 's'
}
],
action: function(params, options, done) {
var _, docker, dockerUtils, resin, tmp, tmpNameAsync;
_ = require('lodash');
tmp = require('tmp');
tmpNameAsync = Promise.promisify(tmp.tmpName);
resin = require('resin-sdk-preconfigured');
dockerUtils = require('../utils/docker');
tmp.setGracefulCleanup();
docker = dockerUtils.getDocker(options);
return parseInput(params, options).then(function(arg) {
var appName, build, context, imageName;
appName = arg[0], build = arg[1], context = arg[2], imageName = arg[3];
return tmpNameAsync().then(function(tmpPath) {
options = _.assign({}, options, {
appName: appName
});
params = _.assign({}, params, {
context: context
});
return Promise["try"](function() {
if (build) {
return dockerUtils.runBuild(params, options, getBundleInfo);
} else {
return imageName;
}
}).then(function(imageName) {
return Promise.join(dockerUtils.bufferImage(docker, imageName, tmpPath), resin.auth.getToken(), resin.auth.whoami(), resin.settings.get('resinUrl'), dockerUtils.getImageSize(docker, imageName), params.appName, performUpload);
})["finally"](function() {
return require('fs').unlink(tmpPath);
});
});
}).then(function(imageName) {
return console.log("Successfully deployed image: " + (formatImageName(imageName)));
}).asCallback(done);
}
};