forked from hashicorp/vagrant
/
check_port_collisions.rb
89 lines (74 loc) · 3.34 KB
/
check_port_collisions.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
require "vagrant/util/is_port_open"
module Vagrant
module Action
module VM
# Action that checks to make sure there are no forwarded port collisions,
# and raises an exception if there is.
class CheckPortCollisions
include Util::IsPortOpen
def initialize(app, env)
@app = app
end
def call(env)
# For the handlers...
@env = env
# Figure out how we handle port collisions. By default we error.
handler = env[:port_collision_handler] || :error
# Read our forwarded ports, if we have any, to override what
# we have configured.
current = {}
env[:vm].driver.read_forwarded_ports.each do |nic, name, hostport, guestport|
current[name] = hostport.to_i
end
existing = env[:vm].driver.read_used_ports
env[:vm].config.vm.forwarded_ports.each do |options|
# Use the proper port, whether that be the configured port or the
# port that is currently on use of the VM.
hostport = options[:hostport].to_i
hostport = current[options[:name]] if current.has_key?(options[:name])
if existing.include?(hostport) || is_port_open?("localhost", hostport)
# We have a collision! Handle it
send("handle_#{handler}".to_sym, options, existing)
end
end
@app.call(env)
end
# Handles a port collision by raising an exception.
def handle_error(options, existing_ports)
raise Errors::ForwardPortCollisionResume
end
# Handles a port collision by attempting to fix it.
def handle_correct(options, existing_ports)
# We need to keep this for messaging purposes
original_hostport = options[:hostport]
if !options[:auto]
# Auto fixing is disabled for this port forward, so we
# must throw an error so the user can fix it.
raise Errors::ForwardPortCollision, :host_port => options[:hostport].to_s,
:guest_port => options[:guestport].to_s
end
# Get the auto port range and get rid of the used ports and
# ports which are being used in other forwards so we're just
# left with available ports.
range = @env[:vm].config.vm.auto_port_range.to_a
range -= @env[:vm].config.vm.forwarded_ports.collect { |opts| opts[:hostport].to_i }
range -= existing_ports
if range.empty?
raise Errors::ForwardPortAutolistEmpty, :vm_name => @env[:vm].name,
:host_port => options[:hostport].to_s,
:guest_port => options[:guestport].to_s
end
# Set the port up to be the first one and add that port to
# the used list.
options[:hostport] = range.shift
existing_ports << options[:hostport]
# Notify the user
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.fixed_collision",
:host_port => original_hostport.to_s,
:guest_port => options[:guestport].to_s,
:new_port => options[:hostport]))
end
end
end
end
end