lib/vagrant-libvirt/driver.rb in vagrant-libvirt-0.5.3 vs lib/vagrant-libvirt/driver.rb in vagrant-libvirt-0.6.0
- old
+ new
@@ -1,29 +1,34 @@
+# frozen_string_literal: true
+
require 'fog/libvirt'
require 'libvirt'
require 'log4r'
+require 'json'
module VagrantPlugins
module ProviderLibvirt
class Driver
- # store the connection at the process level
+ # store the connection at the instance level as this will be per
+ # thread and allows for individual machines to use different
+ # connection settings.
#
# possibly this should be a connection pool using the connection
- # settings as a key to allow per machine connection attributes
- # to be used.
- @@connection = nil
- @@system_connection = nil
+ # settings as a key to allow identical connections to be reused
+ # across machines.
+ @connection = nil
+ @system_connection = nil
def initialize(machine)
@logger = Log4r::Logger.new('vagrant_libvirt::driver')
@machine = machine
end
def connection
# If already connected to Libvirt, just use it and don't connect
# again.
- return @@connection if @@connection
+ return @connection if @connection
# Get config options for Libvirt provider.
config = @machine.provider_config
uri = config.uri
@@ -38,28 +43,28 @@
ip_command = %q( awk "/$mac/ {print \$1}" /proc/net/arp )
conn_attr[:libvirt_ip_command] = ip_command
@logger.info("Connecting to Libvirt (#{uri}) ...")
begin
- @@connection = Fog::Compute.new(conn_attr)
+ @connection = Fog::Compute.new(conn_attr)
rescue Fog::Errors::Error => e
raise Errors::FogLibvirtConnectionError,
error_message: e.message
end
- @@connection
+ @connection
end
def system_connection
# If already connected to Libvirt, just use it and don't connect
# again.
- return @@system_connection if @@system_connection
+ return @system_connection if @system_connection
config = @machine.provider_config
- @@system_connection = Libvirt::open_read_only(config.system_uri)
- @@system_connection
+ @system_connection = Libvirt::open(config.system_uri)
+ @system_connection
end
def get_domain(machine)
begin
domain = connection.servers.get(machine.id)
@@ -95,10 +100,16 @@
def get_domain_ipaddress(machine, domain)
if @machine.provider_config.qemu_use_session
return get_ipaddress_from_system domain.mac
end
+ # attempt to get ip address from qemu agent
+ if @machine.provider_config.qemu_use_agent == true
+ @logger.info('Get IP via qemu agent')
+ return get_ipaddress_from_qemu_agent(domain, machine.id)
+ end
+
# Get IP address from dhcp leases table
begin
ip_address = get_ipaddress_from_domain(domain)
rescue Fog::Errors::TimeoutError
@logger.info('Timeout at waiting for an ip address for machine %s' % machine.name)
@@ -124,11 +135,21 @@
end
# TODO: terminated no longer appears to be a valid fog state, remove?
return :not_created if domain.nil? || domain.state.to_sym == :terminated
- domain.state.tr('-', '_').to_sym
+ state = domain.state.tr('-', '_').to_sym
+ if state == :running
+ begin
+ get_domain_ipaddress(machine, domain)
+ rescue Fog::Errors::TimeoutError => e
+ @logger.debug("Machine #{machine.id} running but no IP address available: #{e}.")
+ return :inaccessible
+ end
+ end
+
+ return state
end
private
def get_ipaddress_from_system(mac)
@@ -139,9 +160,43 @@
# Assume the lease expiring last is the current IP address
ip_address = leases.sort_by { |lse| lse["expirytime"] }.last["ipaddr"] if !leases.empty?
break if ip_address
end
+ ip_address
+ end
+
+ def get_ipaddress_from_qemu_agent(domain, machine_id)
+ ip_address = nil
+ addresses = nil
+ dom = system_connection.lookup_domain_by_uuid(machine_id)
+ begin
+ response = dom.qemu_agent_command('{"execute":"guest-network-get-interfaces"}', timeout=10)
+ @logger.debug("Got Response from qemu agent")
+ @logger.debug(response)
+ addresses = JSON.parse(response)
+ rescue => e
+ @logger.debug("Unable to receive IP via qemu agent: [%s]" % e.message)
+ end
+
+ unless addresses.nil?
+ addresses["return"].each{ |interface|
+ if domain.mac == interface["hardware-address"]
+ @logger.debug("Found mathing interface: [%s]" % interface["name"])
+ if interface.has_key?("ip-addresses")
+ interface["ip-addresses"].each{ |ip|
+ # returning ipv6 addresses might break windows guests because
+ # winrm cant handle connection, winrm fails with "invalid uri"
+ if ip["ip-address-type"] == "ipv4"
+ ip_address = ip["ip-address"]
+ @logger.debug("Return IP: [%s]" % ip_address)
+ break
+ end
+ }
+ end
+ end
+ }
+ end
ip_address
end
def get_ipaddress_from_domain(domain)
ip_address = nil