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