lib/vagrant-notify/action/start_server.rb in vagrant-notify-0.2.2 vs lib/vagrant-notify/action/start_server.rb in vagrant-notify-0.3.0

- old
+ new

@@ -1,23 +1,61 @@ +require "vagrant/util/is_port_open" + require_relative '../server' module Vagrant module Notify module Action class StartServer - # TODO: This should come from vm configuration or be automatically - # assigned - PORT = '9999' + include Util::IsPortOpen def initialize(app, env) @app = app end def call(env) - env[:notify_data][:pid] = Server.run(env, PORT) - env[:notify_data][:port] = PORT + @env = env + port = next_available_port + env[:notify_data][:pid] = Server.run(env, port) + env[:notify_data][:port] = port + @app.call env + end + + def next_available_port + # Determine a list of usable ports for us to use + usable_ports = Set.new(@env[:machine].config.vm.usable_port_range) + + # Pass one, remove all defined host ports from usable ports + with_forwarded_ports do |options| + usable_ports.delete(options[:host]) + end + + # Pass two, remove ports used by other processes + with_forwarded_ports do |options| + host_port = options[:host] + usable_ports.delete(options[:host]) if is_port_open?("127.0.0.1", host_port) + end + + # If we have no usable ports then we can't use the plugin + raise 'No usable ports available!' if usable_ports.empty? + + # Set the port up to be the last one since vagrant's port collision handler + # will use the first as in: + # https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb#L84 + usable_ports.to_a.sort.reverse.find do |port| + return port unless is_port_open?("127.0.0.1", port) + end + end + + def with_forwarded_ports + @env[:machine].config.vm.networks.each do |type, options| + # Ignore anything but forwarded ports + next if type != :forwarded_port + + yield options + end end end end end end