mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2025-02-25 18:55:27 -06:00
Query host interfaces directly as libvirt may not include them (#1627)
On some distros the libvirt does not appear to always return all of the host interfaces. Switch to using 'ip -j link show' to read them directly from the system in order to ensure all devices are read. Refactor the driver tests to better isolate between test setup for the different sets of functions and avoid accidental setting of configuration details that may not be obvious. Fixes: #1624
This commit is contained in:
@@ -110,7 +110,7 @@ module VagrantPlugins
|
|||||||
end
|
end
|
||||||
).map { |s| ['-o', s] }.flatten
|
).map { |s| ['-o', s] }.flatten
|
||||||
|
|
||||||
options += ['-o', "ProxyCommand=\"#{ssh_info[:proxy_command]}\""] if machine.provider_config.proxy_command
|
options += ['-o', "ProxyCommand=\"#{ssh_info[:proxy_command]}\""] if machine.provider_config.proxy_command && !machine.provider_config.proxy_command.empty?
|
||||||
|
|
||||||
ssh_cmd = ['ssh'] + options + params
|
ssh_cmd = ['ssh'] + options + params
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ module VagrantPlugins
|
|||||||
|
|
||||||
# The name of the server, where Libvirtd is running.
|
# The name of the server, where Libvirtd is running.
|
||||||
attr_accessor :host
|
attr_accessor :host
|
||||||
|
attr_accessor :port
|
||||||
|
|
||||||
# If use ssh tunnel to connect to Libvirt.
|
# If use ssh tunnel to connect to Libvirt.
|
||||||
attr_accessor :connect_via_ssh
|
attr_accessor :connect_via_ssh
|
||||||
@@ -1218,16 +1219,11 @@ module VagrantPlugins
|
|||||||
end
|
end
|
||||||
|
|
||||||
def host_devices(machine)
|
def host_devices(machine)
|
||||||
@host_devices ||= begin
|
machine.provider.driver.host_devices.select do |dev|
|
||||||
(
|
|
||||||
machine.provider.driver.list_host_devices.map { |iface| iface.name } +
|
|
||||||
machine.provider.driver.list_networks.map { |net| net.bridge_name }
|
|
||||||
).uniq.select do |dev|
|
|
||||||
next if dev.empty?
|
next if dev.empty?
|
||||||
dev != "lo" && !@host_device_exclude_prefixes.any? { |exclude| dev.start_with?(exclude) }
|
dev != "lo" && !@host_device_exclude_prefixes.any? { |exclude| dev.start_with?(exclude) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def validate_sysinfo(machine, errors)
|
def validate_sysinfo(machine, errors)
|
||||||
valid_sysinfo = {
|
valid_sysinfo = {
|
||||||
|
|||||||
@@ -197,12 +197,28 @@ module VagrantPlugins
|
|||||||
domain
|
domain
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_host_devices
|
def host_devices
|
||||||
connection.client.list_all_interfaces
|
@host_devices ||= begin
|
||||||
|
cmd = []
|
||||||
|
unless @machine.provider_config.proxy_command.nil? || @machine.provider_config.proxy_command.empty?
|
||||||
|
cmd = ['ssh', @machine.provider_config.host]
|
||||||
|
cmd += ['-p', @machine.provider_config.port.to_s] if @machine.provider_config.port
|
||||||
|
cmd += ['-l', @machine.provider_config.username] if @machine.provider_config.username
|
||||||
|
cmd += ['-i', @machine.provider_config.id_ssh_key_file] if @machine.provider_config.id_ssh_key_file
|
||||||
end
|
end
|
||||||
|
ip_cmd = cmd + %W(ip -j link show)
|
||||||
|
|
||||||
def list_networks
|
result = Vagrant::Util::Subprocess.execute(*ip_cmd)
|
||||||
connection.client.list_all_networks
|
raise Errors::FogLibvirtConnectionError unless result.exit_code == 0
|
||||||
|
|
||||||
|
info = JSON.parse(result.stdout)
|
||||||
|
|
||||||
|
(
|
||||||
|
info.map { |iface| iface['ifname'] } +
|
||||||
|
connection.client.list_all_interfaces.map { |iface| iface.name } +
|
||||||
|
connection.client.list_all_networks.map { |net| net.bridge_name }
|
||||||
|
).uniq.reject(&:empty?)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach_device(xml)
|
def attach_device(xml)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ module VagrantPlugins
|
|||||||
forward_x11: @machine.config.ssh.forward_x11
|
forward_x11: @machine.config.ssh.forward_x11
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_info[:proxy_command] = @machine.provider_config.proxy_command if @machine.provider_config.proxy_command
|
ssh_info[:proxy_command] = @machine.provider_config.proxy_command if @machine.provider_config.proxy_command && !@machine.provider_config.proxy_command.empty?
|
||||||
|
|
||||||
ssh_info
|
ssh_info
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -741,23 +741,15 @@ describe VagrantPlugins::ProviderLibvirt::Config do
|
|||||||
context 'with public_network defined' do
|
context 'with public_network defined' do
|
||||||
let(:libvirt_client) { instance_double(::Libvirt::Connect) }
|
let(:libvirt_client) { instance_double(::Libvirt::Connect) }
|
||||||
let(:host_devices) { [
|
let(:host_devices) { [
|
||||||
instance_double(Libvirt::Interface),
|
'lo',
|
||||||
instance_double(Libvirt::Interface),
|
'eth0',
|
||||||
] }
|
'virbr0',
|
||||||
let(:libvirt_networks) { [
|
|
||||||
instance_double(Libvirt::Network),
|
|
||||||
instance_double(Libvirt::Network),
|
|
||||||
] }
|
] }
|
||||||
let(:driver) { instance_double(::VagrantPlugins::ProviderLibvirt::Driver) }
|
let(:driver) { instance_double(::VagrantPlugins::ProviderLibvirt::Driver) }
|
||||||
before do
|
before do
|
||||||
machine.config.vm.network :public_network, dev: 'eth0', ip: "192.168.2.157"
|
machine.config.vm.network :public_network, dev: 'eth0', ip: "192.168.2.157"
|
||||||
allow(machine.provider).to receive(:driver).and_return(driver)
|
allow(machine.provider).to receive(:driver).and_return(driver)
|
||||||
expect(driver).to receive(:list_host_devices).and_return(host_devices)
|
expect(driver).to receive(:host_devices).and_return(host_devices).at_least(:once).times
|
||||||
expect(driver).to receive(:list_networks).and_return(libvirt_networks)
|
|
||||||
expect(host_devices[0]).to receive(:name).and_return('eth0')
|
|
||||||
expect(host_devices[1]).to receive(:name).and_return('virbr0')
|
|
||||||
expect(libvirt_networks[0]).to receive(:bridge_name).and_return('')
|
|
||||||
expect(libvirt_networks[1]).to receive(:bridge_name).and_return('virbr0')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should validate use of existing device' do
|
it 'should validate use of existing device' do
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ describe VagrantPlugins::ProviderLibvirt::Driver do
|
|||||||
|
|
||||||
subject { described_class.new(machine) }
|
subject { described_class.new(machine) }
|
||||||
|
|
||||||
|
# make it easier for distros that want to switch the default value for
|
||||||
|
# qemu_use_session to true by ensuring it is explicitly false for tests.
|
||||||
|
before do
|
||||||
|
allow(machine.provider_config).to receive(:qemu_use_session).and_return(false)
|
||||||
|
allow(logger).to receive(:info)
|
||||||
|
allow(logger).to receive(:debug)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'connections' do
|
||||||
let(:vagrantfile) do
|
let(:vagrantfile) do
|
||||||
<<-EOF
|
<<-EOF
|
||||||
Vagrant.configure('2') do |config|
|
Vagrant.configure('2') do |config|
|
||||||
@@ -43,9 +52,6 @@ describe VagrantPlugins::ProviderLibvirt::Driver do
|
|||||||
# make it easier for distros that want to switch the default value for
|
# make it easier for distros that want to switch the default value for
|
||||||
# qemu_use_session to true by ensuring it is explicitly false for tests.
|
# qemu_use_session to true by ensuring it is explicitly false for tests.
|
||||||
before do
|
before do
|
||||||
allow(machine.provider_config).to receive(:qemu_use_session).and_return(false)
|
|
||||||
allow(logger).to receive(:info)
|
|
||||||
allow(logger).to receive(:debug)
|
|
||||||
allow(machine.provider).to receive('driver').and_call_original
|
allow(machine.provider).to receive('driver').and_call_original
|
||||||
allow(machine2.provider).to receive('driver').and_call_original
|
allow(machine2.provider).to receive('driver').and_call_original
|
||||||
end
|
end
|
||||||
@@ -97,6 +103,7 @@ describe VagrantPlugins::ProviderLibvirt::Driver do
|
|||||||
expect(machine.provider.driver.system_connection).to eq(system_connection1)
|
expect(machine.provider.driver.system_connection).to eq(system_connection1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#get_ipaddress' do
|
describe '#get_ipaddress' do
|
||||||
context 'when domain exists' do
|
context 'when domain exists' do
|
||||||
@@ -179,6 +186,7 @@ describe VagrantPlugins::ProviderLibvirt::Driver do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when qemu_use_session is enabled' do
|
context 'when qemu_use_session is enabled' do
|
||||||
|
let(:system_connection) { double("system connection") }
|
||||||
let(:networks) { [instance_double(::Fog::Libvirt::Compute::Real)] }
|
let(:networks) { [instance_double(::Fog::Libvirt::Compute::Real)] }
|
||||||
let(:dhcp_leases) {
|
let(:dhcp_leases) {
|
||||||
{
|
{
|
||||||
@@ -199,8 +207,8 @@ describe VagrantPlugins::ProviderLibvirt::Driver do
|
|||||||
|
|
||||||
it 'should retrieve the address via the system dhcp-leases API' do
|
it 'should retrieve the address via the system dhcp-leases API' do
|
||||||
expect(domain).to receive(:mac).and_return("52:54:00:8b:dc:5f")
|
expect(domain).to receive(:mac).and_return("52:54:00:8b:dc:5f")
|
||||||
expect(subject).to receive(:system_connection).and_return(system_connection1)
|
expect(subject).to receive(:system_connection).and_return(system_connection)
|
||||||
expect(system_connection1).to receive(:list_all_networks).and_return(networks)
|
expect(system_connection).to receive(:list_all_networks).and_return(networks)
|
||||||
expect(networks[0]).to receive(:dhcp_leases).and_return([dhcp_leases])
|
expect(networks[0]).to receive(:dhcp_leases).and_return([dhcp_leases])
|
||||||
|
|
||||||
expect(subject.get_ipaddress).to eq("192.168.122.43")
|
expect(subject.get_ipaddress).to eq("192.168.122.43")
|
||||||
@@ -221,6 +229,99 @@ describe VagrantPlugins::ProviderLibvirt::Driver do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#host_devices' do
|
||||||
|
let(:vagrantfile_providerconfig) do
|
||||||
|
<<-EOF
|
||||||
|
libvirt.uri = "qemu:///system"
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:ip_link_show) {
|
||||||
|
JSON.dump(
|
||||||
|
[
|
||||||
|
# trimmed element details of what would be returned by 'ip -j link show'
|
||||||
|
{ "ifindex": 1, "ifname": "lo", "group": "default", "link_type": "loopback"},
|
||||||
|
{ "ifindex": 2, "ifname": "eth0", "group": "default", "link_type": "ether"},
|
||||||
|
{ "ifindex": 3, "ifname": "eth1", "group": "default", "link_type": "ether"},
|
||||||
|
{ "ifindex": 4, "ifname": "virbr0", "group": "default", "link_type": "ether"},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:libvirt_interfaces) { [
|
||||||
|
instance_double(Libvirt::Interface),
|
||||||
|
instance_double(Libvirt::Interface),
|
||||||
|
] }
|
||||||
|
let(:libvirt_networks) { [
|
||||||
|
instance_double(Libvirt::Network),
|
||||||
|
instance_double(Libvirt::Network),
|
||||||
|
] }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(subject).to receive(:connection).and_return(connection)
|
||||||
|
|
||||||
|
allow(Vagrant::Util::Subprocess).to receive(:execute) do |*arr|
|
||||||
|
expect(arr[0]).to eq('ip')
|
||||||
|
end.and_return(Vagrant::Util::Subprocess::Result.new(exit_code=0, stdout=ip_link_show, stderr=''))
|
||||||
|
|
||||||
|
expect(libvirt_client).to receive(:list_all_interfaces).and_return(libvirt_interfaces)
|
||||||
|
expect(libvirt_client).to receive(:list_all_networks).and_return(libvirt_networks)
|
||||||
|
expect(libvirt_interfaces[0]).to receive(:name).and_return('eth0')
|
||||||
|
expect(libvirt_interfaces[1]).to receive(:name).and_return('virbr0')
|
||||||
|
expect(libvirt_networks[0]).to receive(:bridge_name).and_return('')
|
||||||
|
expect(libvirt_networks[1]).to receive(:bridge_name).and_return('virbr0')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should query system and libvirt' do
|
||||||
|
expect(subject.host_devices).to eq(['lo', 'eth0', 'eth1', 'virbr0'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should handle empty string' do
|
||||||
|
expect(machine.provider_config).to receive(:proxy_command).and_return('').twice
|
||||||
|
|
||||||
|
expect(subject.host_devices).to eq(['lo', 'eth0', 'eth1', 'virbr0'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should cache the result' do
|
||||||
|
expect(machine.provider_config).to receive(:proxy_command).and_return(nil).once
|
||||||
|
|
||||||
|
expect(subject.host_devices).to eq(['lo', 'eth0', 'eth1', 'virbr0'])
|
||||||
|
expect(subject.host_devices).to eq(['lo', 'eth0', 'eth1', 'virbr0'])
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when libvirt is remote' do
|
||||||
|
let(:vagrantfile_providerconfig) do
|
||||||
|
<<-EOF
|
||||||
|
libvirt.uri = "qemu+ssh://remote-server/system"
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(machine.provider_config).to receive(:proxy_command).and_return('ssh remote-server -W %h:%p')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should use ssh for ip link' do
|
||||||
|
expect(Vagrant::Util::Subprocess).to receive(:execute) do |*arr|
|
||||||
|
expect(arr[0..3]).to eq(['ssh', 'remote-server', 'ip', '-j'])
|
||||||
|
end.and_return(Vagrant::Util::Subprocess::Result.new(exit_code=0, stdout=ip_link_show, stderr=''))
|
||||||
|
|
||||||
|
expect(subject.host_devices).to eq(['lo', 'eth0', 'eth1', 'virbr0'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should construct the ssh command with all options when needed' do
|
||||||
|
machine.provider_config.port = 2022
|
||||||
|
machine.provider_config.username = 'remote-user'
|
||||||
|
machine.provider_config.id_ssh_key_file = 'my-key-file'
|
||||||
|
|
||||||
|
expect(Vagrant::Util::Subprocess).to receive(:execute) do |*arr|
|
||||||
|
expect(arr[0..9]).to eq(['ssh', 'remote-server', '-p', '2022', '-l', 'remote-user', '-i', 'my-key-file', 'ip', '-j'])
|
||||||
|
end.and_return(Vagrant::Util::Subprocess::Result.new(exit_code=0, stdout=ip_link_show, stderr=''))
|
||||||
|
|
||||||
|
expect(subject.host_devices).to eq(['lo', 'eth0', 'eth1', 'virbr0'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#state' do
|
describe '#state' do
|
||||||
let(:domain) { double('domain') }
|
let(:domain) { double('domain') }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user