mirror of https://github.com/docker/docs.git
Fixing outstanding installer & port mapping bugs
This commit is contained in:
parent
d1c6928321
commit
0357ce7b0e
5
index.js
5
index.js
|
@ -124,7 +124,10 @@ app.on('ready', function() {
|
|||
width: 800,
|
||||
height: 578,
|
||||
resizable: false,
|
||||
frame: false
|
||||
frame: false,
|
||||
'web-preferences': {
|
||||
'web-security': false
|
||||
}
|
||||
};
|
||||
mainWindow = new BrowserWindow(windowOptions);
|
||||
mainWindow.hide();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var exec = require('exec');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
var Convert = require('ansi-to-html');
|
||||
var convert = new Convert();
|
||||
|
||||
|
@ -8,9 +9,10 @@ AppUtil = {};
|
|||
|
||||
AppUtil.run = function (app, callback) {
|
||||
var image = Images.findOne({_id: app.imageId});
|
||||
// Delete old container if one already exists
|
||||
Apps.update(app._id, {$set: {
|
||||
status: 'STARTING'
|
||||
}});
|
||||
Docker.removeContainer(app.name, function (err) {
|
||||
if (err) { callback(err); }
|
||||
Docker.runContainer(app, image, function (err, container) {
|
||||
if (err) { callback(err); }
|
||||
Docker.getContainerData(container.id, function (err, data) {
|
||||
|
@ -26,22 +28,6 @@ AppUtil.run = function (app, callback) {
|
|||
});
|
||||
};
|
||||
|
||||
AppUtil.restartHelper = function (app) {
|
||||
if (app.docker && app.docker.Id) {
|
||||
var container = Docker.client().getContainer(app.docker.Id);
|
||||
container.restart(function (err) {
|
||||
if (err) { console.error(err); }
|
||||
Docker.getContainerData(app.docker.Id, function (err, data) {
|
||||
if (err) { console.error(err); }
|
||||
Apps.update(app._id, {$set: {
|
||||
status: 'READY',
|
||||
docker: data
|
||||
}});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
AppUtil.start = function (appId) {
|
||||
var app = Apps.findOne(appId);
|
||||
if (app && app.docker) {
|
||||
|
@ -78,16 +64,6 @@ AppUtil.stop = function (appId) {
|
|||
}
|
||||
};
|
||||
|
||||
AppUtil.restart = function (appId) {
|
||||
var app = Apps.findOne(appId);
|
||||
if (app && app.docker) {
|
||||
Apps.update(app._id, {$set: {
|
||||
status: 'STARTING'
|
||||
}});
|
||||
AppUtil.restartHelper(app);
|
||||
}
|
||||
};
|
||||
|
||||
AppUtil.remove = function (appId) {
|
||||
var app = Apps.findOne(appId);
|
||||
Apps.remove({_id: appId});
|
||||
|
@ -153,35 +129,14 @@ AppUtil.recover = function () {
|
|||
});
|
||||
};
|
||||
|
||||
AppUtil.sync = function () {
|
||||
AppUtil.sync = function (callback) {
|
||||
Docker.listContainers(function (err, containers) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var apps = Apps.find({}).fetch();
|
||||
_.each(apps, function (app) {
|
||||
var app = Apps.findOne(app._id);
|
||||
if (app && app.docker && app.docker.Id) {
|
||||
var duplicateApps = Apps.find({'docker.Id': app.docker.Id, _id: {$ne: app._id}}).fetch();
|
||||
_.each(duplicateApps, function (duplicateApp) {
|
||||
Apps.remove(duplicateApp._id);
|
||||
});
|
||||
Docker.getContainerData(app.docker.Id, function (err, data) {
|
||||
var status = 'STARTING';
|
||||
if (data && data.State && data.State.Running) {
|
||||
status = 'READY';
|
||||
} else if (data && data.State && !data.State.Running) {
|
||||
status = 'ERROR';
|
||||
}
|
||||
Apps.update(app._id, {
|
||||
$set: {
|
||||
docker: data,
|
||||
status: status
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
var dockerIds = _.map(apps, function (app) {
|
||||
if (app.docker && app.docker.Id) {
|
||||
return app.docker.Id;
|
||||
|
@ -235,12 +190,42 @@ AppUtil.sync = function () {
|
|||
path: appPath,
|
||||
logs: [],
|
||||
createdAt: new Date(),
|
||||
volumesEnabled: true
|
||||
};
|
||||
if (container.HostConfig.Binds && container.HostConfig.Binds.length) {
|
||||
appObj.volumesEnabled = true;
|
||||
} else {
|
||||
appObj.volumesEnabled = false;
|
||||
}
|
||||
console.log(appObj);
|
||||
Apps.insert(appObj);
|
||||
}
|
||||
});
|
||||
|
||||
async.each(apps, function (app, callback) {
|
||||
if (app && app.docker && app.docker.Id) {
|
||||
var duplicateApps = Apps.find({'docker.Id': app.docker.Id, _id: {$ne: app._id}}).fetch();
|
||||
_.each(duplicateApps, function (duplicateApp) {
|
||||
Apps.remove(duplicateApp._id);
|
||||
});
|
||||
Docker.getContainerData(app.docker.Id, function (err, data) {
|
||||
if (err) {callback(err); return;}
|
||||
var status = 'STARTING';
|
||||
if (data && data.State && data.State.Running) {
|
||||
status = 'READY';
|
||||
} else if (data && data.State && !data.State.Running) {
|
||||
status = 'ERROR';
|
||||
}
|
||||
Apps.update(app._id, {
|
||||
$set: {
|
||||
docker: data,
|
||||
status: status
|
||||
}
|
||||
});
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}, function (err) {
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -2,11 +2,12 @@ var exec = require('exec');
|
|||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var async = require('async');
|
||||
var pkginfo = require('pkginfo')(module);
|
||||
|
||||
|
||||
Boot2Docker = {};
|
||||
|
||||
Boot2Docker.REQUIRED_IP = '192.168.60.103';
|
||||
Boot2Docker.VERSION = '1.3.1';
|
||||
Boot2Docker.VERSION = module.exports['boot2docker-version'];
|
||||
|
||||
Boot2Docker.command = function () {
|
||||
return path.join(Util.getBinDir(), 'boot2docker-' + Boot2Docker.VERSION);
|
||||
|
@ -252,7 +253,43 @@ Boot2Docker.vmUpToDate = function (callback) {
|
|||
if (err) {
|
||||
callback(err); return;
|
||||
}
|
||||
var index = data.indexOf('Boot2Docker-v' + Boot2Docker.VERSION);
|
||||
callback(null, index !== -1);
|
||||
var match = data.match(/Boot2Docker-v(\d+\.\d+\.\d+)/);
|
||||
if (!match) {
|
||||
callback('Could not parse boot2docker iso version');
|
||||
return;
|
||||
}
|
||||
callback (null, Util.compareVersions(match[1], Boot2Docker.VERSION) < 0);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Boot2Docker.status = function (callback) {
|
||||
this.exec('status', function (stderr, stdout, code) {
|
||||
if (code) {callback(stderr); return;}
|
||||
callback(null, stdout.trim());
|
||||
});
|
||||
};
|
||||
|
||||
Boot2Docker.portAvailable = function (port, protocol, callback) {
|
||||
this.exec('ssh netstat -lntu | grep LISTEN | grep ' + protocol + ' | grep -c ":::' + port + '\\s"', function (stdout, stderr, code) {
|
||||
if (stderr.trim() === '0') {
|
||||
callback(true);
|
||||
} else {
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Boot2Docker.waitWhileStatus = function (status, callback) {
|
||||
var current = status;
|
||||
async.whilst(function () {
|
||||
return current === status;
|
||||
}, function (innerCallback) {
|
||||
Boot2Docker.status(function (err, vmStatus) {
|
||||
if (err) {innerCallback(err); return;}
|
||||
current = vmStatus.trim();
|
||||
innerCallback();
|
||||
});
|
||||
}, function (err) {
|
||||
callback(err);
|
||||
});
|
||||
};
|
|
@ -95,13 +95,23 @@ Docker.runContainer = function (app, image, callback) {
|
|||
var builtStr = key + '=' + app.config[key];
|
||||
envParam.push(builtStr);
|
||||
});
|
||||
Docker.client().createContainer({
|
||||
|
||||
var containerOpts = {
|
||||
Image: image.docker.Id,
|
||||
Tty: false,
|
||||
Env: envParam,
|
||||
Hostname: app.name,
|
||||
name: app.name
|
||||
}, function (err, container) {
|
||||
};
|
||||
|
||||
|
||||
if (app.docker && app.docker.NetworkSettings.Ports) {
|
||||
containerOpts.ExposedPorts = app.docker.NetworkSettings.Ports;
|
||||
}
|
||||
|
||||
console.log(containerOpts);
|
||||
|
||||
Docker.client().createContainer(containerOpts, function (err, container) {
|
||||
if (err) { callback(err, null); return; }
|
||||
console.log('Created container: ' + container.id);
|
||||
// Bind volumes
|
||||
|
@ -111,11 +121,19 @@ Docker.runContainer = function (app, image, callback) {
|
|||
binds.push([Util.getHomePath(), 'Kitematic', app.name, vol.Path].join('/') + ':' + vol.Path);
|
||||
});
|
||||
}
|
||||
// Start the container
|
||||
container.start({
|
||||
PublishAllPorts: true,
|
||||
|
||||
var startOpts = {
|
||||
Binds: binds
|
||||
}, function (err) {
|
||||
};
|
||||
|
||||
if (app.docker && app.docker.NetworkSettings.Ports) {
|
||||
startOpts.PortBindings = app.docker.NetworkSettings.Ports;
|
||||
} else {
|
||||
startOpts.PublishAllPorts = true;
|
||||
}
|
||||
|
||||
console.log(startOpts);
|
||||
container.start(startOpts, function (err) {
|
||||
if (err) { callback(err, null); return; }
|
||||
console.log('Started container: ' + container.id);
|
||||
callback(null, container);
|
||||
|
|
|
@ -2,11 +2,11 @@ FormSchema = {
|
|||
|
||||
formCreateApp: {
|
||||
name: {
|
||||
label: 'app name',
|
||||
label: 'container name',
|
||||
required: true,
|
||||
transforms: ['clean', 'slugify'],
|
||||
messages: {
|
||||
'uniqueAppName': "This app name is already being used."
|
||||
'uniqueAppName': "This container name is already being used."
|
||||
},
|
||||
rules: {
|
||||
uniqueAppName: true
|
||||
|
|
|
@ -3,6 +3,7 @@ var convert = new Convert();
|
|||
var exec = require('exec');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
|
||||
ImageUtil = {};
|
||||
|
||||
|
@ -239,55 +240,34 @@ ImageUtil.remove = function (imageId) {
|
|||
}
|
||||
};
|
||||
|
||||
ImageUtil.sync = function () {
|
||||
ImageUtil.sync = function (callback) {
|
||||
Docker.listImages(function (err, dockerImages) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
var images = Images.find({}).fetch();
|
||||
_.each(images, function (image) {
|
||||
var image = Images.findOne(image._id);
|
||||
if (image && image.docker && image.docker.Id) {
|
||||
var duplicateImages = Images.find({'docker.Id': image.docker.Id, _id: {$ne: image._id}}).fetch();
|
||||
_.each(duplicateImages, function (duplicateImage) {
|
||||
Images.remove(duplicateImage._id);
|
||||
});
|
||||
var imageData = _.find(dockerImages, function (dockerImage) {
|
||||
return dockerImage.Id === image.docker.Id;
|
||||
});
|
||||
if (imageData && imageData.RepoTags) {
|
||||
Images.update(image._id, {
|
||||
$set: {
|
||||
tags: imageData.RepoTags
|
||||
}
|
||||
});
|
||||
}
|
||||
Docker.getImageData(image.docker.Id, function (err, data) {
|
||||
Images.update(image._id, {
|
||||
$set: {
|
||||
docker: data
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
var dockerIds = _.map(images, function (image) {
|
||||
|
||||
// Delete missing GUI images
|
||||
var kitematicIds = _.map(images, function (image) {
|
||||
if (image.docker && image.docker.Id) {
|
||||
return image.docker.Id;
|
||||
}
|
||||
});
|
||||
var imageIds = _.map(dockerImages, function (image) {
|
||||
var daemonIds = _.map(daemonIds, function (image) {
|
||||
return image.Id;
|
||||
});
|
||||
var diffImages = _.difference(dockerIds, imageIds);
|
||||
var diffImages = _.difference(kitematicIds, daemonIds);
|
||||
_.each(diffImages, function (imageId) {
|
||||
var image = Images.findOne({'docker.Id': imageId});
|
||||
if (image && image.status !== 'BUILDING') {
|
||||
ImageUtil.remove(image._id);
|
||||
Images.remove(image._id);
|
||||
}
|
||||
});
|
||||
|
||||
// Add missing Daemon images
|
||||
var diffDockerImages = _.reject(dockerImages, function (image) {
|
||||
return _.contains(dockerIds, image.Id);
|
||||
return _.contains(kitematicIds, image.Id);
|
||||
});
|
||||
_.each(diffDockerImages, function (image) {
|
||||
var repoTag = _.first(image.RepoTags);
|
||||
|
@ -312,6 +292,36 @@ ImageUtil.sync = function () {
|
|||
Images.insert(imageObj);
|
||||
}
|
||||
});
|
||||
|
||||
async.each(images, function (image, callback) {
|
||||
var image = Images.findOne(image._id);
|
||||
if (image && image.docker && image.docker.Id) {
|
||||
var duplicateImages = Images.find({'docker.Id': image.docker.Id, _id: {$ne: image._id}}).fetch();
|
||||
_.each(duplicateImages, function (duplicateImage) {
|
||||
Images.remove(duplicateImage._id);
|
||||
});
|
||||
var imageData = _.find(dockerImages, function (dockerImage) {
|
||||
return dockerImage.Id === image.docker.Id;
|
||||
});
|
||||
if (imageData && imageData.RepoTags) {
|
||||
Images.update(image._id, {
|
||||
$set: {
|
||||
tags: imageData.RepoTags
|
||||
}
|
||||
});
|
||||
}
|
||||
Docker.getImageData(image.docker.Id, function (err, data) {
|
||||
if (err) {callback(err); return;}
|
||||
Images.update(image._id, {
|
||||
$set: {
|
||||
docker: data
|
||||
}
|
||||
});
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}, function (err) {
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -52,7 +52,7 @@ Router.map(function () {
|
|||
}
|
||||
Session.set('onIntro', false);
|
||||
startUpdatingBoot2DockerUtilization();
|
||||
// startSyncingAppState();
|
||||
startSyncingAppState();
|
||||
Router.go('dashboard_apps');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -67,6 +67,17 @@ Setup.steps = [
|
|||
},
|
||||
message: 'Downloading VirtualBox...'
|
||||
},
|
||||
{
|
||||
run: function (callback) {
|
||||
VirtualBox.shutdownVM('kitematic-vm', function (err, removed) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
message: 'Cleaning up existing Docker VM...'
|
||||
},
|
||||
|
||||
// Initialize Boot2Docker if necessary.
|
||||
{
|
||||
|
@ -74,10 +85,6 @@ Setup.steps = [
|
|||
Boot2Docker.exists(function (err, exists) {
|
||||
if (err) { callback(err); return; }
|
||||
if (!exists) {
|
||||
var vmFilesPath = path.join(Util.getHomePath(), 'VirtualBox\ VMs', 'boot2docker-vm');
|
||||
if (fs.existsSync(vmFilesPath)) {
|
||||
Util.deleteFolder(vmFilesPath);
|
||||
}
|
||||
Boot2Docker.init(function (err) {
|
||||
callback(err);
|
||||
});
|
||||
|
@ -105,9 +112,10 @@ Setup.steps = [
|
|||
},
|
||||
{
|
||||
run: function (callback) {
|
||||
Boot2Docker.state(function (err, state) {
|
||||
Boot2Docker.waitWhileStatus('saving', function (err) {
|
||||
Boot2Docker.status(function (err, status) {
|
||||
if (err) {callback(err); return;}
|
||||
if (state !== 'running') {
|
||||
if (status !== 'running') {
|
||||
Boot2Docker.start(function (err) {
|
||||
callback(err);
|
||||
});
|
||||
|
@ -115,6 +123,7 @@ Setup.steps = [
|
|||
callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
message: 'Starting the Docker VM...'
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var fs = require('fs');
|
||||
var exec = require('exec');
|
||||
var path = require('path');
|
||||
var async = require('async');
|
||||
|
||||
VirtualBox = {};
|
||||
|
||||
|
@ -51,7 +52,7 @@ VirtualBox.version = function (callback) {
|
|||
});
|
||||
};
|
||||
|
||||
VirtualBox.shutDownRunningVMs = function (callback) {
|
||||
VirtualBox.saveRunningVMs = function (callback) {
|
||||
if (!this.installed()) {
|
||||
callback('VirtualBox not installed.');
|
||||
return;
|
||||
|
@ -66,7 +67,7 @@ VirtualBox.shutDownRunningVMs = function (callback) {
|
|||
};
|
||||
|
||||
VirtualBox.killAllProcesses = function (callback) {
|
||||
this.shutDownRunningVMs(function (err) {
|
||||
this.saveRunningVMs(function (err) {
|
||||
if (err) {callback(err); return;}
|
||||
exec('pkill VirtualBox', function (stderr, stdout, code) {
|
||||
if (code) {callback(stderr); return;}
|
||||
|
@ -77,3 +78,41 @@ VirtualBox.killAllProcesses = function (callback) {
|
|||
});
|
||||
});
|
||||
};
|
||||
|
||||
VirtualBox.vmState = function (name, callback) {
|
||||
VirtualBox.exec('showvminfo ' + name + ' --machinereadable', function (stderr, stdout, code) {
|
||||
if (code) { callback(stderr); return; }
|
||||
var match = stdout.match(/VMState="(\w+)"/);
|
||||
if (!match) {
|
||||
callback('Could not parse VMState');
|
||||
return;
|
||||
}
|
||||
callback(null, match[1]);
|
||||
});
|
||||
};
|
||||
|
||||
VirtualBox.shutdownVM = function (name, callback) {
|
||||
VirtualBox.vmState(name, function (err, state) {
|
||||
// No VM found
|
||||
if (err) { callback(null, false); return; }
|
||||
VirtualBox.exec('controlvm ' + name + ' acpipowerbutton', function (stderr, stdout, code) {
|
||||
if (code) { callback(stderr, false); return; }
|
||||
var state = null;
|
||||
|
||||
async.until(function () {
|
||||
return state === 'poweroff';
|
||||
}, function (callback) {
|
||||
VirtualBox.vmState(name, function (err, newState) {
|
||||
if (err) { callback(err); return; }
|
||||
state = newState;
|
||||
setTimeout(callback, 250);
|
||||
});
|
||||
}, function (err) {
|
||||
VirtualBox.exec('unregistervm ' + name + ' --delete', function (stderr, stdout, code) {
|
||||
if (code) { callback(err); return; }
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -100,10 +100,11 @@ startUpdatingBoot2DockerUtilization = function () {
|
|||
};
|
||||
|
||||
startSyncingAppState = function () {
|
||||
ImageUtil.sync();
|
||||
AppUtil.sync();
|
||||
Meteor.setTimeout(function () {
|
||||
ImageUtil.sync();
|
||||
AppUtil.sync();
|
||||
}, 5000);
|
||||
ImageUtil.sync(function (err) {
|
||||
if (err) {console.log(err);}
|
||||
AppUtil.sync(function (err) {
|
||||
if (err) {console.log(err);}
|
||||
Meteor.setTimeout(startSyncingAppState, 5000);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -30,8 +30,11 @@
|
|||
}
|
||||
}
|
||||
.ports {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
.dropdown-menu {
|
||||
min-width: 241px;
|
||||
padding: 10px 15px 3px;
|
||||
}
|
||||
.btn-group {
|
||||
top: -2px;
|
||||
|
@ -62,7 +65,6 @@
|
|||
&.open + .tooltip {
|
||||
display: none !important;
|
||||
}
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
|
@ -281,10 +283,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
.form-env-vars {
|
||||
label {
|
||||
font-size: 13px;
|
||||
}
|
||||
input {
|
||||
font-size: 13px;
|
||||
padding: 5px 9px;
|
||||
}
|
||||
.env-var-pair {
|
||||
.make-row();
|
||||
margin-bottom: 0.2em;
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
.env-var-key {
|
||||
.make-xs-column(5);
|
||||
text-overflow: ellipsis;
|
||||
|
@ -301,10 +311,10 @@
|
|||
.make-xs-column(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-ports {
|
||||
cursor: default;
|
||||
padding: 10px 15px 3px;
|
||||
min-width: 240px;
|
||||
li {
|
||||
padding-bottom: 7px;
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
<template name="dashboardAppsPorts">
|
||||
<div class="app-ports">
|
||||
{{#each ports}}
|
||||
{{#if this.web}}
|
||||
<li role="menuitem">
|
||||
<span class="port-wrapper">Port {{this.port}}</span>
|
||||
<span class="arrow-wrapper"></span>
|
||||
<span class="open-button-wrapper">
|
||||
<a href="{{this.url}}" onclick="trackLink('view container')" class="btn btn-action btn-xs btn-view-port">Open in Browser</a>
|
||||
</span>
|
||||
</li>
|
||||
{{else}}
|
||||
<li role="menuitem">
|
||||
<span class="port-wrapper">Port {{this.port}}</span>
|
||||
<span class="arrow-wrapper">
|
||||
|
@ -17,7 +8,6 @@
|
|||
</span>
|
||||
<span class="host-address-wrapper">{{this.hostIp}}:{{this.hostPort}}</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</template>
|
|
@ -1,4 +1,14 @@
|
|||
<template name="dashboardAppsSettings">
|
||||
<div class="section">
|
||||
<div class="left-section">
|
||||
<h4>Ports</h4>
|
||||
</div>
|
||||
<div class="right-section">
|
||||
<ul class="list-unstyled">
|
||||
{{> dashboardAppsPorts}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="left-section">
|
||||
<h4>Environment Variables</h4>
|
||||
|
|
|
@ -45,7 +45,7 @@ Template.dashboardAppsSettings.events({
|
|||
e.preventDefault();
|
||||
var appId = this._id;
|
||||
dialog.showMessageBox({
|
||||
message: 'Are you sure you want to delete this app?',
|
||||
message: 'Are you sure you want to delete this container?',
|
||||
buttons: ['Delete', 'Cancel']
|
||||
}, function (index) {
|
||||
if (index === 0) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
</h5>
|
||||
<div class="options">
|
||||
{{#if $eq status 'READY'}}
|
||||
{{#if ports}}
|
||||
{{#if viewPort}}
|
||||
<div class="ports btn-group btn-icon" title="View" data-placement="bottom">
|
||||
<a href="{{viewPort.url}}" onclick="trackLink('view container')" class="btn btn-action btn-xs btn-view btn-globe">
|
||||
|
@ -50,10 +51,11 @@
|
|||
</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<a href="#" onclick="trackLink('open container folder')" class="btn-icon btn-folder" data-toggle="tooltip" data-placement="bottom" title="Volumes"><span class="typcn typcn-folder"></span></a>
|
||||
{{#if $eq status 'READY'}}
|
||||
<a href="#" onclick="trackLink('terminal into container')" class="btn-icon btn-terminal" data-toggle="tooltip" data-placement="bottom" title="Terminal"><span class="typcn typcn-device-laptop"></span></a>
|
||||
<a href="#" onclick="trackLink('stop container')" class="btn-icon btn-stop" data-toggle="tooltip" data-placement="bottom" title="Stop"><span class="typcn typcn-media-pause-outline"></span></a>
|
||||
<a href="#" onclick="trackLink('stop container')" class="btn-icon btn-stop" data-toggle="tooltip" data-placement="bottom" title="Stop"><span class="typcn typcn-media-stop-outline"></span></a>
|
||||
{{/if}}
|
||||
{{#if $eq status 'STOPPED'}}
|
||||
<a href="#" onclick="trackLink('start container')" class="btn-icon btn-start" data-toggle="tooltip" data-placement="bottom" title="Start"><span class="typcn typcn-media-play-outline"></span></a>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var remote = require('remote');
|
||||
var dialog = remote.require('dialog');
|
||||
var exec = require('child_process').exec;
|
||||
var path = require('path');
|
||||
|
||||
Template.dashboardSingleApp.rendered = function () {
|
||||
Meteor.setInterval(function () {
|
||||
|
@ -48,22 +49,39 @@ Template.dashboardSingleApp.events({
|
|||
},
|
||||
'click .btn-restart': function (e) {
|
||||
e.preventDefault();
|
||||
AppUtil.restart(this._id);
|
||||
AppUtil.run(this, function (err) {});
|
||||
},
|
||||
'click .btn-folder': function (e) {
|
||||
e.preventDefault();
|
||||
var appId = this._id;
|
||||
|
||||
var app = Apps.findOne(appId);
|
||||
var app = this;
|
||||
if (!app) {
|
||||
throw new Error('Cannot find app with id: ' + appId);
|
||||
throw new Error('Cannot find app with id: ' + app._id);
|
||||
}
|
||||
|
||||
if (app.volumesEnabled) {
|
||||
exec('open ' + this.path, function (err) {
|
||||
var openDirectory = function () {
|
||||
var appPath = path.join(Util.KITE_PATH, app.name);
|
||||
if (app.docker.Volumes.length) {
|
||||
if (app.docker.Volumes[0].Value.indexOf(path.join(Util.getHomePath(), 'Kitematic')) !== -1) {
|
||||
exec('open ' + appPath, function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
exec('open ' + app.docker.Volumes[0].Value, function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
exec('open ' + appPath, function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (app.volumesEnabled) {
|
||||
openDirectory();
|
||||
return;
|
||||
}
|
||||
|
||||
dialog.showMessageBox({
|
||||
|
@ -71,14 +89,12 @@ Template.dashboardSingleApp.events({
|
|||
buttons: ['Enable Volumes', 'Cancel']
|
||||
}, function (index) {
|
||||
if (index === 0) {
|
||||
Apps.update(appId, {
|
||||
Apps.update(app._id, {
|
||||
$set: {volumesEnabled: true}
|
||||
});
|
||||
AppUtil.run(Apps.findOne(appId), function (err) {
|
||||
AppUtil.run(Apps.findOne(app._id), function (err) {
|
||||
if (err) { throw err; }
|
||||
exec('open ' + this.path, function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
openDirectory();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -31,7 +31,6 @@ Template.modalCreateApp.events({
|
|||
imageId: cleaned.imageId,
|
||||
status: 'STARTING',
|
||||
config: {},
|
||||
path: appPath,
|
||||
logs: [],
|
||||
createdAt: new Date(),
|
||||
volumesEnabled: true
|
||||
|
|
|
@ -59,7 +59,7 @@ Template.modalCreateImage.events({
|
|||
if (imageObj.meta.logo) {
|
||||
Images.update(imageId, {
|
||||
$set: {
|
||||
logoPath: path.join(imagePath, imageObj.meta.logo)
|
||||
logoPath: path.join(directory, imageObj.meta.logo)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ Template.dashboardAppsLayout.events({
|
|||
},
|
||||
'click .btn-folder': function () {
|
||||
var exec = require('child_process').exec;
|
||||
exec('open ' + this.path, function (err) {
|
||||
var appPath = path.join(Util.KITE_PATH, this.name);
|
||||
exec('open ' + appPath, function (err) {
|
||||
if (err) { throw err; }
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
Apps = new Meteor.Collection('apps');
|
||||
|
||||
Apps.COMMON_WEB_PORTS = [
|
||||
80,
|
||||
8000,
|
||||
8080,
|
||||
3000,
|
||||
5000,
|
||||
2368,
|
||||
443
|
||||
'80',
|
||||
'8000',
|
||||
'8080',
|
||||
'3000',
|
||||
'5000',
|
||||
'2368',
|
||||
'443'
|
||||
];
|
||||
|
||||
Apps.allow({
|
||||
|
@ -35,22 +35,27 @@ Apps.helpers({
|
|||
if (!app.docker || !app.docker.NetworkSettings.Ports) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var results = _.map(app.docker.NetworkSettings.Ports, function (value, key) {
|
||||
var portProtocolPair = key.split('/');
|
||||
var res = {
|
||||
'port': parseInt(portProtocolPair[0]),
|
||||
'port': portProtocolPair[0],
|
||||
'protocol': portProtocolPair[1]
|
||||
};
|
||||
if (value.length) {
|
||||
if (value && value.length) {
|
||||
var port = value[0].HostPort;
|
||||
res['hostIp'] = Docker.hostIp;
|
||||
res['hostPort'] = port;
|
||||
res['web'] = Apps.COMMON_WEB_PORTS.indexOf(res.port) !== -1;
|
||||
res['url'] = 'http://' + Docker.hostIp + ':' + port;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
results = _.filter(results, function (res) { return res !== null; });
|
||||
|
||||
results.sort(function (a, b) {
|
||||
// prefer lower ports
|
||||
if (a.web && b.web) {
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
"type": "GNU",
|
||||
"url": "https://raw.githubusercontent.com/kitematic/kitematic/master/LICENSE"
|
||||
}],
|
||||
"boot2docker-version": "1.3.2",
|
||||
"main": "index.js",
|
||||
"version": "0.4.0",
|
||||
"dependencies": {
|
||||
"ansi-to-html": "0.2.0",
|
||||
"async": "^0.9.0",
|
||||
"chokidar": "git+https://github.com/usekite/chokidar.git",
|
||||
"dockerode": "2.0.4",
|
||||
"exec": "^0.1.2",
|
||||
"moment": "2.8.1",
|
||||
|
@ -25,6 +25,7 @@
|
|||
"open": "0.0.5",
|
||||
"request": "2.42.0",
|
||||
"request-progress": "0.3.1",
|
||||
"tar": "0.1.20"
|
||||
"tar": "0.1.20",
|
||||
"pkginfo": "0.3.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,35 +2,31 @@
|
|||
set -e # Auto exit on error
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
source $DIR/colors.sh
|
||||
|
||||
BASE=$DIR/..
|
||||
NPM="$BASE/cache/node/bin/npm"
|
||||
NODE="$BASE/cache/node/bin/node"
|
||||
VERSION=$($NODE -pe 'JSON.parse(process.argv[1]).version' "$(cat package.json)")
|
||||
|
||||
pushd $BASE/meteor
|
||||
source $DIR/colors.sh
|
||||
|
||||
$BASE/script/setup.sh
|
||||
rm -rf ../bundle
|
||||
rm -rf ./bundle
|
||||
|
||||
cecho "-----> Building bundle from Meteor app, this may take a few minutes..." $blue
|
||||
|
||||
cd $BASE/meteor
|
||||
meteor bundle --directory ../bundle
|
||||
|
||||
cd ../bundle
|
||||
cd $BASE/bundle
|
||||
|
||||
cecho "-----> Installing bundle npm packages." $blue
|
||||
pushd programs/server
|
||||
cd programs/server
|
||||
$NPM install
|
||||
popd
|
||||
|
||||
cecho "Bundle created." $green
|
||||
|
||||
popd
|
||||
cd $BASE
|
||||
|
||||
pushd $BASE
|
||||
|
||||
rm -rf ./dist/osx
|
||||
rm -Rf ./dist/osx/
|
||||
mkdir -p ./dist/osx/
|
||||
|
||||
DIST_APP=Kitematic.app
|
||||
|
@ -39,6 +35,7 @@ cecho "-----> Creating $DIST_APP..." $blue
|
|||
find cache/atom-shell -name "debug\.log" -print0 | xargs -0 rm -rf
|
||||
cp -R cache/atom-shell/Atom.app dist/osx/
|
||||
mv dist/osx/Atom.app dist/osx/$DIST_APP
|
||||
mv dist/osx/$DIST_APP/Contents/MacOS/Atom dist/osx/$DIST_APP/Contents/MacOS/Kitematic
|
||||
mkdir -p dist/osx/$DIST_APP/Contents/Resources/app
|
||||
|
||||
cecho "-----> Copying meteor bundle into $DIST_APP..." $blue
|
||||
|
@ -58,7 +55,6 @@ cp kitematic.icns dist/osx/$DIST_APP/Contents/Resources/atom.icns
|
|||
|
||||
chmod +x dist/osx/$DIST_APP/Contents/Resources/app/resources/terminal
|
||||
chmod +x dist/osx/$DIST_APP/Contents/Resources/app/resources/node
|
||||
|
||||
chmod -R u+w dist/osx/$DIST_APP/Contents/Resources/app/bundle
|
||||
|
||||
cecho "-----> Updating Info.plist version to $VERSION" $blue
|
||||
|
@ -66,19 +62,17 @@ cecho "-----> Updating Info.plist version to $VERSION" $blue
|
|||
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName Kitematic" $BASE/dist/osx/$DIST_APP/Contents/Info.plist
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleName Kitematic" $BASE/dist/osx/$DIST_APP/Contents/Info.plist
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.kitematic.kitematic" $BASE/dist/osx/$DIST_APP/Contents/Info.plist
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleExecutable Kitematic" $BASE/dist/osx/$DIST_APP/Contents/Info.plist
|
||||
|
||||
if [ -f $DIR/sign.sh ]; then
|
||||
cecho "-----> Signing app file...." $blue
|
||||
$DIR/sign.sh $BASE/dist/osx/$DIST_APP
|
||||
fi
|
||||
|
||||
pushd dist/osx
|
||||
cecho "-----> Creating disributable zip file...." $blue
|
||||
ditto -c -k --sequesterRsrc --keepParent $DIST_APP Kitematic-$VERSION.zip
|
||||
popd
|
||||
cd $BASE/dist/osx
|
||||
cecho "-----> Creating disributable zip file...." $blue
|
||||
ditto -c -k --sequesterRsrc --keepParent $DIST_APP Kitematic-$VERSION.zip
|
||||
|
||||
cecho "Done." $green
|
||||
cecho "Kitematic app available at dist/osx/$DIST_APP" $green
|
||||
cecho "Kitematic zip distribution available at dist/osx/Kitematic.zip" $green
|
||||
|
||||
popd
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
#!/bin/bash
|
||||
set -e # Auto exit on error
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
source $DIR/colors.sh
|
||||
|
||||
BASE=$DIR/..
|
||||
pushd $BASE
|
||||
|
||||
mkdir -p cache
|
||||
|
||||
pushd cache
|
||||
|
||||
BOOT2DOCKER_CLI_VERSION=1.3.1
|
||||
BOOT2DOCKER_CLI_VERSION_FILE=boot2docker-$BOOT2DOCKER_CLI_VERSION
|
||||
BOOT2DOCKER_CLI_FILE=boot2docker
|
||||
|
||||
ATOM_SHELL_VERSION=0.19.1
|
||||
ATOM_SHELL_FILE=atom-shell-v$ATOM_SHELL_VERSION-darwin-x64.zip
|
||||
BASE=$DIR/..
|
||||
|
||||
source $DIR/colors.sh
|
||||
cd $BASE
|
||||
|
||||
mkdir -p cache
|
||||
cd cache
|
||||
|
||||
if [ ! -f $ATOM_SHELL_FILE ]; then
|
||||
cecho "-----> Downloading Atom Shell..." $purple
|
||||
|
@ -42,9 +36,13 @@ if [ ! -f "node-v0.10.29-darwin-x64.tar.gz" ]; then
|
|||
cp node/LICENSE $BASE/resources/NODE_LICENSE.txt
|
||||
fi
|
||||
|
||||
popd
|
||||
cd $BASE
|
||||
|
||||
pushd resources
|
||||
NODE="$BASE/cache/node/bin/node"
|
||||
BOOT2DOCKER_CLI_VERSION=$($NODE -pe "JSON.parse(process.argv[1])['boot2dockerversion']" "$(cat package.json)")
|
||||
BOOT2DOCKER_CLI_VERSION_FILE=boot2docker-$BOOT2DOCKER_CLI_VERSION
|
||||
|
||||
cd resources
|
||||
|
||||
if [ ! -f $BOOT2DOCKER_CLI_VERSION_FILE ]; then
|
||||
cecho "-----> Downloading Boot2docker CLI..." $purple
|
||||
|
@ -53,13 +51,12 @@ fi
|
|||
|
||||
chmod +x $BOOT2DOCKER_CLI_VERSION_FILE
|
||||
|
||||
popd
|
||||
cd $BASE
|
||||
|
||||
# Build NPM modules
|
||||
NPM="$BASE/cache/node/bin/npm"
|
||||
|
||||
export npm_config_disturl=https://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/dist
|
||||
export npm_config_target=0.16.2
|
||||
export npm_config_target=ATOM_SHELL_VERSION
|
||||
export npm_config_arch=ia32
|
||||
HOME=~/.atom-shell-gyp $NPM install
|
||||
|
||||
popd
|
||||
|
|
Loading…
Reference in New Issue