diff --git a/meteor/.jshintrc b/meteor/.jshintrc index 19c2e2f11c..300055089f 100755 --- a/meteor/.jshintrc +++ b/meteor/.jshintrc @@ -143,6 +143,8 @@ "docker": true, "async": true, "child_process": true, + "convert": true, + "Convert": true, // Collections "SimpleSchema": false, @@ -221,6 +223,7 @@ "saveImageFolderSync": true, "rebuildImageSync": true, "saveImageFolder": true, + "getFromImage": true, // Forms "showFormErrors": true, diff --git a/meteor/client/lib/sync.js b/meteor/client/lib/sync.js index 9cf3fe0e4b..cd2468ef2d 100644 --- a/meteor/client/lib/sync.js +++ b/meteor/client/lib/sync.js @@ -75,7 +75,7 @@ addAppWatcher = function (app) { exec(cmd, function () {}); } } catch (e) { - // console.error(e); + //console.error(e); } syncing = false; if (willSyncAgain) { diff --git a/meteor/lib/utilities.js b/meteor/lib/utilities.js index 12c03f9298..73aea70f5f 100644 --- a/meteor/lib/utilities.js +++ b/meteor/lib/utilities.js @@ -8,7 +8,11 @@ Util.getBinDir = function () { if (process.env.NODE_ENV === 'development') { return path.join(path.join(process.env.PWD, '..'), 'resources'); } else { - return path.join(process.cwd(), '../../../resources'); + if (Meteor.isClient) { + return path.join(process.cwd(), 'resources'); + } else { + return path.join(process.cwd(), '../../../resources'); + } } }; diff --git a/meteor/server/apps.js b/meteor/server/apps.js index a96174beeb..6cc531bc13 100755 --- a/meteor/server/apps.js +++ b/meteor/server/apps.js @@ -1,3 +1,71 @@ +deleteApp = function (app, callback) { + if (!app.docker) { + callback(null); + return; + } + try { + Docker.removeContainerSync(app.docker.Id); + } catch (e) { + console.error(e); + } + callback(null); +}; + +deleteAppSync = function (app) { + return Meteor._wrapAsync(deleteApp)(app); +}; + +restartApp = function (app, callback) { + if (app.docker && app.docker.Id) { + try { + Docker.restartContainerSync(app.docker.Id); + } catch (e) { + console.error(e); + } + var containerData = Docker.getContainerDataSync(app.docker.Id); + Fiber(function () { + Apps.update(app._id, {$set: { + status: 'READY', + docker: containerData + }}); + }).run(); + callback(null); + // Use dig to refresh the DNS + exec('/usr/bin/dig dig ' + app.name + '.dev @172.17.42.1 ', function() {}); + } else { + callback(null); + } +}; + +getAppLogs = function (app) { + if (app.docker && app.docker.Id) { + var container = docker.getContainer(app.docker.Id); + container.logs({follow: false, stdout: true, stderr: true, timestamps: true, tail: 300}, function (err, response) { + if (err) { throw err; } + Fiber(function () { + Apps.update(app._id, { + $set: { + logs: [] + } + }); + }).run(); + var logs = []; + response.setEncoding('utf8'); + response.on('data', function (line) { + logs.push(convert.toHtml(line.slice(8))); + Fiber(function () { + Apps.update(app._id, { + $set: { + logs: logs + } + }); + }).run(); + }); + response.on('end', function () {}); + }); + } +}; + removeBindFolder = function (name, callback) { exec(path.join(Util.getBinDir(), 'boot2docker') + ' ssh "sudo rm -rf /var/lib/docker/binds/' + name + '"', function(err, stdout) { callback(err, stdout); diff --git a/meteor/server/docker.js b/meteor/server/docker.js index 0e22efb2ff..447359cf2d 100755 --- a/meteor/server/docker.js +++ b/meteor/server/docker.js @@ -1,8 +1,5 @@ Dockerode = Meteor.require('dockerode'); -var Convert = Meteor.require('ansi-to-html'); -var convert = new Convert(); - var DOCKER_HOST='192.168.59.103'; docker = new Dockerode({host: '192.168.59.103', port: '2375'}); @@ -28,23 +25,6 @@ Docker.removeContainerSync = function (containerId) { return Meteor._wrapAsync(Docker.removeContainer)(containerId); }; -deleteApp = function (app, callback) { - if (!app.docker) { - callback(null); - return; - } - try { - Docker.removeContainerSync(app.docker.Id); - } catch (e) { - console.error(e); - } - callback(null); -}; - -deleteAppSync = function (app) { - return Meteor._wrapAsync(deleteApp)(app); -}; - Docker.getContainerData = function (containerId, callback) { var container = docker.getContainer(containerId); container.inspect(function (err, data) { @@ -123,68 +103,6 @@ Docker.restartContainerSync = function (containerId) { return Meteor._wrapAsync(Docker.restartContainer)(containerId); }; -var getFromImage = function (dockerfile) { - var patternString = "(FROM)(.*)"; - var regex = new RegExp(patternString, "g"); - var fromInstruction = dockerfile.match(regex); - if (fromInstruction && fromInstruction.length > 0) { - return fromInstruction[0].replace('FROM', '').trim(); - } else { - return null; - } -}; - -restartApp = function (app, callback) { - if (app.docker && app.docker.Id) { - try { - Docker.restartContainerSync(app.docker.Id); - } catch (e) { - console.error(e); - } - var containerData = Docker.getContainerDataSync(app.docker.Id); - Fiber(function () { - Apps.update(app._id, {$set: { - status: 'READY', - docker: containerData - }}); - }).run(); - callback(null); - // Use dig to refresh the DNS - exec('/usr/bin/dig dig ' + app.name + '.dev @172.17.42.1 ', function() {}); - } else { - callback(null); - } -}; - -getAppLogs = function (app) { - if (app.docker && app.docker.Id) { - var container = docker.getContainer(app.docker.Id); - container.logs({follow: false, stdout: true, stderr: true, timestamps: true, tail: 300}, function (err, response) { - if (err) { throw err; } - Fiber(function () { - Apps.update(app._id, { - $set: { - logs: [] - } - }); - }).run(); - var logs = []; - response.setEncoding('utf8'); - response.on('data', function (line) { - logs.push(convert.toHtml(line.slice(8))); - Fiber(function () { - Apps.update(app._id, { - $set: { - logs: logs - } - }); - }).run(); - }); - response.on('end', function () {}); - }); - } -}; - createTarFile = function (image, callback) { var TAR_PATH = path.join(KITE_TAR_PATH, image._id + '.tar'); exec('tar czf ' + TAR_PATH + ' -C ' + image.path + ' .', function (err) { @@ -243,23 +161,6 @@ Docker.removeImageSync = function (imageId) { return Meteor._wrapAsync(Docker.removeImage)(imageId); }; -deleteImage = function (image, callback) { - if (!image.docker) { - callback(null, {}); - return; - } - try { - Docker.removeImageSync(image.docker.Id); - } catch (e) { - console.error(e); - } - callback(null); -}; - -deleteImageSync = function (image) { - return Meteor._wrapAsync(deleteImage)(image); -}; - var defaultContainerOptions = function () { return [ { @@ -502,132 +403,6 @@ killAndRemoveContainers = function (names, callback) { }); }; -pullImageFromDockerfile = function (dockerfile, imageId, callback) { - var fromImage = getFromImage(dockerfile); - console.log('From image: ' + fromImage); - var installedImage = null; - try { - installedImage = Docker.getImageDataSync(fromImage); - } catch (e) { - console.error(e); - } - if (fromImage && !installedImage) { - Fiber(function () { - Images.update(imageId, { - $set: { - buildLogs: [] - } - }); - }).run(); - var logs = []; - docker.pull(fromImage, function (err, response) { - if (err) { callback(err); return; } - response.setEncoding('utf8'); - response.on('data', function (data) { - try { - var logData = JSON.parse(data); - var logDisplay = ''; - if (logData.id) { - logDisplay += logData.id + ' | '; - } - logDisplay += logData.status; - if (logData.progressDetail && logData.progressDetail.current && logData.progressDetail.total) { - logDisplay += ' - ' + Math.round(logData.progressDetail.current / logData.progressDetail.total * 100) + '%'; - } - logs.push(logDisplay); - Fiber(function () { - Images.update(imageId, { - $set: { - buildLogs: logs - } - }); - }).run(); - } catch (e) { - console.error(e); - } - }); - response.on('end', function () { - console.log('Finished pulling image: ' + fromImage); - callback(null); - }); - }); - } else { - callback(null); - } -}; - -buildImage = function (image, callback) { - Fiber(function () { - var tarFilePath = createTarFileSync(image); - Images.update(image._id, { - $set: { - buildLogs: [] - } - }); - docker.buildImage(tarFilePath, {t: image._id.toLowerCase()}, function (err, response) { - if (err) { callback(err); } - console.log('Building Docker image...'); - var logs = []; - response.setEncoding('utf8'); - response.on('data', function (data) { - try { - var line = JSON.parse(data).stream; - logs.push(convert.toHtml(line)); - Fiber(function () { - Images.update(image._id, { - $set: { - buildLogs: logs - } - }); - }).run(); - } catch (e) { - console.error(e); - } - }); - response.on('end', function () { - console.log('Finished building Docker image.'); - try { - fs.unlinkSync(tarFilePath); - console.log('Cleaned up tar file.'); - } catch (e) { - console.error(e); - } - Fiber(function () { - var imageData = null; - try { - imageData = Docker.getImageDataSync(image._id); - Images.update(image._id, { - $set: { - docker: imageData, - status: 'READY' - } - }); - } catch (e) { - console.log(e); - Images.update(image._id, { - $set: { - status: 'ERROR' - } - }); - } - var oldImageId = null; - if (image.docker && image.docker.Id) { - oldImageId = image.docker.Id; - } - if (oldImageId && imageData && oldImageId !== imageData.Id) { - try { - Docker.removeImageSync(oldImageId); - } catch (e) { - console.error(e); - } - } - }).run(); - callback(null); - }); - }); - }).run(); -}; - Meteor.methods({ runApp: function (app) { this.unblock(); diff --git a/meteor/server/images.js b/meteor/server/images.js index d8985a8384..a2c91c538b 100755 --- a/meteor/server/images.js +++ b/meteor/server/images.js @@ -1,3 +1,14 @@ +getFromImage = function (dockerfile) { + var patternString = "(FROM)(.*)"; + var regex = new RegExp(patternString, "g"); + var fromInstruction = dockerfile.match(regex); + if (fromInstruction && fromInstruction.length > 0) { + return fromInstruction[0].replace('FROM', '').trim(); + } else { + return null; + } +}; + getImageJSON = function (directory) { var KITE_JSON_PATH = path.join(directory, 'image.json'); if (fs.existsSync(KITE_JSON_PATH)) { @@ -38,6 +49,23 @@ getImageMetaData = function (directory) { return kiteJSON; }; +deleteImage = function (image, callback) { + if (!image.docker) { + callback(null, {}); + return; + } + try { + Docker.removeImageSync(image.docker.Id); + } catch (e) { + console.error(e); + } + callback(null); +}; + +deleteImageSync = function (image) { + return Meteor._wrapAsync(deleteImage)(image); +}; + rebuildImage = function (image, callback) { Util.deleteFolder(image.path); var imageMetaData = getImageMetaData(image.originPath); @@ -75,6 +103,132 @@ rebuildImageSync = function (image) { return Meteor._wrapAsync(rebuildImage)(image); }; +pullImageFromDockerfile = function (dockerfile, imageId, callback) { + var fromImage = getFromImage(dockerfile); + console.log('From image: ' + fromImage); + var installedImage = null; + try { + installedImage = Docker.getImageDataSync(fromImage); + } catch (e) { + console.error(e); + } + if (fromImage && !installedImage) { + Fiber(function () { + Images.update(imageId, { + $set: { + buildLogs: [] + } + }); + }).run(); + var logs = []; + docker.pull(fromImage, function (err, response) { + if (err) { callback(err); return; } + response.setEncoding('utf8'); + response.on('data', function (data) { + try { + var logData = JSON.parse(data); + var logDisplay = ''; + if (logData.id) { + logDisplay += logData.id + ' | '; + } + logDisplay += logData.status; + if (logData.progressDetail && logData.progressDetail.current && logData.progressDetail.total) { + logDisplay += ' - ' + Math.round(logData.progressDetail.current / logData.progressDetail.total * 100) + '%'; + } + logs.push(logDisplay); + Fiber(function () { + Images.update(imageId, { + $set: { + buildLogs: logs + } + }); + }).run(); + } catch (e) { + console.error(e); + } + }); + response.on('end', function () { + console.log('Finished pulling image: ' + fromImage); + callback(null); + }); + }); + } else { + callback(null); + } +}; + +buildImage = function (image, callback) { + Fiber(function () { + var tarFilePath = createTarFileSync(image); + Images.update(image._id, { + $set: { + buildLogs: [] + } + }); + docker.buildImage(tarFilePath, {t: image._id.toLowerCase()}, function (err, response) { + if (err) { callback(err); } + console.log('Building Docker image...'); + var logs = []; + response.setEncoding('utf8'); + response.on('data', function (data) { + try { + var line = JSON.parse(data).stream; + logs.push(convert.toHtml(line)); + Fiber(function () { + Images.update(image._id, { + $set: { + buildLogs: logs + } + }); + }).run(); + } catch (e) { + console.error(e); + } + }); + response.on('end', function () { + console.log('Finished building Docker image.'); + try { + fs.unlinkSync(tarFilePath); + console.log('Cleaned up tar file.'); + } catch (e) { + console.error(e); + } + Fiber(function () { + var imageData = null; + try { + imageData = Docker.getImageDataSync(image._id); + Images.update(image._id, { + $set: { + docker: imageData, + status: 'READY' + } + }); + } catch (e) { + console.log(e); + Images.update(image._id, { + $set: { + status: 'ERROR' + } + }); + } + var oldImageId = null; + if (image.docker && image.docker.Id) { + oldImageId = image.docker.Id; + } + if (oldImageId && imageData && oldImageId !== imageData.Id) { + try { + Docker.removeImageSync(oldImageId); + } catch (e) { + console.error(e); + } + } + }).run(); + callback(null); + }); + }); + }).run(); +}; + Meteor.methods({ createImage: function (directory) { this.unblock(); diff --git a/meteor/server/lib/requires.js b/meteor/server/lib/requires.js index cac98d255a..6174cd0202 100755 --- a/meteor/server/lib/requires.js +++ b/meteor/server/lib/requires.js @@ -6,4 +6,6 @@ path = Meteor.require('path'); exec = Meteor.require('child_process').exec; async = Meteor.require('async'); Fiber = Meteor.require('fibers'); -child_process = Meteor.require('child_process'); \ No newline at end of file +child_process = Meteor.require('child_process'); +Convert = Meteor.require('ansi-to-html'); +convert = new Convert();