Forwarded ports

This commit is contained in:
Mitchell Hashimoto 2011-12-20 22:28:47 -08:00
parent c59defa7e8
commit a39df9f150
4 changed files with 120 additions and 64 deletions

View File

@ -7,17 +7,9 @@ module Vagrant
end
def call(env)
proc = lambda do |vm|
env[:ui].info I18n.t("vagrant.actions.vm.clear_forward_ports.deleting")
env[:ui].info I18n.t("vagrant.actions.vm.clear_forward_ports.deleting")
env[:vm].driver.clear_forwarded_ports
vm.network_adapters.each do |na|
na.nat_driver.forwarded_ports.dup.each do |fp|
fp.destroy
end
end
end
env["vm.modify"].call(proc)
@app.call(env)
end
end

View File

@ -1,11 +1,7 @@
require File.join(File.dirname(__FILE__), 'forward_ports_helpers')
module Vagrant
module Action
module VM
class ForwardPorts
include ForwardPortsHelpers
def initialize(app,env)
@app = app
@env = env
@ -35,7 +31,7 @@ module Vagrant
# report the collisions detected or will attempt to fix them
# automatically if the port is configured to do so.
def external_collision_check
existing = used_ports
existing = @env[:vm].driver.read_used_ports
@env[:vm].config.vm.forwarded_ports.each do |name, options|
if existing.include?(options[:hostport].to_i)
handle_collision(name, options, existing)
@ -86,35 +82,41 @@ module Vagrant
def call(env)
@env = env
proc = lambda do |vm|
env[:ui].info I18n.t("vagrant.actions.vm.forward_ports.forwarding")
forward_ports(vm)
end
env[:ui].info I18n.t("vagrant.actions.vm.forward_ports.forwarding")
forward_ports(env[:vm])
env["vm.modify"].call(proc)
@app.call(env)
end
def forward_ports(vm)
ports = []
@env[:vm].config.vm.forwarded_ports.each do |name, options|
adapter = options[:adapter]
adapter = options[:adapter] + 1
message_attributes = {
:name => name,
:guest_port => options[:guestport],
:host_port => options[:hostport],
:adapter => adapter + 1
:adapter => adapter
}
# Assuming the only reason to establish port forwarding is because the VM is using Virtualbox NAT networking.
# Host-only or Bridged networking don't require port-forwarding and establishing forwarded ports on these
# attachment types has uncertain behaviour.
if vm.network_adapters[adapter].attachment_type == :nat
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.forwarding_entry", message_attributes))
forward_port(vm, name, options)
else
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.non_nat", message_attributes))
end
# Assuming the only reason to establish port forwarding is
# because the VM is using Virtualbox NAT networking. Host-only
# bridged networking don't require port-forwarding and establishing
# forwarded ports on these attachment types has uncertain behaviour.
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.forwarding_entry",
message_attributes))
# Add the options to the ports array to send to the driver later
ports << options.merge(:name => name, :adapter => adapter)
# TODO: Check for non-nat again... This was removed during the VBoxManage
# transition but should be brought back.
# @env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.non_nat",
# message_attributes))
end
@env[:vm].driver.forward_ports(ports)
end
#--------------------------------------------------------------

View File

@ -1,28 +0,0 @@
module Vagrant
module Action
module VM
# Helper methods for forwarding ports. Requires that the environment
# is set to the `@env` instance variable.
module ForwardPortsHelpers
# Returns an array of used ports. This method is implemented
# differently depending on the VirtualBox version, but the
# behavior is the same.
#
# @return [Array<String>]
def used_ports
result = VirtualBox::VM.all.collect do |vm|
if vm.accessible? && vm.running? && vm.uuid != @env["vm"].uuid
vm.network_adapters.collect do |na|
na.nat_driver.forwarded_ports.collect do |fp|
fp.hostport.to_i
end
end
end
end
result.flatten.uniq
end
end
end
end
end

View File

@ -24,6 +24,59 @@ module Vagrant
end
end
# This clears the forwarded ports that have been set on the
# virtual machine.
def clear_forwarded_ports
args = []
read_forwarded_ports(@uuid).each do |nic, name, _, _|
args.concat(["--natpf#{nic}", "delete", name])
end
execute("modifyvm", @uuid, *args) if !args.empty?
end
# This deletes the VM with the given name.
def delete
execute("unregistervm", @uuid, "--delete")
end
# Forwards a set of ports for a VM.
#
# This will not affect any previously set forwarded ports,
# so be sure to delete those if you need to.
#
# The format of each port hash should be the following:
#
# {
# :name => "foo",
# :host_port => 8500,
# :guest_port => 80,
# :adapter => 1,
# :protocol => "tcp"
# }
#
# Note that "adapter" and "protocol" are optional and will default
# to 1 and "tcp" respectively.
#
# @param [Array<Hash>] ports An array of ports to set. See documentation
# for more information on the format.
def forward_ports(ports)
args = []
ports.each do |options|
pf_builder = [options[:name],
options[:protocol] || "tcp",
"",
options[:host_port],
"",
options[:guest_port]]
args.concat(["--natpf#{options[:adapter] || 1}",
pf_builder.join(",")])
end
execute("modifyvm", @uuid, *args)
end
# Imports the VM with the given path to the OVF file. It returns
# the UUID as a string.
def import(ovf, name)
@ -36,11 +89,6 @@ module Vagrant
nil
end
# This deletes the VM with the given name.
def delete
execute("unregistervm", @uuid, "--delete")
end
# This reads the guest additions version for a VM.
def read_guest_additions_version
output = execute("guestproperty", "get", @uuid, "/VirtualBox/GuestAdd/Version")
@ -61,6 +109,21 @@ module Vagrant
nil
end
# This will read all the used ports for port forwarding by
# all virtual machines.
def read_used_ports
ports = []
execute("list", "vms").split("\n").each do |line|
if line =~ /^".+?" \{(.+?)\}$/
read_forwarded_ports($1.to_s, true).each do |_, _, hostport, _|
ports << hostport
end
end
end
ports
end
# This sets the MAC address for a network adapter.
def set_mac_address(mac)
execute("modifyvm", @uuid, "--macaddress1", mac)
@ -68,6 +131,33 @@ module Vagrant
protected
# This returns a list of the forwarded ports in the form
# of `[nic, name, hostport, guestport]`.
#
# @return [Array<Array>]
def read_forwarded_ports(uuid, active_only=false)
results = []
current_nic = nil
execute("showvminfo", uuid, "--machinereadable").split("\n").each do |line|
# This is how we find the nic that a FP is attached to,
# since this comes first.
current_nic = $1.to_i if line =~ /^nic(\d+)=".+?"$/
# If we care about active VMs only, then we check the state
# to verify the VM is running.
if active_only && line =~ /^VMState="(.+?)"$/ && $1.to_s != "running"
return []
end
# Parse out the forwarded port information
if line =~ /^Forwarding.+?="(.+?),.+?,.*?,(.+?),.*?,(.+?)"$/
results << [current_nic, $1.to_s, $2.to_i, $3.to_i]
end
end
results
end
# This returns the version of VirtualBox that is running.
#
# @return [String]