mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2025-02-25 18:55:27 -06:00
Merge pull request #1343 from abbbi/1341_poc
Retrieve IP Address of management interface using qemu-guest-agent commands #1341
This commit is contained in:
commit
e9213b6caa
17
README.md
17
README.md
@ -933,6 +933,23 @@ DHCP server. dnsmasq writes lease information in the `/var/lib/libvirt/dnsmasq`
|
||||
directory. Vagrant-libvirt looks for the MAC address in this file and extracts
|
||||
the corresponding IP address.
|
||||
|
||||
It is also possible to use the Qemu Agent to extract the management interface
|
||||
configuration from the booted virtual machine. This is helpful in libvirt
|
||||
environments where no local dnsmasq is used for automatic address assigment,
|
||||
but external dhcp services via bridged libvirt networks.
|
||||
|
||||
Prerequisite is to enable the qemu agent channel via ([Libvirt communication
|
||||
channels](#libvirt-communication-channels)) and the virtual machine image must
|
||||
have the agent pre-installed before deploy. The agent will start automatically
|
||||
if it detects an attached channel during boot.
|
||||
|
||||
* `qemu_use_agent` - false by default, if set to true, attempt to extract configured
|
||||
ip address via qemu agent.
|
||||
|
||||
To use the management network interface with an external dhcp service you need
|
||||
to setup a bridged host network manually and define it via
|
||||
`management_network_name` in your Vagrantfile.
|
||||
|
||||
## Additional Disks
|
||||
|
||||
You can create and attach additional disks to a VM via `libvirt.storage :file`.
|
||||
|
@ -162,7 +162,7 @@ module VagrantPlugins
|
||||
if @interface_network[:created]
|
||||
# Just check for mismatch error here - if name and ip from
|
||||
# config match together.
|
||||
if @options[:network_name] != @interface_network[:name]
|
||||
if @options[:network_name] != @interface_network[:name] and @qemu_use_agent = false
|
||||
raise Errors::NetworkNameAndAddressMismatch,
|
||||
ip_address: @options[:ip],
|
||||
network_name: @options[:network_name]
|
||||
|
@ -193,6 +193,9 @@ module VagrantPlugins
|
||||
# Use QEMU session instead of system
|
||||
attr_accessor :qemu_use_session
|
||||
|
||||
# Use QEMU Agent to get ip address
|
||||
attr_accessor :qemu_use_agent
|
||||
|
||||
def initialize
|
||||
@uri = UNSET_VALUE
|
||||
@driver = UNSET_VALUE
|
||||
@ -332,6 +335,9 @@ module VagrantPlugins
|
||||
@qemu_env = UNSET_VALUE
|
||||
|
||||
@qemu_use_session = UNSET_VALUE
|
||||
|
||||
# Use Qemu agent to get ip address
|
||||
@qemu_use_agent = UNSET_VALUE
|
||||
end
|
||||
|
||||
def boot(device)
|
||||
@ -936,6 +942,8 @@ module VagrantPlugins
|
||||
|
||||
# Additional QEMU commandline environment variables
|
||||
@qemu_env = {} if @qemu_env == UNSET_VALUE
|
||||
|
||||
@qemu_use_agent = true if @qemu_use_agent != UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
@ -949,6 +957,17 @@ module VagrantPlugins
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if @qemu_use_agent == true
|
||||
# if qemu agent is used to optain domain ip configuration, at least
|
||||
# one qemu channel has to be configured. As there are various options,
|
||||
# error out and leave configuration to the user
|
||||
unless machine.provider_config.channels.any? { |channel| channel[:target_name].start_with?("org.qemu.guest_agent") }
|
||||
errors << "qemu agent option enabled, but no qemu agent channel configured: please add at least one qemu agent channel to vagrant config"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
machine.provider_config.disks.each do |disk|
|
||||
if disk[:path] && (disk[:path][0] == '/')
|
||||
errors << "absolute volume paths like '#{disk[:path]}' not yet supported"
|
||||
|
@ -3,6 +3,7 @@
|
||||
require 'fog/libvirt'
|
||||
require 'libvirt'
|
||||
require 'log4r'
|
||||
require 'json'
|
||||
|
||||
module VagrantPlugins
|
||||
module ProviderLibvirt
|
||||
@ -58,7 +59,7 @@ module VagrantPlugins
|
||||
|
||||
config = @machine.provider_config
|
||||
|
||||
@@system_connection = Libvirt::open_read_only(config.system_uri)
|
||||
@@system_connection = Libvirt::open(config.system_uri)
|
||||
@@system_connection
|
||||
end
|
||||
|
||||
@ -99,6 +100,12 @@ module VagrantPlugins
|
||||
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)
|
||||
@ -146,6 +153,40 @@ module VagrantPlugins
|
||||
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
|
||||
domain.wait_for(2) do
|
||||
|
@ -20,6 +20,7 @@ module VagrantPlugins
|
||||
|
||||
def configured_networks(env, logger)
|
||||
qemu_use_session = env[:machine].provider_config.qemu_use_session
|
||||
qemu_use_agent = env[:machine].provider_config.qemu_use_agent
|
||||
management_network_device = env[:machine].provider_config.management_network_device
|
||||
management_network_name = env[:machine].provider_config.management_network_name
|
||||
management_network_address = env[:machine].provider_config.management_network_address
|
||||
|
13
tests/qemu_agent/Vagrantfile
vendored
Normal file
13
tests/qemu_agent/Vagrantfile
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
#
|
||||
# frozen_string_literal: true
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "generic/debian10"
|
||||
config.vm.synced_folder ".", "/vagrant", disabled: true
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
libvirt.channel :type => 'unix', :target_name => 'org.qemu.guest_agent.0', :target_type => 'virtio'
|
||||
libvirt.qemu_use_agent = true
|
||||
end
|
||||
end
|
@ -119,6 +119,17 @@ cleanup() {
|
||||
cleanup
|
||||
}
|
||||
|
||||
@test "bring up and use qemu agent for connectivity" {
|
||||
export VAGRANT_CWD=tests/qemu_agent
|
||||
cleanup
|
||||
run ${VAGRANT_CMD} up ${VAGRANT_OPT}
|
||||
echo "${output}"
|
||||
echo "status = ${status}"
|
||||
[ "$status" -eq 0 ]
|
||||
echo "${output}"
|
||||
cleanup
|
||||
}
|
||||
|
||||
@test "ip is reachable with private network" {
|
||||
export VAGRANT_CWD=tests/private_network
|
||||
cleanup
|
||||
|
Loading…
Reference in New Issue
Block a user