mirror of https://github.com/docker/docs.git
Merge pull request #101 from kitematic/merge0.3.0
Merge 0.3.0 RC into master.
This commit is contained in:
commit
d88a3cb028
|
@ -10,7 +10,7 @@ bin
|
||||||
|
|
||||||
# Resources
|
# Resources
|
||||||
resources/cache
|
resources/cache
|
||||||
resources/base-images.tar.gz
|
resources/base-images-*.tar.gz
|
||||||
resources/virtualbox-*.pkg
|
resources/virtualbox-*.pkg
|
||||||
resources/boot2docker*
|
resources/boot2docker*
|
||||||
resources/node-webkit
|
resources/node-webkit
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
|
|
||||||
notices-for-0.9.0
|
notices-for-0.9.0
|
||||||
notices-for-0.9.1
|
notices-for-0.9.1
|
||||||
|
0.9.4-platform-file
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
server
|
||||||
|
browser
|
|
@ -1 +1 @@
|
||||||
METEOR@0.9.1.1
|
METEOR@0.9.4
|
||||||
|
|
|
@ -1,54 +1,61 @@
|
||||||
application-configuration@1.0.1
|
application-configuration@1.0.3
|
||||||
autoupdate@1.0.6
|
autoupdate@1.1.2
|
||||||
binary-heap@1.0.0
|
base64@1.0.1
|
||||||
blaze-tools@1.0.0
|
binary-heap@1.0.1
|
||||||
blaze@2.0.0
|
blaze-tools@1.0.1
|
||||||
callback-hook@1.0.0
|
blaze@2.0.2
|
||||||
check@1.0.0
|
boilerplate-generator@1.0.1
|
||||||
ctl-helper@1.0.3
|
callback-hook@1.0.1
|
||||||
ctl@1.0.1
|
check@1.0.2
|
||||||
|
ctl-helper@1.0.4
|
||||||
|
ctl@1.0.2
|
||||||
dburles:collection-helpers@1.0.0
|
dburles:collection-helpers@1.0.0
|
||||||
ddp@1.0.8
|
ddp@1.0.10
|
||||||
deps@1.0.3
|
deps@1.0.5
|
||||||
ejson@1.0.1
|
ejson@1.0.4
|
||||||
follower-livedata@1.0.1
|
fastclick@1.0.1
|
||||||
geojson-utils@1.0.0
|
follower-livedata@1.0.2
|
||||||
html-tools@1.0.0
|
geojson-utils@1.0.1
|
||||||
htmljs@1.0.0
|
html-tools@1.0.2
|
||||||
id-map@1.0.0
|
htmljs@1.0.2
|
||||||
|
http@1.0.7
|
||||||
|
id-map@1.0.1
|
||||||
iron:core@0.3.4
|
iron:core@0.3.4
|
||||||
iron:dynamic-template@0.4.1
|
iron:dynamic-template@0.4.1
|
||||||
iron:layout@0.4.1
|
iron:layout@0.4.1
|
||||||
iron:router@0.9.3
|
iron:router@0.9.4
|
||||||
jquery@1.0.0
|
jquery@1.0.1
|
||||||
json@1.0.0
|
json@1.0.1
|
||||||
less@1.0.7
|
less@1.0.10
|
||||||
livedata@1.0.9
|
livedata@1.0.11
|
||||||
logging@1.0.2
|
logging@1.0.4
|
||||||
meteor-platform@1.0.2
|
meteor-platform@1.1.2
|
||||||
meteor@1.0.3
|
meteor@1.1.2
|
||||||
minifiers@1.0.2
|
minifiers@1.1.1
|
||||||
minimongo@1.0.2
|
minimongo@1.0.4
|
||||||
mongo-livedata@1.0.4
|
mobile-status-bar@1.0.1
|
||||||
mongo@1.0.4
|
mongo-livedata@1.0.6
|
||||||
|
mongo@1.0.7
|
||||||
mrt:underscore-string-latest@2.3.3
|
mrt:underscore-string-latest@2.3.3
|
||||||
observe-sequence@1.0.2
|
observe-sequence@1.0.3
|
||||||
ordered-dict@1.0.0
|
ordered-dict@1.0.1
|
||||||
raix:handlebar-helpers@0.1.2
|
raix:handlebar-helpers@0.1.3
|
||||||
random@1.0.0
|
random@1.0.1
|
||||||
reactive-dict@1.0.2
|
reactive-dict@1.0.4
|
||||||
reactive-var@1.0.1
|
reactive-var@1.0.3
|
||||||
reload@1.0.1
|
reload@1.1.1
|
||||||
retry@1.0.0
|
retry@1.0.1
|
||||||
reywood:iron-router-ga@0.3.2
|
reywood:iron-router-ga@0.3.2
|
||||||
routepolicy@1.0.0
|
routepolicy@1.0.2
|
||||||
session@1.0.1
|
session@1.0.3
|
||||||
simison:bootstrap3-less@0.3.0
|
simison:bootstrap3-less@0.3.0
|
||||||
spacebars-compiler@1.0.2
|
spacebars-compiler@1.0.3
|
||||||
spacebars@1.0.1
|
spacebars@1.0.3
|
||||||
standard-app-packages@1.0.1
|
standard-app-packages@1.0.3
|
||||||
templating@1.0.5
|
templating@1.0.8
|
||||||
tracker@1.0.2
|
tracker@1.0.3
|
||||||
ui@1.0.2
|
ui@1.0.4
|
||||||
underscore@1.0.0
|
underscore@1.0.1
|
||||||
webapp@1.0.3
|
url@1.0.1
|
||||||
|
webapp-hashing@1.0.1
|
||||||
|
webapp@1.1.3
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var exec = require('exec');
|
var exec = require('exec');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
var Convert = require('ansi-to-html');
|
var Convert = require('ansi-to-html');
|
||||||
var convert = new Convert();
|
var convert = new Convert();
|
||||||
|
|
||||||
|
@ -32,11 +33,10 @@ AppUtil.restartHelper = function (app) {
|
||||||
if (err) { console.error(err); }
|
if (err) { console.error(err); }
|
||||||
Docker.getContainerData(app.docker.Id, function (err, data) {
|
Docker.getContainerData(app.docker.Id, function (err, data) {
|
||||||
if (err) { console.error(err); }
|
if (err) { console.error(err); }
|
||||||
// Use dig to refresh the DNS
|
Util.refreshDNS(app, function (err) {
|
||||||
exec('/usr/bin/dig ' + app.name + '.kite @172.17.42.1', function(err, stdout, stderr) {
|
if (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
console.log(stdout);
|
}
|
||||||
console.log(stderr);
|
|
||||||
Apps.update(app._id, {$set: {
|
Apps.update(app._id, {$set: {
|
||||||
status: 'READY',
|
status: 'READY',
|
||||||
docker: data
|
docker: data
|
||||||
|
@ -57,11 +57,10 @@ AppUtil.start = function (appId) {
|
||||||
if (err) { console.error(err); }
|
if (err) { console.error(err); }
|
||||||
Docker.getContainerData(app.docker.Id, function (err, data) {
|
Docker.getContainerData(app.docker.Id, function (err, data) {
|
||||||
if (err) { console.error(err); }
|
if (err) { console.error(err); }
|
||||||
// Use dig to refresh the DNS
|
Util.refreshDNS(app, function (err) {
|
||||||
exec('/usr/bin/dig ' + app.name + '.kite @172.17.42.1', function(err, stdout, stderr) {
|
if (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
console.log(stdout);
|
}
|
||||||
console.log(stderr);
|
|
||||||
Apps.update(app._id, {$set: {
|
Apps.update(app._id, {$set: {
|
||||||
status: 'READY',
|
status: 'READY',
|
||||||
docker: data
|
docker: data
|
||||||
|
@ -166,3 +165,94 @@ AppUtil.recover = function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AppUtil.sync = function () {
|
||||||
|
Docker.listContainers(function (err, containers) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var containerIds = _.map(containers, function (container) {
|
||||||
|
return container.Id;
|
||||||
|
});
|
||||||
|
var diffApps = _.difference(dockerIds, containerIds);
|
||||||
|
_.each(diffApps, function (appContainerId) {
|
||||||
|
var app = Apps.findOne({'docker.Id': appContainerId});
|
||||||
|
if (app && app.status !== 'STARTING') {
|
||||||
|
AppUtil.remove(app._id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var diffContainers = _.reject(containers, function (container) {
|
||||||
|
return _.contains(dockerIds, container.Id);
|
||||||
|
});
|
||||||
|
_.each(diffContainers, function (container) {
|
||||||
|
var appName = container.Name.substring(1);
|
||||||
|
var startingApp = _.find(apps, function (app) {
|
||||||
|
return app.status === 'STARTING' && app.name === appName;
|
||||||
|
});
|
||||||
|
if (!startingApp && appName !== 'kite-dns') {
|
||||||
|
var appPath = path.join(Util.KITE_PATH, appName);
|
||||||
|
if (!fs.existsSync(appPath)) {
|
||||||
|
console.log('Created Kite ' + appName + ' directory.');
|
||||||
|
fs.mkdirSync(appPath, function (err) {
|
||||||
|
if (err) { throw err; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var envVars = container.Config.Env;
|
||||||
|
var config = {};
|
||||||
|
_.each(envVars, function (envVar) {
|
||||||
|
var eqPos = envVar.indexOf('=');
|
||||||
|
var envKey = envVar.substring(0, eqPos);
|
||||||
|
var envVal = envVar.substring(eqPos + 1);
|
||||||
|
config[envKey] = envVal;
|
||||||
|
});
|
||||||
|
var status = 'STARTING';
|
||||||
|
if (container.State.Running) {
|
||||||
|
status = 'READY';
|
||||||
|
} else {
|
||||||
|
status = 'ERROR';
|
||||||
|
}
|
||||||
|
var appObj = {
|
||||||
|
name: appName,
|
||||||
|
docker: container,
|
||||||
|
status: status,
|
||||||
|
config: config,
|
||||||
|
path: appPath,
|
||||||
|
logs: [],
|
||||||
|
createdAt: new Date()
|
||||||
|
};
|
||||||
|
console.log(appObj);
|
||||||
|
Apps.insert(appObj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@ Boot2Docker = {};
|
||||||
Boot2Docker.REQUIRED_IP = '192.168.60.103';
|
Boot2Docker.REQUIRED_IP = '192.168.60.103';
|
||||||
|
|
||||||
Boot2Docker.command = function () {
|
Boot2Docker.command = function () {
|
||||||
return path.join(Util.getBinDir().replace(' ', '\\ '), 'boot2docker-1.2.0') + ' --vm="kitematic-vm"';
|
return path.join(Util.getBinDir(), 'boot2docker-1.3.0') + ' --vm="kitematic-vm"';
|
||||||
};
|
};
|
||||||
|
|
||||||
Boot2Docker.exec = function (command, callback) {
|
Boot2Docker.exec = function (command, callback) {
|
||||||
|
@ -60,8 +60,10 @@ Boot2Docker.ip = function (callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Boot2Docker.setIp = function (ifname, ip, callback) {
|
Boot2Docker.setIp = function (ifname, ip, callback) {
|
||||||
this.exec('ssh "sudo ifconfig ' + ifname + ' ' + ip + ' netmask 255.255.255.0"', function (err, stdout) {
|
Boot2Docker.exec('ssh "sudo ifconfig ' + ifname + ' ' + ip + ' netmask 255.255.255.0"', function (err, stdout) {
|
||||||
callback(err);
|
Boot2Docker.exec('ssh "sudo rm -rf /var/lib/boot2docker/tls/* && sudo /etc/init.d/docker restart"', function (err, stdout) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,12 +80,10 @@ Boot2Docker.start = function (callback) {
|
||||||
callback('Cannot start if the boot2docker VM doesn\'t exist');
|
callback('Cannot start if the boot2docker VM doesn\'t exist');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.exec('up -v', function (err, stdout) {
|
self.exec('start', function (err, stdout) {
|
||||||
// Sometimes boot2docker returns an error code even though it's working / waiting, so treat that as
|
// Sometimes boot2docker returns an error code even though it's working / waiting, so treat that as success as well
|
||||||
// Success as well
|
if (!err || (err.indexOf('Waiting') !== -1 || err.indexOf('Writing') !== -1 || err.indexOf('Generating a server cert') !== -1)) {
|
||||||
if (!err || (err.indexOf('Waiting for VM to be started') !== -1 || err.indexOf('..........') !== -1)) {
|
|
||||||
self.correct(function (err) {
|
self.correct(function (err) {
|
||||||
if (err) { callback(err); return; }
|
|
||||||
self.injectUtilities(function (err) {
|
self.injectUtilities(function (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
|
@ -96,7 +96,7 @@ Boot2Docker.start = function (callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Boot2Docker.correct = function (callback) {
|
Boot2Docker.correct = function (callback) {
|
||||||
Boot2Docker.setIp('eth2', Boot2Docker.REQUIRED_IP, function(err) {
|
Boot2Docker.setIp('eth1', Boot2Docker.REQUIRED_IP, function(err) {
|
||||||
if (err) { callback(err); return; }
|
if (err) { callback(err); return; }
|
||||||
VirtualBox.removeDHCP(function (err) {
|
VirtualBox.removeDHCP(function (err) {
|
||||||
callback();
|
callback();
|
||||||
|
@ -239,7 +239,7 @@ Boot2Docker.version = function (callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Boot2Docker.injectUtilities = function (callback) {
|
Boot2Docker.injectUtilities = function (callback) {
|
||||||
exec('/bin/cat ' + path.join(Util.getBinDir(), 'kite-binaries.tar.gz') + ' | ' + Boot2Docker.command() + ' ssh "tar zx -C /usr/local/bin"', function (err, stdout) {
|
exec('/bin/cat ' + path.join(Util.getBinDir(), 'kite-binaries.tar.gz') + ' | ' + Boot2Docker.command() + ' ssh "sudo tar zx -C /usr/local/bin && sudo chown -R root.root /usr/local/bin"', function (err, stdout) {
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,15 +2,25 @@ var Dockerode = require('dockerode');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var exec = require('exec');
|
var exec = require('exec');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
Docker = {};
|
Docker = {};
|
||||||
Docker.DOCKER_HOST = '192.168.60.103';
|
|
||||||
|
|
||||||
Docker.DEFAULT_IMAGES_FILENAME = 'base-images-0.0.2.tar.gz';
|
Docker.DEFAULT_IMAGES_FILENAME = 'base-images-0.0.2.tar.gz';
|
||||||
Docker.DEFAULT_IMAGES_CHECKSUM = 'a3517ac21034a1969d9ff15e3c41b1e2f1aa83c67b16a8bd0bc378ffefaf573b'; // Sha256 Checksum
|
Docker.DEFAULT_IMAGES_CHECKSUM = 'a3517ac21034a1969d9ff15e3c41b1e2f1aa83c67b16a8bd0bc378ffefaf573b'; // Sha256 Checksum
|
||||||
|
Docker.CERT_DIR = path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/kitematic-vm');
|
||||||
|
Docker.HOST_IP = '192.168.60.103';
|
||||||
|
Docker.HOST_PORT = '2376';
|
||||||
|
|
||||||
Docker.client = function () {
|
Docker.client = function () {
|
||||||
return new Dockerode({host: Docker.DOCKER_HOST, port: '2375'});
|
return new Dockerode({
|
||||||
|
protocol: 'https',
|
||||||
|
host: Docker.HOST_IP,
|
||||||
|
port: Docker.HOST_PORT,
|
||||||
|
ca: fs.readFileSync(path.join(Docker.CERT_DIR, 'ca.pem')),
|
||||||
|
cert: fs.readFileSync(path.join(Docker.CERT_DIR, 'cert.pem')),
|
||||||
|
key: fs.readFileSync(path.join(Docker.CERT_DIR, 'key.pem'))
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var docker = Docker.client();
|
var docker = Docker.client();
|
||||||
|
@ -27,6 +37,33 @@ Docker.removeContainer = function (containerId, callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Docker.listContainers = function (callback) {
|
||||||
|
docker.listContainers({all: true}, function (err, containers) {
|
||||||
|
if (err) {
|
||||||
|
callback(err, null);
|
||||||
|
} else {
|
||||||
|
var cbList = _.map(containers, function (container) {
|
||||||
|
return function (cb) {
|
||||||
|
Docker.getContainerData(container.Id, function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
cb(err, null);
|
||||||
|
} else {
|
||||||
|
cb(null, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
async.parallel(cbList, function (err, results) {
|
||||||
|
if (err) {
|
||||||
|
callback(err, null);
|
||||||
|
} else {
|
||||||
|
callback(null, results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Docker.getContainerData = function (containerId, callback) {
|
Docker.getContainerData = function (containerId, callback) {
|
||||||
var container = docker.getContainer(containerId);
|
var container = docker.getContainer(containerId);
|
||||||
container.inspect(function (err, data) {
|
container.inspect(function (err, data) {
|
||||||
|
@ -34,9 +71,15 @@ Docker.getContainerData = function (containerId, callback) {
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
data.Config.Volumes = convertVolumeObjToArray(data.Config.Volumes);
|
if (data.Config && data.Config.Volumes) {
|
||||||
data.Volumes = convertVolumeObjToArray(data.Volumes);
|
data.Config.Volumes = convertVolumeObjToArray(data.Config.Volumes);
|
||||||
data.VolumesRW = convertVolumeObjToArray(data.VolumesRW);
|
}
|
||||||
|
if (data.Volumes) {
|
||||||
|
data.Volumes = convertVolumeObjToArray(data.Volumes);
|
||||||
|
}
|
||||||
|
if (data.VolumesRW) {
|
||||||
|
data.VolumesRW = convertVolumeObjToArray(data.VolumesRW);
|
||||||
|
}
|
||||||
callback(null, data);
|
callback(null, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +94,7 @@ Docker.runContainer = function (app, image, callback) {
|
||||||
});
|
});
|
||||||
console.log(envParam);
|
console.log(envParam);
|
||||||
docker.createContainer({
|
docker.createContainer({
|
||||||
Image: image._id.toLowerCase(),
|
Image: image.docker.Id,
|
||||||
Tty: false,
|
Tty: false,
|
||||||
Env: envParam,
|
Env: envParam,
|
||||||
Hostname: app.name,
|
Hostname: app.name,
|
||||||
|
@ -61,7 +104,7 @@ Docker.runContainer = function (app, image, callback) {
|
||||||
console.log('Created container: ' + container.id);
|
console.log('Created container: ' + container.id);
|
||||||
// Bind volumes
|
// Bind volumes
|
||||||
var binds = [];
|
var binds = [];
|
||||||
if (image.docker.Config.Volumes.length > 0) {
|
if (image.docker.Config.Volumes && image.docker.Config.Volumes.length > 0) {
|
||||||
_.each(image.docker.Config.Volumes, function (vol) {
|
_.each(image.docker.Config.Volumes, function (vol) {
|
||||||
binds.push('/var/lib/docker/binds/' + app.name + vol.Path + ':' + vol.Path);
|
binds.push('/var/lib/docker/binds/' + app.name + vol.Path + ':' + vol.Path);
|
||||||
});
|
});
|
||||||
|
@ -73,11 +116,10 @@ Docker.runContainer = function (app, image, callback) {
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
if (err) { callback(err, null); return; }
|
if (err) { callback(err, null); return; }
|
||||||
console.log('Started container: ' + container.id);
|
console.log('Started container: ' + container.id);
|
||||||
// Use dig to refresh the DNS
|
Util.refreshDNS(app, function (err) {
|
||||||
exec('/usr/bin/dig ' + app.name + '.kite @172.17.42.1', function(err, stdout, stderr) {
|
if (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
console.log(stdout);
|
}
|
||||||
console.log(stderr);
|
|
||||||
callback(null, container);
|
callback(null, container);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -137,22 +179,64 @@ var convertVolumeObjToArray = function (obj) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Docker.getImageData = function (imageId, callback) {
|
Docker.getImageData = function (imageId, callback) {
|
||||||
var image = docker.getImage(imageId.toLowerCase());
|
docker.listImages({all: false}, function (err, images) {
|
||||||
image.inspect(function (err, data) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
data.Config.Volumes = convertVolumeObjToArray(data.Config.Volumes);
|
var dockerImage = _.find(images, function (image) {
|
||||||
data.ContainerConfig.Volumes = convertVolumeObjToArray(data.ContainerConfig.Volumes);
|
return image.Id === imageId;
|
||||||
callback(null, data);
|
});
|
||||||
return;
|
var image = docker.getImage(imageId);
|
||||||
|
image.inspect(function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
callback(err, null);
|
||||||
|
} else {
|
||||||
|
if (data.Config && data.Config.Volumes) {
|
||||||
|
data.Config.Volumes = convertVolumeObjToArray(data.Config.Volumes);
|
||||||
|
}
|
||||||
|
if (data.ContainerConfig && data.ContainerConfig.Volumes) {
|
||||||
|
data.ContainerConfig.Volumes = convertVolumeObjToArray(data.ContainerConfig.Volumes);
|
||||||
|
}
|
||||||
|
if (!dockerImage) {
|
||||||
|
callback(null, data);
|
||||||
|
} else {
|
||||||
|
callback(null, _.extend(dockerImage, data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Docker.listImages = function (callback) {
|
||||||
|
docker.listImages({all: false}, function (err, images) {
|
||||||
|
if (err) {
|
||||||
|
callback(err, null);
|
||||||
|
} else {
|
||||||
|
var cbList = _.map(images, function (image) {
|
||||||
|
return function (cb) {
|
||||||
|
Docker.getImageData(image.Id, function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
cb(err, null);
|
||||||
|
} else {
|
||||||
|
cb(null, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
async.parallel(cbList, function (err, results) {
|
||||||
|
if (err) {
|
||||||
|
callback(err, null);
|
||||||
|
} else {
|
||||||
|
callback(null, results);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Docker.removeImage = function (imageId, callback) {
|
Docker.removeImage = function (imageId, callback) {
|
||||||
var image = docker.getImage(imageId.toLowerCase());
|
var image = docker.getImage(imageId);
|
||||||
image.remove({force: true}, function (err) {
|
image.remove({force: true}, function (err) {
|
||||||
if (err) { callback(err); return; }
|
if (err) { callback(err); return; }
|
||||||
console.log('Deleted image: ' + imageId);
|
console.log('Deleted image: ' + imageId);
|
||||||
|
@ -211,7 +295,7 @@ Docker.resolveDefaultImages = function () {
|
||||||
image.inspect(function (err) {
|
image.inspect(function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.reason === 'no such image') {
|
if (err.reason === 'no such image') {
|
||||||
docker.loadImage(path.join(Util.getBinDir(), 'base-images.tar.gz'), {}, function (err) {
|
docker.loadImage(path.join(Util.getBinDir(), Docker.DEFAULT_IMAGES_FILENAME), {}, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
innerCallback(err);
|
innerCallback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -270,6 +354,7 @@ Docker.reloadDefaultContainers = function (callback) {
|
||||||
async.until(function () {
|
async.until(function () {
|
||||||
return ready;
|
return ready;
|
||||||
}, function (callback) {
|
}, function (callback) {
|
||||||
|
docker = Docker.client();
|
||||||
docker.listContainers(function (err) {
|
docker.listContainers(function (err) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
ready = true;
|
ready = true;
|
||||||
|
|
|
@ -44,9 +44,13 @@ ImageUtil.getMetaData = function (directory) {
|
||||||
if (!kiteJSON.name) {
|
if (!kiteJSON.name) {
|
||||||
kiteJSON.name = _.last(directory.split(path.sep));
|
kiteJSON.name = _.last(directory.split(path.sep));
|
||||||
}
|
}
|
||||||
|
if (!kiteJSON.version) {
|
||||||
|
kiteJSON.version = 'latest';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
kiteJSON = {
|
kiteJSON = {
|
||||||
name: _.last(directory.split(path.sep))
|
name: _.last(directory.split(path.sep)),
|
||||||
|
version: 'latest'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return kiteJSON;
|
return kiteJSON;
|
||||||
|
@ -196,7 +200,7 @@ ImageUtil.build = function (image, callback) {
|
||||||
buildLogs: []
|
buildLogs: []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
docker.buildImage(tarFilePath, {t: image._id.toLowerCase()}, function (err, response) {
|
docker.buildImage(tarFilePath, {t: image.meta.name + ':' + image.meta.version}, function (err, response) {
|
||||||
if (err) { callback(err); }
|
if (err) { callback(err); }
|
||||||
console.log('Building Docker image...');
|
console.log('Building Docker image...');
|
||||||
response.setEncoding('utf8');
|
response.setEncoding('utf8');
|
||||||
|
@ -221,8 +225,10 @@ ImageUtil.build = function (image, callback) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
var imageData = null;
|
var imageData = null;
|
||||||
Docker.getImageData(image._id, function (err, data) {
|
Docker.getImageData(image.meta.name + ':' + image.meta.version, function (err, data) {
|
||||||
|
console.log(data);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
Images.update(image._id, {
|
Images.update(image._id, {
|
||||||
$set: {
|
$set: {
|
||||||
status: 'ERROR'
|
status: 'ERROR'
|
||||||
|
@ -252,3 +258,97 @@ ImageUtil.build = function (image, callback) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ImageUtil.remove = function (imageId) {
|
||||||
|
var image = Images.findOne(imageId);
|
||||||
|
Images.remove({_id: image._id});
|
||||||
|
if (image.docker) {
|
||||||
|
Docker.removeImage(image.docker.Id, function (err) {
|
||||||
|
if (err) { console.error(err); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Util.deleteFolder(image.path);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
Sync.removeAppWatcher(imageId);
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageUtil.sync = function () {
|
||||||
|
Docker.listImages(function (err, dockerImages) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
|
if (image.docker && image.docker.Id) {
|
||||||
|
return image.docker.Id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var imageIds = _.map(dockerImages, function (image) {
|
||||||
|
return image.Id;
|
||||||
|
});
|
||||||
|
var diffImages = _.difference(dockerIds, imageIds);
|
||||||
|
_.each(diffImages, function (imageId) {
|
||||||
|
var image = Images.findOne({'docker.Id': imageId});
|
||||||
|
if (image && image.status !== 'BUILDING') {
|
||||||
|
ImageUtil.remove(image._id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var diffDockerImages = _.reject(dockerImages, function (image) {
|
||||||
|
return _.contains(dockerIds, image.Id);
|
||||||
|
});
|
||||||
|
_.each(diffDockerImages, function (image) {
|
||||||
|
var repoTag = _.first(image.RepoTags);
|
||||||
|
var repoTagTokens = repoTag.split(':');
|
||||||
|
var name = repoTagTokens[0];
|
||||||
|
var version = repoTagTokens[1];
|
||||||
|
var buildingImage = _.find(images, function (image) {
|
||||||
|
return image.status === 'BUILDING' && image.meta.name === name && image.meta.version === version;
|
||||||
|
});
|
||||||
|
if (!buildingImage && name !== '<none>' && version !== '<none>' && name !== 'kite-dns') {
|
||||||
|
var imageObj = {
|
||||||
|
status: 'READY',
|
||||||
|
docker: image,
|
||||||
|
buildLogs: [],
|
||||||
|
createdAt: new Date(),
|
||||||
|
tags: image.RepoTags,
|
||||||
|
meta: {
|
||||||
|
name: name,
|
||||||
|
version: version
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(imageObj);
|
||||||
|
Images.insert(imageObj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -38,7 +38,6 @@ Installer.steps = [
|
||||||
progressCallback(progress);
|
progressCallback(progress);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Version 4.3.12 is required.
|
|
||||||
VirtualBox.version(function (err, installedVersion) {
|
VirtualBox.version(function (err, installedVersion) {
|
||||||
if (err) {callback(err); return;}
|
if (err) {callback(err); return;}
|
||||||
if (Util.compareVersions(installedVersion, VirtualBox.REQUIRED_VERSION) < 0) {
|
if (Util.compareVersions(installedVersion, VirtualBox.REQUIRED_VERSION) < 0) {
|
||||||
|
@ -65,7 +64,7 @@ Installer.steps = [
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pastMessage: 'VirtualBox installed',
|
pastMessage: 'VirtualBox Installed',
|
||||||
message: 'Downloading & Installing VirtualBox',
|
message: 'Downloading & Installing VirtualBox',
|
||||||
futureMessage: 'Download & Install VirtualBox if necessary'
|
futureMessage: 'Download & Install VirtualBox if necessary'
|
||||||
},
|
},
|
||||||
|
@ -76,7 +75,7 @@ Installer.steps = [
|
||||||
Boot2Docker.exists(function (err, exists) {
|
Boot2Docker.exists(function (err, exists) {
|
||||||
if (err) { callback(err); return; }
|
if (err) { callback(err); return; }
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
var vmFilesPath = path.join(Util.getHomePath(), 'VirtualBox VMs', 'kitematic-vm');
|
var vmFilesPath = path.join(Util.getHomePath(), 'VirtualBox\ VMs', 'kitematic-vm');
|
||||||
if (fs.existsSync(vmFilesPath)) {
|
if (fs.existsSync(vmFilesPath)) {
|
||||||
Util.deleteFolder(vmFilesPath);
|
Util.deleteFolder(vmFilesPath);
|
||||||
}
|
}
|
||||||
|
@ -92,7 +91,7 @@ Installer.steps = [
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -120,10 +119,16 @@ Installer.steps = [
|
||||||
if (state !== 'running') {
|
if (state !== 'running') {
|
||||||
console.log('starting');
|
console.log('starting');
|
||||||
Boot2Docker.start(function (err) {
|
Boot2Docker.start(function (err) {
|
||||||
callback(err);
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Boot2Docker.setIp('eth1', Boot2Docker.REQUIRED_IP, function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Boot2Docker.setIp('eth2', Boot2Docker.REQUIRED_IP, function(err) {
|
Boot2Docker.setIp('eth1', Boot2Docker.REQUIRED_IP, function(err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ Router.configure({
|
||||||
SetupController = RouteController.extend({
|
SetupController = RouteController.extend({
|
||||||
layoutTemplate: 'setup_layout',
|
layoutTemplate: 'setup_layout',
|
||||||
waitOn: function () {
|
waitOn: function () {
|
||||||
return [Meteor.subscribe('installs'), Meteor.subscribe('settings')];
|
return [Meteor.subscribe('apps'), Meteor.subscribe('images'), Meteor.subscribe('installs'), Meteor.subscribe('settings')];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,25 @@ var nodeCrypto = require('crypto');
|
||||||
var request = require('request');
|
var request = require('request');
|
||||||
var progress = require('request-progress');
|
var progress = require('request-progress');
|
||||||
var ncp = require('ncp').ncp;
|
var ncp = require('ncp').ncp;
|
||||||
|
var exec = require('exec');
|
||||||
ncp.limit = 16;
|
ncp.limit = 16;
|
||||||
|
|
||||||
Util = {};
|
Util = {};
|
||||||
|
|
||||||
|
Util.refreshDNS = function (app, callback) {
|
||||||
|
// Use dig to refresh the DNS
|
||||||
|
exec('/usr/bin/dig ' + app.name + '.kite @172.17.42.1', function (err, stdout, stderr) {
|
||||||
|
console.log(err);
|
||||||
|
console.log(stdout);
|
||||||
|
console.log(stderr);
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Util.getHomePath = function () {
|
Util.getHomePath = function () {
|
||||||
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
|
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
|
||||||
};
|
};
|
||||||
|
@ -56,17 +71,21 @@ Util.copyFolder = function (src, dest, callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Util.copyVolumes = function (directory, appName, callback) {
|
Util.copyVolumes = function (directory, appName, callback) {
|
||||||
var volumesPath = path.join(directory, 'volumes');
|
if (directory) {
|
||||||
if (fs.existsSync(volumesPath)) {
|
var volumesPath = path.join(directory, 'volumes');
|
||||||
var destinationPath = path.join(Util.KITE_PATH, appName);
|
if (fs.existsSync(volumesPath)) {
|
||||||
Util.copyFolder(volumesPath, destinationPath, function (err) {
|
var destinationPath = path.join(Util.KITE_PATH, appName);
|
||||||
if (err) {
|
Util.copyFolder(volumesPath, destinationPath, function (err) {
|
||||||
callback(err);
|
if (err) {
|
||||||
return;
|
callback(err);
|
||||||
}
|
return;
|
||||||
console.log('Copied volumes for: ' + appName);
|
}
|
||||||
|
console.log('Copied volumes for: ' + appName);
|
||||||
|
callback(null);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ var path = require('path');
|
||||||
|
|
||||||
VirtualBox = {};
|
VirtualBox = {};
|
||||||
|
|
||||||
VirtualBox.REQUIRED_VERSION = '4.3.14';
|
VirtualBox.REQUIRED_VERSION = '4.3.18';
|
||||||
VirtualBox.INCLUDED_VERSION = '4.3.14';
|
VirtualBox.INCLUDED_VERSION = '4.3.18';
|
||||||
VirtualBox.INSTALLER_FILENAME = 'virtualbox-4.3.14.pkg';
|
VirtualBox.INSTALLER_FILENAME = 'virtualbox-4.3.18.pkg';
|
||||||
VirtualBox.INSTALLER_CHECKSUM = '486348a5336539728ca20dcd9674cf3d37e5c7f32255d90f1edc7391b54bd5dd'; // Sha256 Checksum
|
VirtualBox.INSTALLER_CHECKSUM = '5836c94481c460c648b9216386591a2915293ac86b9bb6c57746637796af6af2'; // Sha256 Checksum
|
||||||
|
|
||||||
// Info for the hostonly interface we add to the VM.
|
// Info for the hostonly interface we add to the VM.
|
||||||
VirtualBox.HOSTONLY_HOSTIP = '192.168.60.3';
|
VirtualBox.HOSTONLY_HOSTIP = '192.168.60.3';
|
||||||
|
@ -129,7 +129,7 @@ VirtualBox.addCustomHostAdapter = function (vm, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.hostOnlyAdapter(function (err, ifname) {
|
self.hostOnlyAdapter(function (err, ifname) {
|
||||||
if (err) { callback(err); return; }
|
if (err) { callback(err); return; }
|
||||||
self.exec('modifyvm ' + vm + ' --nic3 hostonly --nictype3 virtio --cableconnected3 on --hostonlyadapter3 ' + ifname, function (err, stdout, stderr) {
|
self.exec('modifyvm ' + vm + ' --nic2 hostonly --nictype2 virtio --cableconnected2 on --hostonlyadapter2 ' + ifname, function (err, stdout, stderr) {
|
||||||
callback(err, ifname);
|
callback(err, ifname);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -67,6 +67,14 @@ Handlebars.registerHelper('isUpdating', function () {
|
||||||
return Session.get('isUpdating');
|
return Session.get('isUpdating');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper('displayTags', function (tags, delimiter) {
|
||||||
|
if (tags) {
|
||||||
|
return tags.join(delimiter);
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var fixBoot2DockerVM = function (callback) {
|
var fixBoot2DockerVM = function (callback) {
|
||||||
Boot2Docker.check(function (err) {
|
Boot2Docker.check(function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -124,40 +132,33 @@ var fixDefaultContainers = function (callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Meteor.setInterval(function () {
|
Meteor.setInterval(function () {
|
||||||
Boot2Docker.exists(function (err, exists) {
|
if (!Session.get('installing')) {
|
||||||
if (err) { console.log(err); return; }
|
Boot2Docker.exists(function (err, exists) {
|
||||||
if (exists) {
|
if (err) { console.log(err); return; }
|
||||||
Boot2Docker.state(function (err, state) {
|
if (exists) {
|
||||||
if (err) { console.log(err); return; }
|
Boot2Docker.state(function (err, state) {
|
||||||
Session.set('boot2dockerState', state);
|
if (err) { console.log(err); return; }
|
||||||
if (state === 'running') {
|
Session.set('boot2dockerState', state);
|
||||||
Boot2Docker.stats(function (err, stats) {
|
if (state === 'running') {
|
||||||
if (err) { console.log(err); return; }
|
Boot2Docker.stats(function (err, stats) {
|
||||||
if (stats.state !== 'poweroff' && stats.memory && stats.disk) {
|
if (err) { console.log(err); return; }
|
||||||
Session.set('boot2dockerMemoryUsage', stats.memory);
|
if (stats.state !== 'poweroff' && stats.memory && stats.disk) {
|
||||||
Session.set('boot2dockerDiskUsage', stats.disk);
|
Session.set('boot2dockerMemoryUsage', stats.memory);
|
||||||
}
|
Session.set('boot2dockerDiskUsage', stats.disk);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
Meteor.setInterval(function () {
|
Meteor.setInterval(function () {
|
||||||
if (!Session.get('installing')) {
|
if (!Session.get('installing')) {
|
||||||
Sync.resolveWatchers(function () {});
|
Sync.resolveWatchers(function () {});
|
||||||
if (!Session.get('boot2dockerOff')) {
|
ImageUtil.sync();
|
||||||
fixBoot2DockerVM(function (err) {
|
AppUtil.sync();
|
||||||
if (err) { console.log(err); return; }
|
AppUtil.recover();
|
||||||
AppUtil.recover();
|
|
||||||
fixDefaultImages(function (err) {
|
|
||||||
if (err) { console.log(err); return; }
|
|
||||||
fixDefaultContainers(function (err) {
|
|
||||||
if (err) { console.log(err); }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
|
@ -9,24 +9,26 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="padded">
|
<div class="content">
|
||||||
{{#if hasItem apps}}
|
<div class="padded">
|
||||||
<div class="apps line-item-collection">
|
{{#if hasItem apps}}
|
||||||
{{#each apps}}
|
<div class="apps line-item-collection">
|
||||||
{{> dashboard_single_app}}
|
{{#each apps}}
|
||||||
{{/each}}
|
{{> dashboard_single_app}}
|
||||||
</div>
|
{{/each}}
|
||||||
{{else}}
|
</div>
|
||||||
<div class="empty-placeholder">
|
{{else}}
|
||||||
<div class="big-icon"><i class="fa fa-cube"></i></div>
|
<div class="empty-placeholder">
|
||||||
<h4>There are no apps yet.</h4>
|
<div class="big-icon"><i class="fa fa-cube"></i></div>
|
||||||
{{#if $.Session.equals 'boot2dockerState' 'poweroff'}}
|
<h4>There are no apps yet.</h4>
|
||||||
<a href="#" data-toggle="modal" data-target="#modal-create-app" class="btn btn-action" disabled="disabled"><span class="typcn typcn-plus-outline"></span> Create App</a>
|
{{#if $.Session.equals 'boot2dockerState' 'poweroff'}}
|
||||||
{{else}}
|
<a href="#" data-toggle="modal" data-target="#modal-create-app" class="btn btn-action" disabled="disabled"><span class="typcn typcn-plus-outline"></span> Create App</a>
|
||||||
<a href="#" onclick="trackLink('create app')" data-toggle="modal" data-target="#modal-create-app" class="btn btn-action"><span class="typcn typcn-plus-outline"></span> Create App</a>
|
{{else}}
|
||||||
{{/if}}
|
<a href="#" onclick="trackLink('create app')" data-toggle="modal" data-target="#modal-create-app" class="btn btn-action"><span class="typcn typcn-plus-outline"></span> Create App</a>
|
||||||
</div>
|
{{/if}}
|
||||||
{{/if}}
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{> modal_create_app}}
|
{{> modal_create_app}}
|
||||||
{{> modal_create_image}}
|
{{> modal_create_image}}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a onclick="trackLink('app detail')" href="/apps/{{name}}" class="name">{{name}}</a>
|
<a onclick="trackLink('app detail')" href="/apps/{{name}}" class="name">{{name}}</a>
|
||||||
<small><a onclick="trackLink('app image detail')" href="/images/{{image._id}}">{{image.meta.name}}</a></small>
|
<small><a onclick="trackLink('app image detail')" href="/images/{{image._id}}">{{displayTags image.tags}}</a></small>
|
||||||
</h5>
|
</h5>
|
||||||
<div class="options">
|
<div class="options">
|
||||||
{{#if $eq status 'READY'}}
|
{{#if $eq status 'READY'}}
|
||||||
|
|
|
@ -3,7 +3,7 @@ var path = require('path');
|
||||||
|
|
||||||
Template.modal_create_app.helpers({
|
Template.modal_create_app.helpers({
|
||||||
images: function () {
|
images: function () {
|
||||||
return Images.find({status: 'READY'}, {sort: {createdAt: -1}});
|
return Images.find({status: 'READY', 'docker.Config.ExposedPorts': {$ne: null}}, {sort: {createdAt: -1}});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,11 +36,6 @@ Template.modal_create_app.events({
|
||||||
createdAt: new Date()
|
createdAt: new Date()
|
||||||
};
|
};
|
||||||
var appId = Apps.insert(appObj);
|
var appId = Apps.insert(appObj);
|
||||||
Apps.update(appId, {
|
|
||||||
$set: {
|
|
||||||
'config.APP_ID': appId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var app = Apps.findOne(appId);
|
var app = Apps.findOne(appId);
|
||||||
var image = Images.findOne(app.imageId);
|
var image = Images.findOne(app.imageId);
|
||||||
Util.copyVolumes(image.path, app.name, function (err) {
|
Util.copyVolumes(image.path, app.name, function (err) {
|
||||||
|
|
|
@ -49,6 +49,7 @@ Template.modal_create_image.events({
|
||||||
};
|
};
|
||||||
var imageMetaData = ImageUtil.getMetaData(directory);
|
var imageMetaData = ImageUtil.getMetaData(directory);
|
||||||
imageObj.meta = imageMetaData;
|
imageObj.meta = imageMetaData;
|
||||||
|
imageObj.tags = [imageMetaData.name + ':' + imageMetaData.version];
|
||||||
var imageId = Images.insert(imageObj);
|
var imageId = Images.insert(imageObj);
|
||||||
var imagePath = path.join(Util.KITE_IMAGES_PATH, imageId);
|
var imagePath = path.join(Util.KITE_IMAGES_PATH, imageId);
|
||||||
Images.update(imageId, {
|
Images.update(imageId, {
|
||||||
|
|
|
@ -11,21 +11,9 @@ Template.dashboard_images_settings.events({
|
||||||
if (index !== 0) {
|
if (index !== 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var image = Images.findOne(imageId);
|
|
||||||
var app = Apps.findOne({imageId: imageId});
|
var app = Apps.findOne({imageId: imageId});
|
||||||
if (!app) {
|
if (!app) {
|
||||||
Images.remove({_id: image._id});
|
ImageUtil.remove(imageId);
|
||||||
if (image.docker) {
|
|
||||||
Docker.removeImage(image.docker.Id, function (err) {
|
|
||||||
if (err) { console.error(err); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Util.deleteFolder(image.path);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
Sync.removeAppWatcher(imageId);
|
|
||||||
Router.go('dashboard_images');
|
Router.go('dashboard_images');
|
||||||
} else {
|
} else {
|
||||||
$('#error-delete-image').html('<small class="error">This image is currently being used by <a href="/apps/' + app.name + '">' + app.name + '</a>.</small>');
|
$('#error-delete-image').html('<small class="error">This image is currently being used by <a href="/apps/' + app.name + '">' + app.name + '</a>.</small>');
|
||||||
|
|
|
@ -9,24 +9,26 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="padded">
|
<div class="content">
|
||||||
{{#if hasItem images}}
|
<div class="padded">
|
||||||
<div class="images line-item-collection">
|
{{#if hasItem images}}
|
||||||
{{#each images}}
|
<div class="images line-item-collection">
|
||||||
{{> dashboard_single_image}}
|
{{#each images}}
|
||||||
{{/each}}
|
{{> dashboard_single_image}}
|
||||||
</div>
|
{{/each}}
|
||||||
{{else}}
|
</div>
|
||||||
<div class="empty-placeholder">
|
{{else}}
|
||||||
<div class="big-icon"><i class="fa fa-camera"></i></div>
|
<div class="empty-placeholder">
|
||||||
<h4>There are no images yet.</h4>
|
<div class="big-icon"><i class="fa fa-camera"></i></div>
|
||||||
{{#if $.Session.equals 'boot2dockerState' 'poweroff'}}
|
<h4>There are no images yet.</h4>
|
||||||
<a href="#" data-toggle="modal" data-target="#modal-create-image" class="btn btn-action" disabled="disabled"><span class="typcn typcn-plus-outline"></span> Create Image</a>
|
{{#if $.Session.equals 'boot2dockerState' 'poweroff'}}
|
||||||
{{else}}
|
<a href="#" data-toggle="modal" data-target="#modal-create-image" class="btn btn-action" disabled="disabled"><span class="typcn typcn-plus-outline"></span> Create Image</a>
|
||||||
<a href="#" onclick="trackLink('create image')" data-toggle="modal" data-target="#modal-create-image" class="btn btn-action"><span class="typcn typcn-plus-outline"></span>Create Image</a>
|
{{else}}
|
||||||
{{/if}}
|
<a href="#" onclick="trackLink('create image')" data-toggle="modal" data-target="#modal-create-image" class="btn btn-action"><span class="typcn typcn-plus-outline"></span>Create Image</a>
|
||||||
</div>
|
{{/if}}
|
||||||
{{/if}}
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{> modal_create_app}}
|
{{> modal_create_app}}
|
||||||
{{> modal_create_image}}
|
{{> modal_create_image}}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a onclick="trackLink('image detail')" href="/images/{{_id}}" class="name">{{meta.name}}</a>
|
<a onclick="trackLink('image detail')" href="/images/{{_id}}" class="name">{{displayTags tags ', '}}</a>
|
||||||
{{#if $eq status 'BUILDING'}}
|
{{#if $eq status 'BUILDING'}}
|
||||||
<small>Creating image. This may take a couple minutes...</small>
|
<small>Creating image. This may take a couple minutes...</small>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -27,11 +27,17 @@
|
||||||
</h5>
|
</h5>
|
||||||
<div class="options">
|
<div class="options">
|
||||||
{{#if $eq status 'READY'}}
|
{{#if $eq status 'READY'}}
|
||||||
<a onclick="trackLink('create app from image')" href="#" class="btn-icon btn-create-app" data-toggle="tooltip" data-placement="bottom" title="Create App"><span class="typcn typcn-plus-outline"></span></a>
|
{{#if hasExposedPort}}
|
||||||
|
<a onclick="trackLink('create app from image')" href="#" class="btn-icon btn-create-app" data-toggle="tooltip" data-placement="bottom" title="Create App"><span class="typcn typcn-plus-outline"></span></a>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if originPath}}
|
||||||
|
<a onclick="trackLink('open image folder')" href="#" class="btn-icon btn-folder" target="_blank" data-toggle="tooltip" data-placement="bottom" title="Folder"><span class="typcn typcn-folder-open"></span></a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a onclick="trackLink('open image folder')" href="#" class="btn-icon btn-folder" target="_blank" data-toggle="tooltip" data-placement="bottom" title="Folder"><span class="typcn typcn-folder-open"></span></a>
|
|
||||||
{{#if $neq status 'BUILDING'}}
|
{{#if $neq status 'BUILDING'}}
|
||||||
<a onclick="trackLink('rebuild image')" href="#" class="btn-icon btn-rebuild" target="_blank" data-toggle="tooltip" data-placement="bottom" title="Rebuild"><span class="typcn typcn-refresh-outline"></span></a>
|
{{#if originPath}}
|
||||||
|
<a onclick="trackLink('rebuild image')" href="#" class="btn-icon btn-rebuild" target="_blank" data-toggle="tooltip" data-placement="bottom" title="Rebuild"><span class="typcn typcn-refresh-outline"></span></a>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a onclick="trackLink('image logs')" href="/images/{{_id}}/logs" class="btn-icon" data-toggle="tooltip" data-placement="bottom" title="Logs"><span class="typcn typcn-document-text"></span></a>
|
<a onclick="trackLink('image logs')" href="/images/{{_id}}/logs" class="btn-icon" data-toggle="tooltip" data-placement="bottom" title="Logs"><span class="typcn typcn-document-text"></span></a>
|
||||||
<a onclick="trackLink('image settings')" href="/images/{{_id}}/settings" class="btn-icon" data-toggle="tooltip" data-placement="bottom" title="Settings"><span class="typcn typcn-cog-outline"></span></a>
|
<a onclick="trackLink('image settings')" href="/images/{{_id}}/settings" class="btn-icon" data-toggle="tooltip" data-placement="bottom" title="Settings"><span class="typcn typcn-cog-outline"></span></a>
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
<a onclick="trackLink('view app')" href="{{url}}" class="btn-view" target="_blank" data-toggle="tooltip" data-placement="bottom" title="View App" data-container="body"><span class="typcn typcn-eye-outline"></span></a>
|
<a onclick="trackLink('view app')" href="{{url}}" class="btn-view" target="_blank" data-toggle="tooltip" data-placement="bottom" title="View App" data-container="body"><span class="typcn typcn-eye-outline"></span></a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a onclick="trackLink('terminal into app')" href="#" class="btn-terminal" data-toggle="tooltip" data-placement="bottom" title="Terminal" data-container="body"><span class="typcn typcn-device-laptop"></span></a>
|
<a onclick="trackLink('terminal into app')" href="#" class="btn-terminal" data-toggle="tooltip" data-placement="bottom" title="Terminal" data-container="body"><span class="typcn typcn-device-laptop"></span></a>
|
||||||
<a onclick="trackLink('go to app image')" href="/images/{{image._id}}" class="btn-image" data-toggle="tooltip" data-placement="bottom" title="Image" data-container="body"><span class="typcn typcn-camera-outline"></span></a>
|
{{#if image}}
|
||||||
|
<a onclick="trackLink('go to app image')" href="/images/{{image._id}}" class="btn-image" data-toggle="tooltip" data-placement="bottom" title="Image" data-container="body"><span class="typcn typcn-camera-outline"></span></a>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a onclick="trackLink('open app folder')" href="#" class="btn-folder" target="_blank" data-toggle="tooltip" data-placement="bottom" title="Folder" data-container="body"><span class="typcn typcn-folder-open"></span></a>
|
<a onclick="trackLink('open app folder')" href="#" class="btn-folder" target="_blank" data-toggle="tooltip" data-placement="bottom" title="Folder" data-container="body"><span class="typcn typcn-folder-open"></span></a>
|
||||||
{{#if $eq status 'READY'}}
|
{{#if $eq status 'READY'}}
|
||||||
|
|
|
@ -12,11 +12,17 @@
|
||||||
<a href="/images" onclick="trackLink('back to images')">Images</a> » {{this.meta.name}}
|
<a href="/images" onclick="trackLink('back to images')">Images</a> » {{this.meta.name}}
|
||||||
<span class="icons">
|
<span class="icons">
|
||||||
{{#if $eq status 'READY'}}
|
{{#if $eq status 'READY'}}
|
||||||
<a onclick="trackLink('create app from image')" href="#" class="btn-create-app" data-toggle="tooltip" data-placement="bottom" title="Create App" data-container="body"><span class="typcn typcn-plus-outline"></span></a>
|
{{#if hasExposedPort}}
|
||||||
|
<a onclick="trackLink('create app from image')" href="#" class="btn-create-app" data-toggle="tooltip" data-placement="bottom" title="Create App" data-container="body"><span class="typcn typcn-plus-outline"></span></a>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if originPath}}
|
||||||
|
<a onclick="trackLink('open image folder')" href="#" class="btn-folder" data-toggle="tooltip" data-placement="bottom" title="Folder" data-container="body"><span class="typcn typcn-folder-open"></span></a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a onclick="trackLink('open image folder')" href="#" class="btn-folder" data-toggle="tooltip" data-placement="bottom" title="Folder" data-container="body"><span class="typcn typcn-folder-open"></span></a>
|
|
||||||
{{#if $neq status 'BUILDING'}}
|
{{#if $neq status 'BUILDING'}}
|
||||||
<a onclick="trackLink('rebuild image')" href="#" class="btn-rebuild" data-toggle="tooltip" data-placement="bottom" title="Rebuild" data-container="body"><span class="typcn typcn-refresh-outline"></span></a>
|
{{#if originPath}}
|
||||||
|
<a onclick="trackLink('rebuild image')" href="#" class="btn-rebuild" data-toggle="tooltip" data-placement="bottom" title="Rebuild" data-container="body"><span class="typcn typcn-refresh-outline"></span></a>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
{{> dashboard_menu}}
|
{{> dashboard_menu}}
|
||||||
<div class="dashboard-body">
|
<div class="dashboard-body">
|
||||||
<div class="mac-window-header"><a href="#">Kitematic</a></div>
|
<div class="mac-window-header"><a href="#">Kitematic</a></div>
|
||||||
<div class="content longer">
|
{{> yield}}
|
||||||
{{> yield}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -56,13 +56,11 @@ Template.dashboard_settings.events({
|
||||||
Template.dashboard_settings.helpers({
|
Template.dashboard_settings.helpers({
|
||||||
settings: function () {
|
settings: function () {
|
||||||
return Settings.findOne({});
|
return Settings.findOne({});
|
||||||
|
},
|
||||||
|
memory: function () {
|
||||||
|
return Session.get('boot2dockerMemoryUsage');
|
||||||
|
},
|
||||||
|
disk: function () {
|
||||||
|
return Session.get('boot2dockerDiskUsage');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.dashboard_settings.memory = function () {
|
|
||||||
return Session.get('boot2dockerMemoryUsage');
|
|
||||||
};
|
|
||||||
|
|
||||||
Template.dashboard_settings.disk = function () {
|
|
||||||
return Session.get('boot2dockerDiskUsage');
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
Template.setup_install.steps = function () {
|
Template.setup_install.helpers({
|
||||||
return Installer.steps.map(function (step, index) {
|
steps: function () {
|
||||||
step.index = index;
|
return Installer.steps.map(function (step, index) {
|
||||||
return step;
|
step.index = index;
|
||||||
});
|
return step;
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Template.setup_install.helpers({
|
Template.setup_install.helpers({
|
||||||
currentInstallStep: function () {
|
currentInstallStep: function () {
|
||||||
|
|
|
@ -24,7 +24,11 @@ Apps.allow({
|
||||||
|
|
||||||
Apps.helpers({
|
Apps.helpers({
|
||||||
image: function () {
|
image: function () {
|
||||||
return Images.findOne(this.imageId);
|
if (this.docker && this.docker.Image) {
|
||||||
|
return Images.findOne({'docker.Id': this.docker.Image});
|
||||||
|
} else {
|
||||||
|
return Images.findOne(this.imageId);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
hostUrl: function () {
|
hostUrl: function () {
|
||||||
return this.name + '.kite';
|
return this.name + '.kite';
|
||||||
|
|
|
@ -19,6 +19,9 @@ Images.helpers({
|
||||||
} else {
|
} else {
|
||||||
return '100%';
|
return '100%';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
hasExposedPort: function () {
|
||||||
|
return this.docker && this.docker.Config && this.docker.Config.ExposedPorts;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ansi-to-html": "0.2.0",
|
||||||
"async": "^0.9.0",
|
"async": "^0.9.0",
|
||||||
"chokidar": "git+https://github.com/usekite/chokidar.git",
|
"chokidar": "git+https://github.com/usekite/chokidar.git",
|
||||||
|
"dockerode": "2.0.3",
|
||||||
"exec": "^0.1.2",
|
"exec": "^0.1.2",
|
||||||
"moment": "2.8.1",
|
"moment": "2.8.1",
|
||||||
|
"ncp": "0.6.0",
|
||||||
"open": "0.0.5",
|
"open": "0.0.5",
|
||||||
"dockerode": "2.0.3",
|
|
||||||
"tar": "0.1.20",
|
|
||||||
"ansi-to-html": "0.2.0",
|
|
||||||
"request": "2.42.0",
|
"request": "2.42.0",
|
||||||
"request-progress": "0.3.1",
|
"request-progress": "0.3.1",
|
||||||
"ncp": "0.6.0"
|
"tar": "0.1.20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ mkdir -p cache
|
||||||
|
|
||||||
pushd cache
|
pushd cache
|
||||||
|
|
||||||
BOOT2DOCKER_CLI_VERSION=1.2.0
|
BOOT2DOCKER_CLI_VERSION=1.3.0
|
||||||
BOOT2DOCKER_CLI_VERSION_FILE=boot2docker-$BOOT2DOCKER_CLI_VERSION
|
BOOT2DOCKER_CLI_VERSION_FILE=boot2docker-$BOOT2DOCKER_CLI_VERSION
|
||||||
BOOT2DOCKER_CLI_FILE=boot2docker
|
BOOT2DOCKER_CLI_FILE=boot2docker
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ pushd resources
|
||||||
|
|
||||||
if [ ! -f $BOOT2DOCKER_CLI_VERSION_FILE ]; then
|
if [ ! -f $BOOT2DOCKER_CLI_VERSION_FILE ]; then
|
||||||
cecho "-----> Downloading Boot2docker CLI..." $purple
|
cecho "-----> Downloading Boot2docker CLI..." $purple
|
||||||
curl -L -o $BOOT2DOCKER_CLI_VERSION_FILE https://s3.amazonaws.com/kite-installer/boot2docker-v$BOOT2DOCKER_CLI_VERSION
|
curl -L -o $BOOT2DOCKER_CLI_VERSION_FILE https://github.com/boot2docker/boot2docker-cli/releases/download/v${BOOT2DOCKER_CLI_VERSION}/boot2docker-v${BOOT2DOCKER_CLI_VERSION}-darwin-amd64
|
||||||
fi
|
fi
|
||||||
|
|
||||||
chmod +x $BOOT2DOCKER_CLI_VERSION_FILE
|
chmod +x $BOOT2DOCKER_CLI_VERSION_FILE
|
||||||
|
|
Loading…
Reference in New Issue