diff --git a/meteor/client/lib/boot2docker.js b/meteor/client/lib/boot2docker.js
index 281d79c0c0..879fb42a76 100644
--- a/meteor/client/lib/boot2docker.js
+++ b/meteor/client/lib/boot2docker.js
@@ -1,14 +1,54 @@
var exec = require('exec');
var path = require('path');
-boot2dockerexec = function (command, callback) {
- exec(path.join(getBinDir(), 'boot2docker') + ' ' + command, function(err, stdout) {
- callback(err, stdout);
+Boot2Docker = {};
+
+Boot2Docker.REQUIRED_IP = '192.168.60.103';
+
+Boot2Docker.exec = function (command, callback) {
+ exec(path.join(getBinDir(), 'boot2docker') + ' ' + command, function(err, stdout, stderr) {
+ callback(err, stdout, stderr);
});
};
-getBoot2DockerIp = function (callback) {
- boot2dockerexec('ip', function (err, stdout) {
+Boot2Docker.exists = function (callback) {
+ this.exec('info', function (err) {
+ if (err) {
+ callback(null, false);
+ } else {
+ callback(null, true);
+ }
+ });
+};
+
+Boot2Docker.stop = function (callback) {
+ this.exec('stop', function (err, stdout) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null);
+ }
+ });
+};
+
+Boot2Docker.erase = function (callback) {
+ var VMFileLocation = path.join(getHomePath(), 'VirtualBox\\ VMs/boot2docker-vm');
+ exec('rm -rf ' + VMFileLocation, function (err) {
+ callback(err);
+ });
+};
+
+Boot2Docker.upgrade = function (callback) {
+ var self = this;
+ self.stop(function (err) {
+ self.exec('upgrade', function (err, stdout) {
+ callback(err);
+ });
+ });
+};
+
+Boot2Docker.ip = function (callback) {
+ this.exec('ip', function (err, stdout) {
if (err) {
callback(err, null);
} else {
@@ -17,8 +57,51 @@ getBoot2DockerIp = function (callback) {
});
};
-getBoot2DockerState = function (callback) {
- boot2dockerexec(' info', function (err, stdout) {
+Boot2Docker.setIp = function (ifname, ip, callback) {
+ this.exec('ssh "sudo ifconfig ' + ifname + ' ' + ip + ' netmask 255.255.255.0"', function (err, stdout) {
+ callback(err);
+ });
+};
+
+Boot2Docker.init = function (callback) {
+ this.exec('init', function (err) {
+ callback(err);
+ });
+};
+
+Boot2Docker.start = function (callback) {
+ var self = this;
+ self.exists(function (err, exists) {
+ if (!exists) {
+ callback('Cannot start if the boot2docker VM doesn\'t exist');
+ return;
+ }
+ self.exec('up -v', function (err, stdout) {
+ console.log('here0');
+ console.log('here1');
+ // Sometimes boot2docker returns an error code even though it's working / waiting, so treat that as
+ // Success as well
+ if (!err || (err.indexOf('Waiting for VM to be started') !== -1 || err.indexOf('..........') !== -1)) {
+ Boot2Docker.setIp('eth2', Boot2Docker.REQUIRED_IP, function(err) {
+ console.log('here1');
+ if (err) { callback(err); return; }
+ VirtualBox.removeDHCP(function (err) {
+ console.log('here2');
+ self.injectUtilities(function (err) {
+ console.log('here3');
+ callback(err);
+ });
+ });
+ });
+ } else {
+ callback(err);
+ }
+ });
+ });
+};
+
+Boot2Docker.state = function (callback) {
+ this.exec('info', function (err, stdout) {
if (err) {
callback(err, null);
return;
@@ -32,8 +115,8 @@ getBoot2DockerState = function (callback) {
});
};
-getBoot2DockerDiskUsage = function (callback) {
- boot2dockerexec('ssh "df"', function (err, stdout) {
+Boot2Docker.diskUsage = function (callback) {
+ this.exec('ssh "df"', function (err, stdout) {
if (err) {
callback(err, null);
return;
@@ -61,8 +144,8 @@ getBoot2DockerDiskUsage = function (callback) {
});
};
-getBoot2DockerMemoryUsage = function (callback) {
- boot2dockerexec('ssh "free -m"', function (err, stdout) {
+Boot2Docker.memoryUsage = function (callback) {
+ this.exec('ssh "free -m"', function (err, stdout) {
if (err) {
callback(err, null);
return;
@@ -92,152 +175,80 @@ getBoot2DockerMemoryUsage = function (callback) {
});
};
-getBoot2DockerInfo = function (callback) {
- boot2dockerexec('ssh "sudo ifconfig eth1 192.168.59.103 netmask 255.255.255.0"', function (err, stdout) {
- exec('VBoxManage dhcpserver remove --netname HostInterfaceNetworking-vboxnet0', function (err, stdout) {
- getBoot2DockerState(function (err, state) {
+Boot2Docker.stats = function (callback) {
+ this.state(function (err, state) {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+ if (state === 'poweroff') {
+ callback(null, {state: state});
+ return;
+ }
+ this.memoryUsage(function (err, mem) {
if (err) {
- callback(err, null);
+ callback(null, {state: state});
return;
}
- if (state === 'poweroff') {
- callback(null, {state: state});
- } else {
- getBoot2DockerMemoryUsage(function (err, mem) {
- if (err) { callback(null, {state: state}); }
- getBoot2DockerDiskUsage(function (err, disk) {
- if (err) { callback(null, {state: state}); }
- callback(null, {
- state: state,
- memory: mem,
- disk: disk
- });
- });
- });
- }
- });
- });
- });
-};
-
-boot2DockerVMExists = function (callback) {
- boot2dockerexec('info', function (err) {
- if (err) {
- callback(null, false);
- } else {
- callback(null, true);
- }
- });
-};
-
-eraseBoot2DockerVMFiles = function (callback) {
- var VMFileLocation = path.join(getHomePath(), 'VirtualBox\\ VMs/boot2docker-vm');
- exec('rm -rf ' + VMFileLocation, function (err) {
- callback(err);
- });
-};
-
-initBoot2Docker = function (callback) {
- isVirtualBoxInstalled(function (err, installed) {
- if (err) {
- callback(err);
- return;
- }
- if (installed) {
- boot2dockerexec('init', function (err) {
- console.log(err);
+ this.diskUsage(function (err, disk) {
if (err) {
- if (err.indexOf('exit status 1') !== -1) {
- eraseBoot2DockerVMFiles(function () {
- boot2dockerexec('init', function (err) {
- callback(err);
- });
- });
- } else {
- callback(err);
- }
- } else {
- callback();
+ callback(null, {state: state});
+ return;
}
+ callback(null, {
+ state: state,
+ memory: mem,
+ disk: disk
+ });
});
+ });
+ });
+};
+
+/**
+ * Get the VM's version.
+ * Node that this only works if the VM is up and running.
+ */
+Boot2Docker.vmVersion = function (callback) {
+ this.exec('ssh "cat /etc/version', function (err, stdout, stderr) {
+ if (err) {
+ callback(err);
+ return;
} else {
- callback(new Error('initBoot2Docker called but VirtualBox isn\'t installed.'));
+ callback(null, stdout);
}
});
};
-upgradeBoot2Docker = function (callback) {
- boot2dockerexec('upgrade', function (err, stdout) {
- console.log(stdout);
- callback(err);
+Boot2Docker.version = function (callback) {
+ this.exec('version', function (err, stdout, stderr) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ var match = stdout.match(/Client version: v(\d\.\d\.\d)/);
+ if (!match || match.length < 2) {
+ callback('Could not parse the boot2docker cli version.')
+ } else {
+ callback(null, match[1]);
+ }
});
};
-installBoot2DockerAddons = function (callback) {
+Boot2Docker.injectUtilities = function (callback) {
exec('/bin/cat ' + path.join(getBinDir(), 'kite-binaries.tar.gz') + ' | ' + path.join(getBinDir(), 'boot2docker') + ' ssh "tar zx -C /usr/local/bin"', function (err, stdout) {
- console.log(stdout);
callback(err);
});
- exec('VBoxManage modifyvm boot2docker-vm --nic2 hostonly --nictype2 virtio --cableconnected2 on --hostonlyadapter2 vboxnet0', function (err, stdout) {});
- boot2dockerexec('ssh "sudo ifconfig eth1 192.168.59.103 netmask 255.255.255.0"', function (err, stdout) {});
- exec('VBoxManage dhcpserver remove --netname HostInterfaceNetworking-vboxnet0', function (err, stdout) {});
};
-startBoot2Docker = function (callback) {
- isVirtualBoxInstalled(function (err, installed) {
- if (err) {
- callback(err);
- return;
- }
- if (installed) {
- boot2DockerVMExists(function (err, exists) {
- if (exists) {
- boot2dockerexec('up -v', function (err, stdout) {
- console.log(err);
- console.log(stdout);
- if (err) {
- if (err.indexOf('Waiting for VM to be started') !== -1 || err.indexOf('..........') !== -1) {
- installBoot2DockerAddons(function (err) {
- callback(err);
- });
- } else {
- callback(err);
- }
- } else {
- installBoot2DockerAddons(function (err) {
- callback(err);
- });
- }
- });
- } else {
- callback(new Error('startBoot2Docker called but boot2docker-vm doesn\'t exist.'));
- }
- });
- } else {
- callback(new Error('startBoot2Docker called but VirtualBox isn\'t installed.'));
- }
- });
-};
-
-stopBoot2Docker = function (callback) {
- boot2dockerexec('stop', function (err, stdout) {
- console.log(stdout);
- console.log(err);
- if (err) {
- callback(err);
- return;
- }
- callback(null);
- });
-};
-
-checkBoot2DockerVM = function (callback) {
- boot2DockerVMExists(function (err) {
+Boot2Docker.check = function (callback) {
+ var self = this;
+ self.exists(function (err) {
if (err) {
callback(err);
return;
} else {
- getBoot2DockerState(function (err, state) {
+ self.state(function (err, state) {
if (state !== 'running') {
callback('boot2docker not running');
} else {
@@ -248,10 +259,9 @@ checkBoot2DockerVM = function (callback) {
});
};
-// Make sure the VM exists, is up and is running.
-resolveBoot2DockerVM = function (callback) {
- boot2DockerVMExists(function (err, exists) {
-
+Boot2Docker.resolve = function (callback) {
+ var self = this;
+ self.exists(function (err, exists) {
// If somehow the boot2docker VM doesn't exist anymor then re-create it.
if (!exists) {
initBoot2Docker(function () {
@@ -260,9 +270,8 @@ resolveBoot2DockerVM = function (callback) {
});
});
} else {
-
// If it exists but it's not running.. restart it.
- getBoot2DockerState(function (err, state) {
+ self.state(function (err, state) {
if (state !== 'running') {
startBoot2Docker(function (err) {
callback(err);
diff --git a/meteor/client/lib/installer.js b/meteor/client/lib/installer.js
new file mode 100644
index 0000000000..39e043c2b8
--- /dev/null
+++ b/meteor/client/lib/installer.js
@@ -0,0 +1,146 @@
+var async = require('async');
+
+Installer = {};
+
+/**
+ * Install steps. A step is a function that accepts a function (err) callback and returns once that step is complete.keys:
+ * - run: Function that runs the installation step and calls the callback with an error if failed.
+ * - pastMessage: Message to show after step completion
+ * - message: Message to show while step is running
+ * - imperativeMessage: Message to show before running
+ */
+Installer.steps = [
+ {
+ run: function (callback) {
+ var installed = VirtualBox.installed();
+ if (!installed) {
+ VirtualBox.install(function (err) {
+ callback(err);
+ });
+ } else {
+ // Version 4.3.12 is required.
+ VirtualBox.version(function (err, installedVersion) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ var needsUpdate = Utilities.compareVersions(installedVersion, VirtualBox.REQUIRED_VERSION) < 0;
+ if (needsUpdate) {
+ VirtualBox.install(function (err) {
+ callback(err);
+ });
+ } else {
+ callback();
+ }
+ });
+ }
+ },
+ pastMessage: 'VirtualBox installed',
+ message: 'Installing VirtualBox',
+ futureMessage: 'Install VirtualBox if necessary'
+ },
+
+ // Initialize Boot2Docker if necessary.
+ {
+ run: function (callback) {
+ Boot2Docker.exists(function (err, exists) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (!exists) {
+ Boot2Docker.init(function (err) {
+ callback(err);
+ });
+ } else {
+ Boot2Docker.stop(function (err) {
+ Boot2Docker.upgrade(function (err) {
+ callback(err);
+ });
+ });
+ }
+ });
+ },
+ pastMessage: 'Setup the Boot2Docker VM (if required)',
+ message: 'Setting up the Boot2Docker VM',
+ futureMessage: 'Set up the Boot2Docker VM(if required)'
+ },
+
+ // Set up the routing.
+ {
+ run: function (callback) {
+ VirtualBox.setupRouting('boot2docker-vm', function (err, ifname) {
+ callback(err);
+ });
+ },
+ pastMessage: 'Container routing set up.',
+ message: 'Setting up container routing (root required).',
+ subMessage: '(This may take a few minutes)',
+ futureMessage: 'Set up container routing to VM (root required).'
+ },
+
+ // Start the Kitematic VM
+ {
+ run: function (callback) {
+ Boot2Docker.state(function (err, state) {
+ if (state !== 'running') {
+ Boot2Docker.start(function (err) {
+ callback(err);
+ });
+ } else {
+ Boot2Docker.setIp('eth2', Boot2Docker.REQUIRED_IP, function(err) {
+ callback(err);
+ });
+ }
+ });
+ },
+ pastMessage: 'Started the Boot2Docker VM',
+ message: 'Starting the Boot2Docker VM',
+ subMessage: '(This may take a few minutes)',
+ futureMessage: 'Start the Kitematic VM',
+ },
+
+ // Set up the default Kitematic images
+ {
+ run: function (callback) {
+ Meteor.call('reloadDefaultContainers', function (err) {
+ callback(err);
+ });
+ },
+ pastMessage: 'Started the Boot2Docker VM',
+ message: 'Setting up the default Kitematic images...',
+ subMessage: '(This may take a few minutes)',
+ futureMessage: 'Set up the default Kitematic images',
+ }
+];
+
+Installer.run = function (callback) {
+ var currentStep = 0;
+ Session.set('currentInstallStep', currentStep);
+ Session.set('numberOfInstallSteps', this.steps.length);
+ async.eachSeries(this.steps, function (step, callback) {
+ console.log('Performing step ' + currentStep);
+ step.run(function (err) {
+ if (err) {
+ callback(err);
+ } else {
+ currentStep += 1;
+ Session.set('currentInstallStep', currentStep);
+ callback();
+ }
+ });
+ }, function (err) {
+ if (err) {
+ // if any of the steps fail
+ console.log('Kitematic setup failed at step ' + currentStep);
+ console.log(err);
+ Session.set('failedStep', currentStep);
+ Session.set('failedError', err);
+ callback(err);
+ } else {
+ // Setup Finished
+ console.log('Setup finished.');
+ callback();
+ }
+ });
+};
diff --git a/meteor/client/lib/utilities.js b/meteor/client/lib/utilities.js
index c3fe268798..8915f19d46 100755
--- a/meteor/client/lib/utilities.js
+++ b/meteor/client/lib/utilities.js
@@ -1,5 +1,80 @@
var path = require('path');
+Utilities = {};
+
+/**
+ * Compares two software version numbers (e.g. "1.7.1" or "1.2b").
+ *
+ * @param {string} v1 The first version to be compared.
+ * @param {string} v2 The second version to be compared.
+ * @param {object} [options] Optional flags that affect comparison behavior:
+ *
+ * -
+ * lexicographical: true compares each part of the version strings lexicographically instead of
+ * naturally; this allows suffixes such as "b" or "dev" but will cause "1.10" to be considered smaller than
+ * "1.2".
+ *
+ * -
+ * zeroExtend: true changes the result if one version string has less parts than the other. In
+ * this case the shorter string will be padded with "zero" parts instead of being considered smaller.
+ *
+ *
+ * @returns {number|NaN}
+ *
+ * - 0 if the versions are equal
+ * - a negative integer iff v1 < v2
+ * - a positive integer iff v1 > v2
+ * - NaN if either version string is in the wrong format
+ *
+ *
+ */
+Utilities.compareVersions = function (v1, v2, options) {
+ var lexicographical = options && options.lexicographical,
+ zeroExtend = options && options.zeroExtend,
+ v1parts = v1.split('.'),
+ v2parts = v2.split('.');
+
+ function isValidPart(x) {
+ return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
+ }
+
+ if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
+ return NaN;
+ }
+
+ if (zeroExtend) {
+ while (v1parts.length < v2parts.length) v1parts.push('0');
+ while (v2parts.length < v1parts.length) v2parts.push('0');
+ }
+
+ if (!lexicographical) {
+ v1parts = v1parts.map(Number);
+ v2parts = v2parts.map(Number);
+ }
+
+ for (var i = 0; i < v1parts.length; ++i) {
+ if (v2parts.length == i) {
+ return 1;
+ }
+
+ if (v1parts[i] == v2parts[i]) {
+ continue;
+ }
+ else if (v1parts[i] > v2parts[i]) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+ }
+
+ if (v1parts.length != v2parts.length) {
+ return -1;
+ }
+
+ return 0;
+};
+
getBinDir = function () {
if (process.env.NODE_ENV === 'development') {
return path.join(path.join(process.env.PWD, '..'), 'resources');
diff --git a/meteor/client/lib/virtualbox.js b/meteor/client/lib/virtualbox.js
index 6d362492a9..cbf3290293 100644
--- a/meteor/client/lib/virtualbox.js
+++ b/meteor/client/lib/virtualbox.js
@@ -1,55 +1,168 @@
var fs = require('fs');
-var child_process = require('child_process');
+var exec = require('exec');
var path = require('path');
-isVirtualBoxInstalled = function (callback) {
- fs.exists('/usr/bin/VBoxManage', function (exists) {
- callback(null, exists);
+VirtualBox = {};
+
+VirtualBox.REQUIRED_VERSION = '4.3.12';
+VirtualBox.INCLUDED_VERSION = '4.3.12';
+VirtualBox.INSTALLER_FILENAME = 'virtualbox-4.3.12.pkg';
+
+// Info for the hostonly interface we add to the VM.
+VirtualBox.HOSTONLY_HOSTIP = '192.168.60.3';
+VirtualBox.HOSTONLY_NETWORKMASK = '255.255.255.0';
+
+VirtualBox.installed = function () {
+ return fs.existsSync('/usr/bin/VBoxManage');
+};
+
+VirtualBox.exec = function (command, callback) {
+ exec('/usr/bin/VBoxManage ' + command, function (error, stdout, stderr) {
+ callback(error, stdout, stderr);
});
};
-isResolverSetup = function (callback) {
- fs.readFile('/etc/resolver/dev', {
- encoding: 'utf8'
- }, function (err, data) {
+VirtualBox.install = function (callback) {
+ // -W waits for the process to close before finishing.
+ exec('open -W ' + path.join(getBinDir(), this.INSTALLER_FILENAME), function (error, stdout, stderr) {
+ if (error) {
+ callback(error);
+ return;
+ }
+ callback(null);
+ });
+}
+
+VirtualBox.version = function (callback) {
+ if (!this.installed()) {
+ callback('VirtualBox not installed.');
+ return;
+ }
+ this.exec('-v', function (err, stdout, stderr) {
if (err) {
- callback(err, false);
- } else {
- if (data.indexOf('nameserver 172.17.42.1') !== -1) {
- callback(null, true);
- } else {
- callback(null, false);
+ callback(err);
+ return;
+ }
+ // Output is x.x.xryyyyyy
+ var match = stdout.match(/(\d+\.\d+\.\d+).*/);
+ if (!match || match.length < 2) {
+ callback('VBoxManage -v output format not recognized.');
+ return;
+ }
+ callback(null, match[1]);
+ });
+};
+
+VirtualBox.hostOnlyIfs = function (callback) {
+ this.exec('list hostonlyifs', function (err, stdout, stderr) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ var lines = stdout.split('\n');
+ var hostOnlyIfs = {};
+ var currentIf = null;
+ _.each(lines, function (line) {
+ if (!line.length) return;
+ var pieces = line.split(':');
+ var key = pieces[0].trim();
+ var value = pieces[1] ? pieces[1].trim() : null;
+ if (key === 'Name') {
+ currentIf = value;
+ hostOnlyIfs[value] = {};
}
- }
+ hostOnlyIfs[currentIf][key] = value;
+ });
+ callback(null, hostOnlyIfs);
});
};
-setupResolver = function (callback) {
- var installFile = path.join(getBinDir(), 'install');
- var cocoaSudo = path.join(getBinDir(), 'cocoasudo');
- var execCommand = cocoaSudo + ' --prompt="Kitematic Setup wants to make changes. Type your password to allow this." ' + installFile;
- child_process.exec(execCommand, function (error, stdout, stderr) {
- console.log(stdout);
- if (error) {
- console.log(error);
- callback(error);
+VirtualBox.hostOnlyAdapters = function (vm, callback) {
+ this.exec('showvminfo ' + vm + ' --machinereadable', function (err, stdout, stderr) {
+ if (err) {
+ callback(err);
return;
}
- console.log('Virtualbox Installation & Resolver config complete.');
- callback();
+ var matches = stdout.match(/(hostonlyadapter\d+)="(vboxnet\d+)"/g);
+ if (!matches.length) {
+ callback(null, {});
+ } else {
+ var objs = {};
+ _.each(matches, function (match) {
+ var pieces = match.split('=');
+ objs[pieces[0]] = pieces[1].replace(/"/g, '');
+ });
+ callback(null, objs);
+ }
});
};
-setupVirtualBox = function (callback) {
- child_process.exec('open -W ' + path.join(getBinDir(), 'virtualbox-4.3.12.pkg'), function (error, stdout, stderr) {
- console.log(stdout);
- if (error) {
- console.log(error);
- callback(error);
+VirtualBox.hostOnlyAdapter = function (callback) {
+ var self = this;
+ self.hostOnlyIfs(function (err, ifs) {
+ var iface = _.findWhere(_.toArray(ifs), {IPAddress: VirtualBox.HOSTONLY_HOSTIP});
+ if (!iface) {
+ self.exec('hostonlyif create', function (err, stdout, stderr) {
+ var match = stdout.match(/Interface '(vboxnet\d+)' was successfully created/);
+ console.log(match);
+ if (!match) {
+ callback('Could not parse output of hostonlyif create');
+ return;
+ }
+ self.exec('hostonlyif ipconfig ' + match[1] + ' --ip ' + VirtualBox.HOSTONLY_HOSTIP + ' --netmask ' + VirtualBox.HOSTONLY_NETWORKMASK, function(err, stdout, stderr) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ callback(null, match[1]);
+ });
+ });
+ } else {
+ callback(null, iface.Name);
+ }
+ });
+};
+
+VirtualBox.addCustomHostAdapter = function (vm, callback) {
+ var self = this;
+ self.hostOnlyAdapter(function (err, ifname) {
+ if (err) {
+ callback(err);
return;
}
- console.log('Virtualbox Installation running.');
- callback();
+ self.exec('modifyvm ' + vm + ' --nic3 hostonly --nictype3 virtio --cableconnected3 on --hostonlyadapter3 ' + ifname, function (err, stdout, stderr) {
+ callback(err, ifname);
+ });
});
};
+VirtualBox.setupRouting = function (vm, callback) {
+ // Get the host only adapter or create it if it doesn't exist
+ this.addCustomHostAdapter(vm, function (err, ifname) {
+ var installFile = path.join(getBinDir(), 'install');
+ var cocoaSudo = path.join(getBinDir(), 'cocoasudo');
+ var execCommand = cocoaSudo + ' --prompt="Kitematic needs your password to allow routing *.dev requests to containers." ' + installFile;
+ exec(execCommand, {env: {IFNAME: ifname, GATEWAY: Boot2Docker.REQUIRED_IP}}, function (error, stdout, stderr) {
+ if (error) {
+ callback(error);
+ return;
+ }
+ callback();
+ });
+ });
+};
+
+
+VirtualBox.removeDHCP = function (callback) {
+ var self = this;
+ self.hostOnlyAdapter(function (err, ifname) {
+ if (err) { callback(err); return; }
+ console.log(ifname);
+ self.exec('dhcpserver remove --ifname ' + ifname, function (err, stdout, stderr) {
+ callback(err);
+ });
+ });
+};
+
+
+
diff --git a/meteor/client/main.js b/meteor/client/main.js
index 7abe7d59a1..b021d84992 100755
--- a/meteor/client/main.js
+++ b/meteor/client/main.js
@@ -68,19 +68,6 @@ Meteor.call('getDockerHost', function (err, host) {
Session.set('dockerHost', host);
});
-updateBoot2DockerInfo = function () {
- getBoot2DockerInfo(function (err, info) {
- if (err) {
- return;
- }
- Session.set('boot2dockerState', info.state);
- if (info.state !== 'poweroff' && info.memory && info.disk) {
- Session.set('boot2dockerMemoryUsage', info.memory);
- Session.set('boot2dockerDiskUsage', info.disk);
- }
- });
-};
-
fixBoot2DockerVM = function (callback) {
checkBoot2DockerVM(function (err) {
if (err) {
@@ -138,7 +125,24 @@ fixDefaultContainers = function (callback) {
};
Meteor.setInterval(function () {
- updateBoot2DockerInfo();
+ Boot2Docker.exists(function (err, exists) {
+ if (err) { return; }
+ if (exists) {
+ Boot2Docker.state(function (err, state) {
+ if (err) { return; }
+ if (state === 'running') {
+ Boot2Docker.info(function (err, info) {
+ if (err) { return; }
+ Session.set('boot2dockerState', info.state);
+ if (info.state !== 'poweroff' && info.memory && info.disk) {
+ Session.set('boot2dockerMemoryUsage', info.memory);
+ Session.set('boot2dockerDiskUsage', info.disk);
+ }
+ });
+ }
+ });
+ }
+ });
}, 5000);
fixInterval = null;
@@ -148,7 +152,6 @@ startFixInterval = function () {
resolveWatchers(function () {});
fixBoot2DockerVM(function (err) {
if (err) { console.log(err); return; }
- // Meteor.call('recoverApps');
fixDefaultImages(function (err) {
if (err) { console.log(err); return; }
fixDefaultContainers(function (err) {
diff --git a/meteor/client/views/dashboard/settings/dashboard-settings.js b/meteor/client/views/dashboard/settings/dashboard-settings.js
index cf12f91c27..5ee50c0778 100644
--- a/meteor/client/views/dashboard/settings/dashboard-settings.js
+++ b/meteor/client/views/dashboard/settings/dashboard-settings.js
@@ -3,7 +3,7 @@ Template.dashboard_settings.events({
var $btn = $(e.currentTarget);
$btn.html('Starting Boot2Docker...');
$btn.attr("disabled", "disabled");
- startFixInterval();
+ //startFixInterval();
startBoot2Docker(function (err) {
if (err) { console.error(err); }
});
diff --git a/meteor/client/views/dashboard/setup/setup-install.js b/meteor/client/views/dashboard/setup/setup-install.js
index 004ac755cf..020e86413b 100644
--- a/meteor/client/views/dashboard/setup/setup-install.js
+++ b/meteor/client/views/dashboard/setup/setup-install.js
@@ -1,136 +1,8 @@
-var async = require('async');
-
-// Install steps. A step is a function that accepts a function (err) callback and returns once that step is complete.
-// keys:
-// - install: Function that runs the installation step and calls the callback with an error if failed.
-// - pastMessage: Message to show after step completion
-// - message: Message to show while step is running
-// - imperativeMessage: Message to show before running
-var steps = [
-
- // Set up VirtualBox
- {
- install: function (callback) {
- isVirtualBoxInstalled(function (err, virtualBoxInstalled) {
- var installedYet = false;
- if (!virtualBoxInstalled) {
- setupVirtualBox(function (err) {
- callback(err);
- });
- } else {
- callback();
- }
- });
- },
- pastMessage: 'VirtualBox installed',
- message: 'Installing VirtualBox',
- futureMessage: 'Install VirtualBox if necessary'
- },
-
- // Set up the routing.
- {
- install: function (callback) {
- setupResolver(function (err) {
- callback(err);
- });
- },
- pastMessage: 'Container routing set up (root required).',
- message: 'Setting up container routing (root required).',
- subMessage: '(This may take a few minutes)',
- futureMessage: 'Set up container routing to VM (root required).'
- },
-
- // Set up the VM for running Kitematic apps
- {
- install: function (callback) {
- console.log('Checking if vm exists...');
- boot2DockerVMExists(function (err, exists) {
- console.log('VM exists: ' + exists);
- if (exists) {
- console.log('Stopping vm');
- stopBoot2Docker(function () {
- console.log('Upgrading vm');
- upgradeBoot2Docker(function () {
- callback();
- });
- });
- } else {
- console.log('init VM');
- initBoot2Docker(function () {
- callback();
- });
- }
- });
- },
- pastMessage: 'Set up the Kitematic VM',
- message: 'Setting up the Kitematic VM...',
- futureMessage: 'Set up the Kitematic VM'
- },
-
- // Start the Kitematic VM
- {
- install: function (callback) {
- startBoot2Docker(function (err) {
- callback(err);
- });
- },
- pastMessage: 'Started the Kitematic VM',
- message: 'Starting the Kitematic VM',
- subMessage: '(This may take a few minutes)',
- futureMessage: 'Start the Kitematic VM',
- },
-
- // Set up the default Kitematic images
- {
- install: function (callback) {
- Meteor.call('reloadDefaultContainers', function (err) {
- callback(err);
- });
- },
- pastMessage: 'Started the Kitematic VM',
- message: 'Setting up the default Kitematic images...',
- subMessage: '(This may take a few minutes)',
- futureMessage: 'Set up the default Kitematic images',
- }
-];
-
-runSetup = function (callback) {
- // Run through the Kitematic installation, skipping steps if required.
- var currentStep = 0;
- Session.set('currentInstallStep', currentStep);
- Session.set('numberOfInstallSteps', steps.length);
- async.eachSeries(steps, function (step, callback) {
- console.log('Performing step ' + currentStep);
- step.install(function (err) {
- if (err) {
- callback(err);
- } else {
- currentStep += 1;
- Session.set('currentInstallStep', currentStep);
- callback();
- }
- });
- }, function (err) {
- if (err) {
- // if any of the steps fail
- console.log('Kitematic setup failed at step ' + currentStep);
- console.log(err);
- Session.set('failedStep', currentStep);
- Session.set('failedError', err);
- callback(err);
- } else {
- // Setup Finished
- console.log('Setup finished.');
- callback();
- }
- });
-};
-
var installStarted = false;
Template.setup_install.rendered = function() {
if(!installStarted) {
installStarted = true;
- runSetup(function (err) {
+ Installer.run(function (err) {
if (err) {
console.log('Setup failed.');
console.log(err);
@@ -144,7 +16,7 @@ Template.setup_install.rendered = function() {
};
Template.setup_install.steps = function () {
- return steps.map(function (step, index) {
+ return Installer.steps.map(function (step, index) {
step.index = index;
return step;
});
@@ -155,7 +27,7 @@ Template.setup_install.helpers({
return Session.get('currentInstallStep');
},
installComplete: function () {
- return Session.get('currentInstallStep') === steps.length;
+ return Session.get('currentInstallStep') === Installer.steps.length;
},
failedStep: function () {
return Session.get('failedStep');
diff --git a/meteor/server/docker.js b/meteor/server/docker.js
index d71b12688b..6aded68a47 100755
--- a/meteor/server/docker.js
+++ b/meteor/server/docker.js
@@ -3,8 +3,8 @@ Docker = Meteor.require('dockerode');
var Convert = Meteor.require('ansi-to-html');
var convert = new Convert();
-var DOCKER_HOST='192.168.59.103';
-docker = new Docker({host: '192.168.59.103', port: '2375'});
+var DOCKER_HOST='192.168.60.103';
+docker = new Docker({host: DOCKER_HOST, port: '2375'});
hasDockerfile = function (directory) {
return fs.existsSync(path.join(directory, 'Dockerfile'));
diff --git a/resources/install b/resources/install
index 723ff280d1..b0791ac3bc 100755
--- a/resources/install
+++ b/resources/install
@@ -1,6 +1,11 @@
#!/bin/sh
-# Lookup the Kitematic VM resolver for .dev domains
+# This script must be run as root and sets up Mac OS X to route all .dev domains to the virtual box VM with the name
+# 'boot2docker-vm'. It does the following:
+# 1) Adds a file under /etc/resolver/dev
+# 2) Sets up a LaunchAgent for adding entries to the route table to route all requests to the Docker subnet (172.17.0.0/16)
+# And expects the $IFNAME variable to contain the interface on which to send traffic to the boot2docker VM.
+
mkdir -p /etc/resolver
echo "nameserver 172.17.42.1" > /etc/resolver/dev
@@ -8,10 +13,9 @@ DIR=$(dirname "$0")
USER=`w -h | sort -u -t' ' -k1,1 | awk '{print $1}'`
/bin/rm -rf /Library/LaunchAgents/com.kitematic.route.plist
-
-echo '
-
-
+echo "
+
+
Label
com.kitematic.route
@@ -20,26 +24,25 @@ echo '
/sbin/route
-n
add
- 172.17.0.0/16
- 192.168.59.103
+ -net
+ 172.17.0.0
+ -netmask
+ 255.255.0.0
+ -iface
+ $IFNAME
+ 255.255.0.0
+ -gateway
+ $GATEWAY
KeepAlive
RunAtLoad
- ServiceIPC
-
- UserName
- root
LaunchOnlyOnce
-' > /Library/LaunchAgents/com.kitematic.route.plist
-
-sudo -u $USER $DIR/boot2docker init
-VBoxManage modifyvm boot2docker-vm --nic2 hostonly --nictype2 virtio --cableconnected2 on --hostonlyadapter2 vboxnet0
-VBoxManage dhcpserver add --netname=vboxnet0 --ip=192.168.59.99 --netmask=255.255.255.0 --lowerip=192.168.59.103 --upperip=192.168.59.103
+" > /Library/LaunchAgents/com.kitematic.route.plist
# Add entries to routing table for Kitematic VM
-/sbin/route delete 172.17.0.0/16 192.168.59.103
-/sbin/route -n add 172.17.0.0/16 192.168.59.103
\ No newline at end of file
+/sbin/route delete -net 172.17.0.0 -netmask 255.255.0.0 -gateway $GATEWAY
+/sbin/route -n add -net 172.17.0.0 -netmask 255.255.0.0 -iface $IFNAME -gateway $GATEWAY
\ No newline at end of file