diff --git a/lib/vagrant/actions/vm/forward_ports.rb b/lib/vagrant/actions/vm/forward_ports.rb index ab8733662..95e2c6bf3 100644 --- a/lib/vagrant/actions/vm/forward_ports.rb +++ b/lib/vagrant/actions/vm/forward_ports.rb @@ -2,6 +2,31 @@ module Vagrant module Actions module VM class ForwardPorts < Base + def prepare + ActiveList.vms.each do |vagrant_vm| + vm = vagrant_vm.vm + next unless vm.running? + + vm.forwarded_ports.each do |fp| + Vagrant.config.vm.forwarded_ports.each do |name, options| + if fp.hostport.to_s == options[:hostport].to_s + raise ActionException.new(<<-msg) +Vagrant cannot forward the specified ports on this VM, since they +would collide with another Vagrant-managed virtual machine's forwarded +ports! The "#{name}" forwarded port (#{fp.hostport}) is already in use on the host +machine. + +To fix this, modify your current projects Vagrantfile to use another +port. Example, where '1234' would be replaced by a unique host port: + +config.vm.forward_port("#{name}", #{options[:guestport]}, 1234) +msg + end + end + end + end + end + def execute! clear forward_ports diff --git a/test/vagrant/actions/vm/forward_ports_test.rb b/test/vagrant/actions/vm/forward_ports_test.rb index 626150d25..da290fac6 100644 --- a/test/vagrant/actions/vm/forward_ports_test.rb +++ b/test/vagrant/actions/vm/forward_ports_test.rb @@ -6,6 +6,52 @@ class ForwardPortsActionTest < Test::Unit::TestCase mock_config end + context "checking for colliding ports" do + setup do + @forwarded_port = mock("forwarded_port") + @forwarded_port.stubs(:hostport) + @forwarded_ports = [@forwarded_port] + + @vm = mock("vm") + @vm.stubs(:forwarded_ports).returns(@forwarded_ports) + @vm.stubs(:running?).returns(true) + vagrant_vm = mock("vagrant_vm") + vagrant_vm.stubs(:vm).returns(@vm) + vms = [vagrant_vm] + Vagrant::ActiveList.stubs(:vms).returns(vms) + + mock_config do |config| + config.vm.forwarded_ports.clear + config.vm.forward_port("ssh", 22, 2222) + end + end + + should "ignore vms which aren't running" do + @vm.expects(:running?).returns(false) + @vm.expects(:forwarded_ports).never + @action.prepare + end + + should "not raise any errors if no forwarded ports collide" do + @forwarded_port.expects(:hostport).returns(80) + assert_nothing_raised { @action.prepare } + end + + should "raise an ActionException if a port collides" do + @forwarded_port.expects(:hostport).returns(2222) + assert_raises(Vagrant::Actions::ActionException) { + @action.prepare + } + end + + should "convert ports to strings prior to checking" do + @forwarded_port.expects(:hostport).returns("2222") + assert_raises(Vagrant::Actions::ActionException) { + @action.prepare + } + end + end + context "execution" do should "clear all previous ports and forward new ports" do exec_seq = sequence("exec_seq")