From d2a1eeeabca61af29971ad51ff49d5c3987a7aa0 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Sun, 10 Mar 2013 01:54:33 -0300 Subject: [PATCH] Use `arp` to grab container ip instead of `dig` (it seems to be more reliable) References: #31 --- example/Vagrantfile | 1 - lib/vagrant-lxc/config.rb | 7 ----- lib/vagrant-lxc/container.rb | 41 +++++++++++++++++----------- lib/vagrant-lxc/provider.rb | 2 +- spec/fixtures/sample-arp-output | 4 +++ spec/fixtures/sample-config | 47 +++++++++++++++++++++++++++++++++ spec/unit/container_spec.rb | 20 +++++++------- 7 files changed, 88 insertions(+), 34 deletions(-) create mode 100644 spec/fixtures/sample-arp-output create mode 100644 spec/fixtures/sample-config diff --git a/example/Vagrantfile b/example/Vagrantfile index 081748a..941582a 100644 --- a/example/Vagrantfile +++ b/example/Vagrantfile @@ -24,7 +24,6 @@ Vagrant.configure("2") do |config| config.vm.synced_folder cache_dir, "/var/cache/apt/archives" 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.memsw.limit_in_bytes=500M' end diff --git a/lib/vagrant-lxc/config.rb b/lib/vagrant-lxc/config.rb index b03f662..bd923ac 100644 --- a/lib/vagrant-lxc/config.rb +++ b/lib/vagrant-lxc/config.rb @@ -6,15 +6,8 @@ module Vagrant # @return [Array] 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 @start_opts = [] - @lxc_dhcp_ip = '10.0.3.1' end end end diff --git a/lib/vagrant-lxc/container.rb b/lib/vagrant-lxc/container.rb index 883a782..3d3e8ed 100644 --- a/lib/vagrant-lxc/container.rb +++ b/lib/vagrant-lxc/container.rb @@ -9,6 +9,9 @@ require "vagrant-lxc/errors" module Vagrant module LXC class Container + # Root folder where containers are stored + CONTAINERS_PATH = '/var/lib/lxc' + # Include this so we can use `Subprocess` more easily. include Vagrant::Util::Retryable @@ -16,8 +19,6 @@ module Vagrant # a name. class NotFound < StandardError; end - CONTAINERS_PATH = '/var/lib/lxc' - attr_reader :name def initialize(name) @@ -29,6 +30,14 @@ module Vagrant raise NotFound if @name && ! lxc(:ls).split("\n").include?(@name) end + def base_path + Pathname.new("#{CONTAINERS_PATH}/#{@name}") + end + + def rootfs_path + Pathname.new("#{base_path}/rootfs") + end + def create(metadata = {}) # FIXME: Ruby 1.8 users dont have SecureRandom @logger.debug('Creating container using lxc-create...') @@ -52,10 +61,6 @@ module Vagrant @name end - def rootfs_path - Pathname.new("#{CONTAINERS_PATH}/#{@name}/rootfs") - end - def share_folders(folders, config) folders.each do |folder| guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, '')) @@ -109,15 +114,18 @@ module Vagrant 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 = '' - # Right after creation lxc reports the container as running - # before DNS is returning the right IP, so have to wait for a while + # See: http://programminglinuxblog.blogspot.com.br/2007/11/detecting-ip-address-from-mac-address.html 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 - # of our target from there. - # Tks to: https://github.com/neerolyte/vagueant/blob/master/bin/vagueant#L340 - r = (raw 'dig', @name, "@#{server_ip}", '+short') + r = (raw 'arp', '-n') # If the command was a failure then raise an exception that is nicely # handled by Vagrant. @@ -125,14 +133,15 @@ module Vagrant if @interrupted @logger.info("Exit code != 0, but interrupted. Ignoring.") else - raise LXC::Errors::ExecuteError, :command => ['dig', @name, "@#{server_ip}", '+short'].inspect + raise LXC::Errors::ExecuteError, :command => ['arp', '-n'].inspect 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' end + ip = $1.to_s # Sometimes lxc reports the container as running before DNS is returning # the right IP, so have to try a couple of times sometimes. diff --git a/lib/vagrant-lxc/provider.rb b/lib/vagrant-lxc/provider.rb index 38629cb..f1f2bdc 100644 --- a/lib/vagrant-lxc/provider.rb +++ b/lib/vagrant-lxc/provider.rb @@ -52,7 +52,7 @@ module Vagrant 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) } end diff --git a/spec/fixtures/sample-arp-output b/spec/fixtures/sample-arp-output new file mode 100644 index 0000000..0b68ed4 --- /dev/null +++ b/spec/fixtures/sample-arp-output @@ -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 diff --git a/spec/fixtures/sample-config b/spec/fixtures/sample-config new file mode 100644 index 0000000..3fe64a9 --- /dev/null +++ b/spec/fixtures/sample-config @@ -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 diff --git a/spec/unit/container_spec.rb b/spec/unit/container_spec.rb index 0293943..fd6428a 100644 --- a/spec/unit/container_spec.rb +++ b/spec/unit/container_spec.rb @@ -4,7 +4,6 @@ require "vendored_vagrant" require 'vagrant-lxc/container' describe Vagrant::LXC::Container do - # Default subject and container name for specs let(:name) { nil } subject { described_class.new(name) } @@ -181,20 +180,23 @@ describe Vagrant::LXC::Container do end end - describe 'dhcp ip' do - let(:name) { 'random-container-name' } - let(:ip) { "10.0.4.123" } - let(:server_ip) { "10.0.4.1" } + describe 'assigned ip' do + # This ip is set on the sample-arp-output based on mac address from sample-config + let(:ip) { "10.0.3.30" } + let(:conf_file_contents) { File.read('spec/fixtures/sample-config') } + let(:name) { 'random-container-name' } before do + @arp_output = File.read('spec/fixtures/sample-arp-output') 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 - it 'digs the container ip from lxc dns server' do - subject.dhcp_ip(server_ip).should == ip - subject.should have_received(:raw).with('dig', name, "@#{server_ip}", '+short') + it 'gets parsed from `arp` based on lxc mac address' do + subject.assigned_ip.should == ip + subject.should have_received(:raw).with('arp', '-n') end end end