Skip to content
This repository has been archived by the owner on Jun 25, 2023. It is now read-only.

Enhancement: IP/NIC selection #122

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ tags

.vagrant
.vagrant_dns.json
.idea
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ source 'https://rubygems.org'

gem 'rubydns', '1.0.2'
gem 'rexec'
gem 'rake'
gem 'rake', '~> 10.0'

# Vagrant's special group
group :plugins do
gem 'landrush', path: '.'
gem 'landrush-ip', '~> 0.2.1'
end

group :test do
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,17 @@ Landrush assigns your vm's hostname from either the vagrant config (see the `exa

Every time a VM is started, its IP address is automatically detected and a DNS record is created that maps the hostname to its IP.

If for any reason the auto-detection detects no IP address or the wrong IP address, or you want to override it, you can do like so:
If for any reason the auto-detection detects no IP address or the wrong IP address you can control how it looks for it.

You can start by excluding interfaces matching an array of regex patterns (the value shown here is the default):

config.landrush.exclude = [/lo[0-9]*/, /docker[0-9]+/, /tun[0-9]+/]

Or, if you know which interface you need the IP of you can specify that too (default is none):

config.landrush.interface = 'eth0'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 good idea


If all else fails, you can override it entirely:

config.landrush.host_ip_address = '1.2.3.4'

Expand Down
15 changes: 13 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
require 'rubygems'
require 'bundler/setup'
require 'bundler/gem_tasks'
require 'rake/testtask'
require 'rubocop/rake_task'

# Immediately sync all stdout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need these changes to the Rakefile?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, that was me comparing the Rakefile with the one I cooked up for the landrush-ip repository because it wouldn't work with my OS X' Rake. These changes aren't necessary at all.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense, thanks

$stdout.sync = true
$stderr.sync = true

# Change to the directory of this file
Dir.chdir(File.expand_path('../', __FILE__))

# Rubocop
RuboCop::RakeTask.new

# Tests
Rake::TestTask.new do |t|
t.pattern = 'test/**/*_test.rb'
t.libs << 'test'
Expand All @@ -15,5 +28,3 @@ task default: [
task :generate_diagrams do
sh 'cd doc; seqdiag --fontmap=support/seqdiag.fontmap -Tsvg vagrant_dns_without_landrush.diag'
end

RuboCop::RakeTask.new
27 changes: 27 additions & 0 deletions Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure('2') do |config|
config.vm.define 'landrush-test-debian' do |machine|
machine.vm.box = 'debian/jessie64'

# Add a DHCP network so we don't know its IP :P
machine.vm.network 'private_network', type: 'dhcp'

machine.vm.provider :virtualbox do |provider, _|
provider.memory = 512
provider.cpus = 2
end

machine.landrush_ip.override = true

machine.vm.hostname = 'landrush-dev'
machine.vm.network 'private_network', type: 'dhcp'

# Landrush (DNS)
machine.landrush.enabled = true
machine.landrush.tld = 'landrush'
machine.landrush.interface = 'eth1'
machine.landrush.exclude = [/lo[0-9]*/, /docker[0-9]+/, /tun[0-9]+/]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you specify the interface explicitly, do the excludes matter at all?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, they are still used as a fallback.

Basically the mechanic works as follows:

  • Get all the interfaces and addresses
  • If landrush.interface is set, look for it and pick it if found
  • If not found or the option is not set, filter the addresses according to the exclude rules (if any) and pick the last address

See the tests, I added a test for that too. landrush.interface = dummy with the default landrush.exclude ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I guess I just did not see it. Need to take a closer look, once I have this locally and also can run the tests

end
end
49 changes: 49 additions & 0 deletions lib/landrush/cap/all/read_host_visible_ip_address.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module Landrush
module Cap
module All
module ReadHostVisibleIpAddress
def self.filter_addresses(addresses)
unless @machine.config.landrush.exclude.nil?
re = Regexp.union(@machine.config.landrush.exclude)

addresses = addresses.select do |addr|
!addr['name'].match(re)
end
end

addresses
end

def self.read_host_visible_ip_address(machine)
@machine = machine

addr = nil
addresses = machine.guest.capability(:landrush_ip_get)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just so that I understand correctly, this is the part which "requests" the landrush-ip capability to which we have now a dependency in the Gemfile and which you release from https://github.com/Werelds/landrush-ip, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. And because the cap will be supported on all platforms (at least, I don't think Vagrant has a guest that Go doesn't support), this code will apply to all platforms.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice


# Short circuit this one first: if an explicit interface is defined, look for it and return it if found.
# Technically, we could do a single loop, but execution time is not vital here.
# This allows us to be more accurate, especially with logging what's going on.
unless machine.config.landrush.interface.nil?
addr = addresses.detect { |a| a['name'] == machine.config.landrush.interface }

machine.env.ui.warn "[landrush] Unable to find interface #{machine.config.landrush.interface}" if addr.nil?
end

if addr.nil?
addresses = filter_addresses addresses

raise 'No addresses found' if addresses.empty?

addr = addresses.last
end

ip = IPAddr.new(addr['ipv4'])

machine.env.ui.info "[landrush] Using #{addr['name']} (#{addr['ipv4']})"

ip.to_s
end
end
end
end
end
47 changes: 0 additions & 47 deletions lib/landrush/cap/linux/read_host_visible_ip_address.rb

This file was deleted.

8 changes: 7 additions & 1 deletion lib/landrush/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ class Config < Vagrant.plugin('2', :config)
attr_accessor :upstream_servers
attr_accessor :host_ip_address
attr_accessor :guest_redirect_dns
attr_accessor :interface
attr_accessor :exclude

DEFAULTS = {
:enabled => false,
:tld => 'vagrant.test',
:upstream_servers => [[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]],
:host_ip_address => nil,
:guest_redirect_dns => true
:guest_redirect_dns => true,
:interface => nil,
:exclude => [/lo[0-9]*/, /docker[0-9]+/, /tun[0-9]+/]
}

def initialize
Expand All @@ -22,6 +26,8 @@ def initialize
@upstream_servers = UNSET_VALUE
@host_ip_address = UNSET_VALUE
@guest_redirect_dns = UNSET_VALUE
@interface = UNSET_VALUE
@exclude = UNSET_VALUE
end

def enable
Expand Down
4 changes: 2 additions & 2 deletions lib/landrush/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ def self.post_boot_actions
end

guest_capability('linux', 'read_host_visible_ip_address') do
require_relative 'cap/linux/read_host_visible_ip_address'
Cap::Linux::ReadHostVisibleIpAddress
require_relative 'cap/all/read_host_visible_ip_address'
Cap::All::ReadHostVisibleIpAddress
end
end
end
87 changes: 87 additions & 0 deletions test/landrush/cap/all/read_host_visible_ip_address_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
require 'test_helper'

module Landrush
module Cap
module All
describe ReadHostVisibleIpAddress do
let(:machine) { fake_machine }
let(:addresses) { fake_addresses }

def call_cap(machine)
Landrush::Cap::All::ReadHostVisibleIpAddress.read_host_visible_ip_address(machine)
end

before do
# TODO: Is there a way to only unstub it for read_host_visible_ip_address
machine.guest.unstub(:capability)
machine.guest.stubs(:capability).with(:landrush_ip_get).returns(fake_addresses)
end

describe 'read_host_visible_ip_address' do
# First, test with an empty response (no addresses)
it 'should throw an error when there are no addresses' do
machine.guest.stubs(:capability).with(:landrush_ip_get).returns([])

lambda do
call_cap(machine)
end.must_raise(RuntimeError, 'No addresses found')
end

# Step 1: nothing excluded, nothing explicitly selected
it 'should return the last address' do
machine.config.landrush.interface = nil
machine.config.landrush.exclude = []

expected = addresses.last['ipv4']

# call_cap(machine).must_equal expected
call_cap(machine).must_equal expected
end

# Test exclusion mechanics; it should select the las
it 'should ignore interfaces that are excluded and select the last not excluded interface' do
machine.config.landrush.interface = nil
machine.config.landrush.exclude = [/exclude[0-9]+/]

expected = addresses.detect { |a| a['name'] == 'include3' }
expected = expected['ipv4']

call_cap(machine).must_equal expected
end

# Explicitly select one; this supersedes the exclusion mechanic
it 'should select the desired interface' do
machine.config.landrush.interface = 'include1'
machine.config.landrush.exclude = [/exclude[0-9]+/]

expected = addresses.detect { |a| a['name'] == 'include1' }
expected = expected['ipv4']

call_cap(machine).must_equal expected
end

# Now make sure it returns the last not excluded interface when the desired interface does not exist
it 'should return the last not excluded interface if the desired interface does not exist' do
machine.config.landrush.interface = 'dummy'
machine.config.landrush.exclude = [/exclude[0-9]+/]

expected = addresses.detect { |a| a['name'] == 'include3' }
expected = expected['ipv4']

call_cap(machine).must_equal expected
end

# Now make sure it returns the last interface overall when nothing is excluded
it 'should return the last interface if the desired interface does not exist' do
machine.config.landrush.interface = 'dummy'
machine.config.landrush.exclude = []

expected = addresses.last['ipv4']

call_cap(machine).must_equal expected
end
end
end
end
end
end
39 changes: 0 additions & 39 deletions test/landrush/cap/linux/read_host_visible_ip_address_test.rb

This file was deleted.

Loading