add ability for test pxe in private network

This commit is contained in:
dima 2016-12-06 19:45:27 +01:00
parent 981ca18b5e
commit b92b02b6d6
3 changed files with 94 additions and 31 deletions

View File

@ -83,14 +83,14 @@ kvm type virtual machines with `virsh` or `virt-manager`.
Next, you must have [Vagrant
installed](http://docs.vagrantup.com/v2/installation/index.html).
Vagrant-libvirt supports Vagrant 1.5, 1.6, 1.7 and 1.8.
Vagrant-libvirt supports Vagrant 1.5, 1.6, 1.7 and 1.8.
*We only test with the upstream version!* If you decide to install your distros
version and you run into problems, as a first step you should switch to upstream.
Now you need to make sure your have all the build dependencies installed for
Now you need to make sure your have all the build dependencies installed for
vagrant-libvirt. This depends on your distro. An overview:
* Ubuntu 12.04/14.04/16.04, Debian:
* Ubuntu 12.04/14.04/16.04, Debian:
```shell
apt-get build-dep vagrant ruby-libvirt
apt-get install qemu libvirt-bin ebtables dnsmasq
@ -780,7 +780,7 @@ You can define filter for redirected devices. These filters can be positiv or ne
You can extract that information from output of `lsusb` command. Every line contains the information in format `Bus [<bus>] Device [<device>]: ID [<vendor>:[<product>]`. The `version` can be extracted from the detailed output of the device using `lsusb -D /dev/usb/[<bus>]/[<device>]`. For example:
```shell
# get bcdDevice from
# get bcdDevice from
$: lsusb
Bus 001 Device 009: ID 08e6:3437 Gemalto (was Gemplus) GemPC Twin SmartCard Reader
@ -903,6 +903,25 @@ Vagrant.configure("2") do |config|
end
```
Example for vm with 2 networks and only 1 is bootable and has dhcp server in this subnet, for example foreman with dhcp server
Name of network "foreman_managed" is key for define boot order
```ruby
config.vm.define :pxeclient do |pxeclient|
pxeclient.vm.network :private_network,ip: '10.0.0.5',
libvirt__network_name: "foreman_managed",
libvirt__dhcp_enabled: false,
libvirt__host_ip: '10.0.0.1'
pxeclient.vm.provider :libvirt do |domain|
domain.memory = 1000
boot_network = {'network' => 'foreman_managed'}
domain.storage :file, :size => '100G', :type => 'qcow2'
domain.boot boot_network
domain.boot 'hd'
end
end
```
## SSH Access To VM
vagrant-libvirt supports vagrant's [standard ssh

View File

@ -227,6 +227,7 @@ module VagrantPlugins
# Do we need to create new network?
unless @interface_network[:created]
@interface_network[:name] = @options[:network_name]
@interface_network[:ip_address] ||= @options[:host_ip]
# Generate a unique name for network bridge.
@interface_network[:bridge_name] = generate_bridge_name

View File

@ -1,64 +1,107 @@
require "log4r"
require 'log4r'
require 'nokogiri'
module VagrantPlugins
module ProviderLibvirt
module Action
# boot order useful for pxe in discovery workflow
class SetBootOrder
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_libvirt::action::set_boot_order")
@logger = Log4r::Logger.new('vagrant_libvirt::action::set_boot_order')
config = env[:machine].provider_config
@boot_order = config.boot_order
end
def call(env)
# Get domain first
# Get domain first
begin
domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(
env[:machine].id.to_s)
domain = env[:machine].provider
.driver
.connection
.client
.lookup_domain_by_uuid(
env[:machine].id.to_s
)
rescue => e
raise Errors::NoDomainError,
:error_message => e.message
error_message: e.message
end
# Only execute specific boot ordering if this is defined in the Vagrant file
# Only execute specific boot ordering if this is defined
# in the Vagrant file
if @boot_order.count >= 1
# If a domain is initially defined with no box or disk or with an explicit boot order, libvirt adds <boot dev="foo">
# This conflicts with an explicit boot_order configuration, so we need to remove it from the domain xml and feed it back.
# Also see https://bugzilla.redhat.com/show_bug.cgi?id=1248514 as to why we have to do this after all devices have been defined.
# If a domain is initially defined with no box or disk or
# with an explicit boot order, libvirt adds <boot dev="foo">
# This conflicts with an explicit boot_order configuration,
# so we need to remove it from the domain xml and feed it back.
# Also see https://bugzilla.redhat.com/show_bug.cgi?id=1248514
# as to why we have to do this after all devices have been defined.
xml = Nokogiri::XML(domain.xml_desc)
xml.search("/domain/os/boot").each do |node|
node.remove
end
xml.search('/domain/os/boot').each(&:remove)
# Parse the XML and find each defined drive and network interfacee
hd = xml.search("/domain/devices/disk[@device='disk']")
cdrom = xml.search("/domain/devices/disk[@device='cdrom']")
network = xml.search("/domain/devices/interface[@type='network' or @type='udp']")
# implemented only for 1 network
nets = @boot_order.flat_map do |x|
x.class == Hash ? x : nil
end.compact
raise 'Defined only for 1 network for boot' if nets.size > 1
network = search_network(nets, xml)
# Generate an array per device group and a flattened array from all of those
devices = {"hd" => hd, "cdrom" => cdrom, "network" => network}
final_boot_order = @boot_order.flat_map {|category| devices[category] }
# Generate an array per device group and a flattened
# array from all of those
devices = { 'hd' => hd,
'cdrom' => cdrom,
'network' => network }
# Loop over the entire defined boot order array and create boot order entries in the domain XML
final_boot_order = final_boot_order(@boot_order, devices)
# Loop over the entire defined boot order array and
# create boot order entries in the domain XML
final_boot_order.each_with_index do |node, index|
boot = "<boot order='#{index+1}'/>"
boot = "<boot order='#{index + 1}'/>"
node.add_child(boot)
if node.name == 'disk'
@logger.debug "Setting #{node['device']} to boot index #{index+1}"
elsif node.name == 'interface'
@logger.debug "Setting #{node.name} to boot index #{index+1}"
end
logger_msg(node, index)
end
# Finally redefine the domain XML through libvirt to apply the boot ordering
env[:machine].provider.driver.connection.client.define_domain_xml(xml.to_s)
# Finally redefine the domain XML through libvirt
# to apply the boot ordering
env[:machine].provider
.driver
.connection
.client
.define_domain_xml(xml.to_s)
end
@app.call(env)
end
def final_boot_order(boot_order, devices)
boot_order.flat_map do |category|
devices[category.class == Hash ? category.keys.first : category]
end
end
def search_network(nets, xml)
str = '/domain/devices/interface'
str += "[(@type='network' or @type='udp')"
unless nets.empty?
str += " and source[@network='#{nets.first['network']}']"
end
str += ']'
@logger.debug(str)
xml.search(str)
end
def logger_msg(node, index)
name = if node.name == 'disk'
node['device']
elsif node.name == 'interface'
node.name
end
@logger.debug "Setting #{name} to boot index #{index + 1}"
end
end
end