Use arp to grab container ip instead of dig (it seems to be more reliable)

References: #31
This commit is contained in:
Fabio Rehm 2013-03-10 01:54:33 -03:00
parent 238b5cd681
commit d2a1eeeabc
7 changed files with 88 additions and 34 deletions

1
example/Vagrantfile vendored
View file

@ -24,7 +24,6 @@ Vagrant.configure("2") do |config|
config.vm.synced_folder cache_dir, "/var/cache/apt/archives" config.vm.synced_folder cache_dir, "/var/cache/apt/archives"
config.vm.provider :lxc do |lxc| config.vm.provider :lxc do |lxc|
lxc.lxc_dhcp_ip = '10.0.254.1' if ENV['USER'] == 'vagrant'
lxc.start_opts << 'lxc.cgroup.memory.limit_in_bytes=400M' lxc.start_opts << 'lxc.cgroup.memory.limit_in_bytes=400M'
lxc.start_opts << 'lxc.cgroup.memory.memsw.limit_in_bytes=500M' lxc.start_opts << 'lxc.cgroup.memory.memsw.limit_in_bytes=500M'
end end

View file

@ -6,15 +6,8 @@ module Vagrant
# @return [Array] # @return [Array]
attr_reader :start_opts attr_reader :start_opts
# The ip set for the built in LXC dhcp server (defaults to configured ip
# at /etc/default/lxc or 10.0.3.1)
#
# @return [String]
attr_accessor :lxc_dhcp_ip
def initialize def initialize
@start_opts = [] @start_opts = []
@lxc_dhcp_ip = '10.0.3.1'
end end
end end
end end

View file

@ -9,6 +9,9 @@ require "vagrant-lxc/errors"
module Vagrant module Vagrant
module LXC module LXC
class Container class Container
# Root folder where containers are stored
CONTAINERS_PATH = '/var/lib/lxc'
# Include this so we can use `Subprocess` more easily. # Include this so we can use `Subprocess` more easily.
include Vagrant::Util::Retryable include Vagrant::Util::Retryable
@ -16,8 +19,6 @@ module Vagrant
# a name. # a name.
class NotFound < StandardError; end class NotFound < StandardError; end
CONTAINERS_PATH = '/var/lib/lxc'
attr_reader :name attr_reader :name
def initialize(name) def initialize(name)
@ -29,6 +30,14 @@ module Vagrant
raise NotFound if @name && ! lxc(:ls).split("\n").include?(@name) raise NotFound if @name && ! lxc(:ls).split("\n").include?(@name)
end end
def base_path
Pathname.new("#{CONTAINERS_PATH}/#{@name}")
end
def rootfs_path
Pathname.new("#{base_path}/rootfs")
end
def create(metadata = {}) def create(metadata = {})
# FIXME: Ruby 1.8 users dont have SecureRandom # FIXME: Ruby 1.8 users dont have SecureRandom
@logger.debug('Creating container using lxc-create...') @logger.debug('Creating container using lxc-create...')
@ -52,10 +61,6 @@ module Vagrant
@name @name
end end
def rootfs_path
Pathname.new("#{CONTAINERS_PATH}/#{@name}/rootfs")
end
def share_folders(folders, config) def share_folders(folders, config)
folders.each do |folder| folders.each do |folder|
guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, '')) guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, ''))
@ -109,15 +114,18 @@ module Vagrant
end end
end end
def dhcp_ip(server_ip) def assigned_ip
unless File.read(base_path.join('config')) =~ /^lxc\.network\.hwaddr\s*=\s*([a-z0-9:]+)\s*$/
raise 'Unknown Container MAC Address'
end
mac_addr = $1
#`ip neigh flush all > /dev/null`
ip = '' ip = ''
# Right after creation lxc reports the container as running # See: http://programminglinuxblog.blogspot.com.br/2007/11/detecting-ip-address-from-mac-address.html
# before DNS is returning the right IP, so have to wait for a while
retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do
# By default LXC supplies a dns server on 10.0.3.1 so we request the IP r = (raw 'arp', '-n')
# of our target from there.
# Tks to: https://github.com/neerolyte/vagueant/blob/master/bin/vagueant#L340
r = (raw 'dig', @name, "@#{server_ip}", '+short')
# If the command was a failure then raise an exception that is nicely # If the command was a failure then raise an exception that is nicely
# handled by Vagrant. # handled by Vagrant.
@ -125,14 +133,15 @@ module Vagrant
if @interrupted if @interrupted
@logger.info("Exit code != 0, but interrupted. Ignoring.") @logger.info("Exit code != 0, but interrupted. Ignoring.")
else else
raise LXC::Errors::ExecuteError, :command => ['dig', @name, "@#{server_ip}", '+short'].inspect raise LXC::Errors::ExecuteError, :command => ['arp', '-n'].inspect
end end
end end
ip = r.stdout.gsub("\r\n", "\n").strip
if ip.empty? unless r.stdout.gsub("\r\n", "\n").strip =~ /^([0-9.]+).+#{Regexp.escape mac_addr}/
raise LXC::Errors::ExecuteError, 'Unable to identify container ip' raise LXC::Errors::ExecuteError, 'Unable to identify container ip'
end end
ip = $1.to_s
# Sometimes lxc reports the container as running before DNS is returning # Sometimes lxc reports the container as running before DNS is returning
# the right IP, so have to try a couple of times sometimes. # the right IP, so have to try a couple of times sometimes.

View file

@ -52,7 +52,7 @@ module Vagrant
return nil if state == :not_created return nil if state == :not_created
{ {
:host => @container.dhcp_ip(@machine.provider_config.lxc_dhcp_ip), :host => @container.assigned_ip,
:port => 22 # @driver.ssh_port(@machine.config.ssh.guest_port) :port => 22 # @driver.ssh_port(@machine.config.ssh.guest_port)
} }
end end

4
spec/fixtures/sample-arp-output vendored Normal file
View file

@ -0,0 +1,4 @@
Address HWtype HWaddress Flags Mask Iface
120.0.3.30 ether 10:16:3e:c8:f9:b7 C lxcbr0
10.0.3.30 ether 00:16:3e:64:d6:74 C lxcbr0
192.168.25.1 ether 2c:e4:12:95:90:45 C wlan0

47
spec/fixtures/sample-config vendored Normal file
View file

@ -0,0 +1,47 @@
lxc.network.type=veth
lxc.network.link=lxcbr0
lxc.network.flags=up
lxc.network.hwaddr = 00:16:3e:64:d6:74
lxc.rootfs = /var/lib/lxc/a91df47bfc6e/rootfs
lxc.utsname = a91df47bfc6e
lxc.devttydir = lxc
lxc.tty = 4
lxc.pts = 1024
lxc.mount = /var/lib/lxc/a91df47bfc6e/fstab
lxc.arch = amd64
lxc.cap.drop = sys_module mac_admin mac_override
lxc.pivotdir = lxc_putold
# uncomment the next line to run the container unconfined:
#lxc.aa_profile = unconfined
lxc.cgroup.devices.deny = a
# Allow any mknod (but not using the node)
lxc.cgroup.devices.allow = c *:* m
lxc.cgroup.devices.allow = b *:* m
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
#lxc.cgroup.devices.allow = c 4:0 rwm
#lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
#fuse
lxc.cgroup.devices.allow = c 10:229 rwm
#tun
lxc.cgroup.devices.allow = c 10:200 rwm
#full
lxc.cgroup.devices.allow = c 1:7 rwm
#hpet
lxc.cgroup.devices.allow = c 10:228 rwm
#kvm
lxc.cgroup.devices.allow = c 10:232 rwm

View file

@ -4,7 +4,6 @@ require "vendored_vagrant"
require 'vagrant-lxc/container' require 'vagrant-lxc/container'
describe Vagrant::LXC::Container do describe Vagrant::LXC::Container do
# Default subject and container name for specs
let(:name) { nil } let(:name) { nil }
subject { described_class.new(name) } subject { described_class.new(name) }
@ -181,20 +180,23 @@ describe Vagrant::LXC::Container do
end end
end end
describe 'dhcp ip' do describe 'assigned ip' do
let(:name) { 'random-container-name' } # This ip is set on the sample-arp-output based on mac address from sample-config
let(:ip) { "10.0.4.123" } let(:ip) { "10.0.3.30" }
let(:server_ip) { "10.0.4.1" } let(:conf_file_contents) { File.read('spec/fixtures/sample-config') }
let(:name) { 'random-container-name' }
before do before do
@arp_output = File.read('spec/fixtures/sample-arp-output')
subject.stub(:raw) { subject.stub(:raw) {
mock(stdout: "#{ip}\n", exit_code: 0) mock(stdout: "#{@arp_output}\n", exit_code: 0)
} }
File.stub(read: conf_file_contents)
end end
it 'digs the container ip from lxc dns server' do it 'gets parsed from `arp` based on lxc mac address' do
subject.dhcp_ip(server_ip).should == ip subject.assigned_ip.should == ip
subject.should have_received(:raw).with('dig', name, "@#{server_ip}", '+short') subject.should have_received(:raw).with('arp', '-n')
end end
end end
end end