Add support for port forwarding.

This commit is contained in:
Ryan Petrello 2014-01-23 15:35:11 -08:00
parent 0fe1798358
commit bb5d081789
3 changed files with 154 additions and 1 deletions

View File

@ -162,7 +162,7 @@ Vagrant goes through steps below when creating new project:
## Networks
Networking features in the form of `config.vm.network` support private networks
concept. Port Forwarding is currently not supported.
concept.
Public Network interfaces are currently implemented using the macvtap driver. The macvtap
driver is only available with the Linux Kernel version >= 2.6.24. See the following libvirt

View File

@ -32,6 +32,8 @@ module VagrantPlugins
b2.use SyncedFolders
end
b2.use ForwardPorts
b2.use PrepareNFSSettings
b2.use ShareFolders
b2.use SetHostname
@ -75,6 +77,8 @@ module VagrantPlugins
b3.use SyncedFolderCleanup
b3.use SyncedFolders
end
b3.use ForwardPorts
b3.use PrepareNFSSettings
b3.use ShareFolders
@ -95,6 +99,7 @@ module VagrantPlugins
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use ClearForwardedPorts
b.use Call, IsCreated do |env, b2|
if !env[:result]
b2.use MessageNotCreated
@ -144,6 +149,7 @@ module VagrantPlugins
end
b2.use ConnectLibvirt
b2.use ClearForwardedPorts
b2.use PruneNFSExports
b2.use DestroyDomain
b2.use DestroyNetworks
@ -297,6 +303,8 @@ module VagrantPlugins
autoload :CreateNetworks, action_root.join('create_networks')
autoload :DestroyDomain, action_root.join('destroy_domain')
autoload :DestroyNetworks, action_root.join('destroy_networks')
autoload :ForwardPorts, action_root.join('forward_ports')
autoload :ClearForwardedPorts, action_root.join('forward_ports')
autoload :HaltDomain, action_root.join('halt_domain')
autoload :HandleBoxImage, action_root.join('handle_box_image')
autoload :HandleStoragePool, action_root.join('handle_storage_pool')

View File

@ -0,0 +1,145 @@
module VagrantPlugins
module ProviderLibvirt
module Action
class ForwardPorts
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_libvirt::action::forward_ports")
end
def call(env)
@env = env
# Get the ports we're forwarding
env[:forwarded_ports] = compile_forwarded_ports(env[:machine].config)
# Warn if we're port forwarding to any privileged ports
env[:forwarded_ports].each do |fp|
if fp[:host] <= 1024
env[:ui].warn I18n.t("vagrant.actions.vm.forward_ports.privileged_ports")
break
end
end
# Continue, we need the VM to be booted in order to grab its IP
@app.call env
if @env[:forwarded_ports].any?
env[:ui].info I18n.t("vagrant.actions.vm.forward_ports.forwarding")
forward_ports
end
end
def forward_ports
@env[:forwarded_ports].each do |fp|
message_attributes = {
:adapter => 'eth0',
:guest_port => fp[:guest],
:host_port => fp[:host]
}
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.forwarding_entry",
message_attributes))
ssh_pid = redirect_port(
@env[:machine].name,
fp[:host_ip] || '0.0.0.0',
fp[:host],
fp[:guest_ip] || @env[:machine].provider.ssh_info[:host],
fp[:guest]
)
store_ssh_pid(fp[:host], ssh_pid)
end
end
private
def compile_forwarded_ports(config)
mappings = {}
config.vm.networks.each do |type, options|
next if options[:disabled]
# TODO: Deprecate this behavior of "automagically" skipping ssh forwarded ports
if type == :forwarded_port && options[:id] != 'ssh'
options.delete(:host_ip) if options.fetch(:host_ip, '').to_s.strip.empty?
mappings[options[:host]] = options
end
end
mappings.values
end
def redirect_port(machine_name, host_ip, host_port, guest_ip, guest_port)
params = %W( #{machine_name} -L #{host_ip}:#{host_port}:#{guest_ip}:#{guest_port} -N ).join(" ")
ssh_cmd = "ssh $(vagrant ssh-config #{machine_name} | awk '{print \" -o \"$1\"=\"$2}') #{params} 2>/dev/null"
@logger.debug "Forwarding port with `#{ssh_cmd}`"
spawn ssh_cmd
end
def store_ssh_pid(host_port, ssh_pid)
data_dir = @env[:machine].data_dir.join('pids')
data_dir.mkdir unless data_dir.directory?
data_dir.join("ssh_#{host_port}.pid").open('w') do |pid_file|
pid_file.write(ssh_pid)
end
end
end
end
end
end
module VagrantPlugins
module ProviderLibvirt
module Action
class ClearForwardedPorts
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_libvirt::action::clear_forward_ports")
end
def call(env)
@env = env
if ssh_pids.any?
env[:ui].info I18n.t("vagrant.actions.vm.clear_forward_ports.deleting")
ssh_pids.each do |pid|
next unless is_ssh_pid?(pid)
@logger.debug "Killing pid #{pid}"
system "pkill -TERM -P #{pid}"
end
@logger.info "Removing ssh pid files"
remove_ssh_pids
else
@logger.info "No ssh pids found"
end
@app.call env
end
protected
def ssh_pids
@ssh_pids = Dir[@env[:machine].data_dir.join('pids').to_s + "/ssh_*.pid"].map do |file|
File.read(file).strip.chomp
end
end
def is_ssh_pid?(pid)
@logger.debug "Checking if #{pid} is an ssh process with `ps -o cmd= #{pid}`"
`ps -o cmd= #{pid}`.strip.chomp =~ /ssh/
end
def remove_ssh_pids
Dir[@env[:machine].data_dir.join('pids').to_s + "/ssh_*.pid"].each do |file|
File.delete file
end
end
end
end
end
end