IP of VM is searched in dnsmasq lease files only.

This commit is contained in:
pradels
2013-04-10 17:34:09 +02:00
parent 0df992d3c1
commit e98c64c0be
6 changed files with 45 additions and 79 deletions

View File

@@ -34,7 +34,7 @@ $ vagrant plugin install vagrant-libvirt
### Possible problems with plugin installation
In case of problems with building nokogiri gem, install missing development
libraries libxslt and libxml2.
libraries for libxslt, libxml2 and libvirt.
In Ubuntu, Debian, ...
```
@@ -55,7 +55,6 @@ want. This is just an example of Libvirt CentOS 6.4 box available:
```
$ vagrant box add centos64 http://kwok.cz/centos64.box
...
```
And then make a Vagrantfile that looks like the following, filling in
@@ -96,7 +95,6 @@ In prepared project directory, run following command:
```
$ vagrant up --provider=libvirt
...
```
Vagrant needs to know that we want to use Libvirt and not default VirtualBox.
@@ -106,6 +104,8 @@ Vagrant to use Libvirt provider is to setup environment variable
### How Project Is Created
Vagrant goes through steps below when creating new project:
1. Connect to Libvirt localy or remotely via SSH.
2. Check if box image is available in Libvirt storage pool. If not, upload it to
remote Libvirt storage pool as new volume.
@@ -114,7 +114,8 @@ Vagrant to use Libvirt provider is to setup environment variable
5. Check for DHCP lease from dnsmasq server. Store IP address into
machines *data_dir* for later use, when lease information is not
available. Then wait till SSH is available.
6. Sync folders via `rsync` and run Vagrant provisioner on new domain.
6. Sync folders via `rsync` and run Vagrant provisioner on new domain if
setup in Vagrantfile.
## Networks
@@ -135,16 +136,13 @@ defined.
## Obtaining Domain IP Address
Libvirt doesn't provide a way to find out an IP address of running domain. We
can get domains MAC address only. So to get an IP address, Libvirt provider is
checking dnsmasq leases files in `/var/lib/libvirt/dnsmasq` directory. After
IP address is known, it's stored into machines *data_dir* for later use, because
lease information disappears after some time.
Possible problem raises when machines IP was changed since last write into
*data_dir*. Libvirt provider first checks, if IP address matches with domains MAC
address. If not, error is writen to user. As possible solution in this
situation occurs `fping` or `nmap` command to ping whole network.
Libvirt doesn't provide standard way how to find out an IP address of running
domain. But we know, what is MAC address of virtual machine. Libvirt is closely
connected with dnsmasq server, which acts also as a DHCP server. Dnsmasq server
makes lease information public in `/var/lib/libvirt/dnsmasq` directory, or in
`/var/lib/misc/dnsmasq.leases` file on some systems. This is the place, where
information like which MAC address has which IP address resides and it's parsed
by vagrant-libvirt plugin.
## Synced Folders
@@ -185,7 +183,14 @@ $ bundle exec rake
If those pass, you're ready to start developing the plugin. You can test
the plugin without installing it into your Vagrant environment by just
creating a `Vagrantfile` in the top level of this directory (it is gitignored)
that uses it, and uses bundler to execute Vagrant:
that uses it. Don't forget to add following line at the beginning of your
`Vagrantfile` while in development mode:
```ruby
Vagrant.require_plugin "vagrant-libvirt"
```
Now you can use bundler to execute Vagrant:
```
$ bundle exec vagrant up --provider=libvirt

View File

@@ -48,9 +48,14 @@ module VagrantPlugins
conn_attr[:libvirt_password] = config.password if config.password
# Setup command for retrieving IP address for newly created machine
# with some MAC address. Get it from dnsmasq leases table.
conn_attr[:libvirt_ip_command] = "cat /var/lib/libvirt/dnsmasq/*.leases"
conn_attr[:libvirt_ip_command] << " | grep $mac | awk ' { print $3 }'"
# with some MAC address. Get it from dnsmasq leases table - either
# /var/lib/libvirt/dnsmasq/*.leases files, or
# /var/lib/misc/dnsmasq.leases if available.
ip_command = "LEASES='/var/lib/libvirt/dnsmasq/*.leases'; "
ip_command << "[ -f /var/lib/misc/dnsmasq.leases ] && "
ip_command << "LEASES='/var/lib/misc/dnsmasq.leases'; "
ip_command << "cat $LEASES | grep $mac | awk '{ print $3 }'"
conn_attr[:libvirt_ip_command] = ip_command
@logger.info("Connecting to Libvirt (#{uri}) ...")
begin

View File

@@ -18,7 +18,7 @@ module VagrantPlugins
@app.call(env)
end
def read_ssh_info(libvirt,machine)
def read_ssh_info(libvirt, machine)
return nil if machine.id.nil?
# Find the machine
@@ -30,53 +30,24 @@ module VagrantPlugins
return nil
end
# IP address of machine is stored in $data_dir/ip file. Why? Commands
# like ssh or provision need to get IP of VM long time after it was
# started and gathered IP. Record in arp table is lost, and this is
# the way how to store this info. Not an ideal solution, but libvirt
# doesn't provide way how to get IP of some domain.
ip_file = machine.data_dir + 'ip'
raise Errors::NoIpAddressError if not File.exists?(ip_file)
ip_address = File.open(ip_file, 'r') do |file|
file.read
end
# Check if stored IP address matches with MAC address of machine.
# Command is executed either localy, or on remote libvirt hypervisor,
# depends on establised fog libvirt connection.
ip_match = false
ip_command = "ping -c1 #{ip_address} > /dev/null && "
ip_command << "arp -an | grep $mac | sed '"
ip_command << 's/.*(\([0-9\.]*\)).*/\1/' + "'"
options_hash = { :ip_command => ip_command }
3.times do |x|
break if ip_match
domain.wait_for(1) {
begin
addresses(service, options_hash).each_pair do |type, ip|
if ip[0] != nil
ip_match = true
break
end
end
rescue Fog::Errors::Error
# Sometimes, if pinging happen too quickly after after IP
# assignment, machine is not responding yet. Give it a little
# time..
sleep 1
end
break if ip_match
}
end
raise Errors::IpAddressMismatchError if not ip_match
# Get IP address from dnsmasq lease file.
ip_address = nil
domain.wait_for(2) {
addresses.each_pair do |type, ip|
ip_address = ip[0] if ip[0] != nil
end
ip_address != nil
}
raise Errors::NoIpAddressError if not ip_address
# Return the info
# TODO: Some info should be configurable in Vagrantfile
return {
:host => ip_address,
:port => 22,
:username => 'root',
:host => ip_address,
:port => 22,
:username => 'root',
:forward_agent => true,
:forward_x11 => true,
}
end
end

View File

@@ -37,7 +37,7 @@ module VagrantPlugins
# Wait for domain to obtain an ip address
domain.wait_for(2) {
addresses.each_pair do |type, ip|
env[:ip_address] = ip[0]
env[:ip_address] = ip[0] if ip[0] != nil
end
env[:ip_address] != nil
}
@@ -47,13 +47,6 @@ module VagrantPlugins
@logger.info("Got IP address #{env[:ip_address]}")
@logger.info("Time for getting IP: #{env[:metrics]["instance_ip_time"]}")
# Save newly assigned IP address to machines data_dir
ip_file_path = env[:machine].data_dir + 'ip'
@logger.info("Saving IP address to #{ip_file_path} file.")
File.open(ip_file_path, 'w') do |file|
file.write(env[:ip_address])
end
# Machine has ip address assigned, now wait till we are able to
# connect via ssh.
env[:metrics]["instance_ssh_time"] = Util::Timer.time do

View File

@@ -90,10 +90,6 @@ module VagrantPlugins
error_key(:no_ip_address_error)
end
class IpAddressMismatchError < VagrantLibvirtError
error_key(:ip_address_mismatch_error)
end
end
end
end

View File

@@ -101,10 +101,6 @@ en:
Error while attaching new device to domain. %{error_message}
no_ip_address_error: |-
No IP address found.
ip_address_mismatch_error: |-
IP address mismatch. Possible reason is that domain IP address changed.
You can run `vagrant destroy` and then `vagrant up` to rebuild your
project.
states:
short_paused: |-