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

@ -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,13 +1,14 @@
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
@ -15,50 +16,92 @@ module VagrantPlugins
def call(env)
# 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}'/>"
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