diff --git a/README.md b/README.md
index 756a281..65abe8f 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ welcome and can help a lot :-)
* Snapshots via [sahara](https://github.com/jedi4ever/sahara).
* Package caching via [vagrant-cachier](http://fgrehm.viewdocs.io/vagrant-cachier/).
* Use boxes from other Vagrant providers via [vagrant-mutate](https://github.com/sciurus/vagrant-mutate).
+* Support VMs with no box for PXE boot purposes
## Future work
@@ -425,6 +426,26 @@ Vagrant.configure("2") do |config|
end
```
+## No box and PXE boot
+
+There is support for PXE booting VMs with no disks as well as PXE booting VMs with blank disks. There are some limitations:
+
+* No provisioning scripts are ran
+* No network configuration is being applied to the VM
+* No SSH connection can be made
+* ```vagrant halt``` will only work cleanly if the VM handles ACPI shutdown signals
+
+In short, VMs without a box can be created, halted and destroyed but all other functionality cannot be used.
+
+An example for a PXE booted VM with no disks whatsoever:
+
+Vagrant.configure("2") do |config|
+ config.vm.define :pxeclient do |pxeclient|
+ pxeclient.vm.provider :libvirt do |domain|
+ domain.boot 'network'
+ end
+ end
+
## SSH Access To VM
vagrant-libvirt supports vagrant's [standard ssh settings](https://docs.vagrantup.com/v2/vagrantfile/ssh_settings.html).
diff --git a/lib/vagrant-libvirt/action.rb b/lib/vagrant-libvirt/action.rb
index e600ae8..bcd5971 100644
--- a/lib/vagrant-libvirt/action.rb
+++ b/lib/vagrant-libvirt/action.rb
@@ -23,27 +23,34 @@ module VagrantPlugins
# Create VM if not yet created.
if !env[:result]
b2.use SetNameOfDomain
- b2.use HandleStoragePool
- b2.use HandleBox
- b2.use HandleBoxImage
- b2.use CreateDomainVolume
- b2.use CreateDomain
+ if !env[:machine].box
+ b2.use CreateDomain
+ b2.use CreateNetworks
+ b2.use CreateNetworkInterfaces
+ b2.use StartDomain
+ else
+ b2.use HandleStoragePool
+ b2.use HandleBox
+ b2.use HandleBoxImage
+ b2.use CreateDomainVolume
+ b2.use CreateDomain
- b2.use Provision
- b2.use PrepareNFSValidIds
- b2.use SyncedFolderCleanup
- b2.use SyncedFolders
- b2.use PrepareNFSSettings
- b2.use ShareFolders
- b2.use CreateNetworks
- b2.use CreateNetworkInterfaces
+ b2.use Provision
+ b2.use PrepareNFSValidIds
+ b2.use SyncedFolderCleanup
+ b2.use SyncedFolders
+ b2.use PrepareNFSSettings
+ b2.use ShareFolders
+ b2.use CreateNetworks
+ b2.use CreateNetworkInterfaces
- b2.use StartDomain
- b2.use WaitTillUp
+ b2.use StartDomain
+ b2.use WaitTillUp
- b2.use ForwardPorts
- b2.use SetHostname
- # b2.use SyncFolders
+ b2.use ForwardPorts
+ b2.use SetHostname
+ # b2.use SyncFolders
+ end
else
b2.use action_start
end
@@ -68,27 +75,33 @@ module VagrantPlugins
next
end
- # VM is not running or suspended.
+ if !env[:machine].box
+ # With no box, we just care about network creation and starting it
+ b3.use CreateNetworks
+ b3.use StartDomain
+ else
+ # VM is not running or suspended.
- b3.use Provision
+ b3.use Provision
- # Ensure networks are created and active
- b3.use CreateNetworks
+ # Ensure networks are created and active
+ b3.use CreateNetworks
- b3.use PrepareNFSValidIds
- b3.use SyncedFolderCleanup
- b3.use SyncedFolders
+ b3.use PrepareNFSValidIds
+ b3.use SyncedFolderCleanup
+ b3.use SyncedFolders
- # Start it..
- b3.use StartDomain
+ # Start it..
+ b3.use StartDomain
- # Machine should gain IP address when comming up,
- # so wait for dhcp lease and store IP into machines data_dir.
- b3.use WaitTillUp
+ # Machine should gain IP address when comming up,
+ # so wait for dhcp lease and store IP into machines data_dir.
+ b3.use WaitTillUp
- b3.use ForwardPorts
- b3.use PrepareNFSSettings
- b3.use ShareFolders
+ b3.use ForwardPorts
+ b3.use PrepareNFSSettings
+ b3.use ShareFolders
+ end
end
end
end
@@ -154,7 +167,9 @@ module VagrantPlugins
if !env[:result]
# Try to remove stale volumes anyway
b2.use SetNameOfDomain
- b2.use RemoveStaleVolume
+ if env[:machine].box
+ b2.use RemoveStaleVolume
+ end
if !env[:result]
b2.use MessageNotCreated
end
diff --git a/lib/vagrant-libvirt/action/create_domain.rb b/lib/vagrant-libvirt/action/create_domain.rb
index 3173716..523199b 100644
--- a/lib/vagrant-libvirt/action/create_domain.rb
+++ b/lib/vagrant-libvirt/action/create_domain.rb
@@ -72,18 +72,29 @@ module VagrantPlugins
@os_type = 'hvm'
- # Get path to domain image from the storage pool selected.
- actual_volumes =
- env[:machine].provider.driver.connection.volumes.all.select do |x|
- x.pool_name == @storage_pool_name
- end
- domain_volume = ProviderLibvirt::Util::Collection.find_matching(
- actual_volumes, "#{@name}.img")
- raise Errors::DomainVolumeExists if domain_volume.nil?
- @domain_volume_path = domain_volume.path
+ # Get path to domain image from the storage pool selected if we have a box.
+ if env[:machine].box
+ actual_volumes =
+ env[:machine].provider.driver.connection.volumes.all.select do |x|
+ x.pool_name == @storage_pool_name
+ end
+ domain_volume = ProviderLibvirt::Util::Collection.find_matching(
+ actual_volumes,"#{@name}.img")
+ raise Errors::DomainVolumeExists if domain_volume.nil?
+ @domain_volume_path = domain_volume.path
+ end
+ # If we have a box, take the path from the domain volume and set our storage_prefix.
+ # If not, we dump the storage pool xml to get its defined path.
# the default storage prefix is typically: /var/lib/libvirt/images/
- storage_prefix = File.dirname(@domain_volume_path) + '/' # steal
+ if env[:machine].box
+ storage_prefix = File.dirname(@domain_volume_path) + '/' # steal
+ else
+ storage_pool = env[:machine].provider.driver.connection.client.lookup_storage_pool_by_name(@storage_pool_name)
+ raise Errors::NoStoragePool if storage_pool.nil?
+ xml = Nokogiri::XML(storage_pool.xml_desc)
+ storage_prefix = xml.xpath("/pool/target/path").inner_text.to_s + '/'
+ end
@disks.each do |disk|
disk[:path] ||= _disk_name(@name, disk)
@@ -125,7 +136,9 @@ module VagrantPlugins
env[:ui].info(" -- Cpus: #{@cpus}")
env[:ui].info(" -- Memory: #{@memory_size / 1024}M")
env[:ui].info(" -- Loader: #{@loader}")
- env[:ui].info(" -- Base box: #{env[:machine].box.name}")
+ if env[:machine].box
+ env[:ui].info(" -- Base box: #{env[:machine].box.name}")
+ end
env[:ui].info(" -- Storage pool: #{@storage_pool_name}")
env[:ui].info(" -- Image: #{@domain_volume_path} (#{env[:box_virtual_size]}G)")
env[:ui].info(" -- Volume Cache: #{@domain_volume_cache}")
diff --git a/lib/vagrant-libvirt/action/create_network_interfaces.rb b/lib/vagrant-libvirt/action/create_network_interfaces.rb
index eede1ac..3324f9e 100644
--- a/lib/vagrant-libvirt/action/create_network_interfaces.rb
+++ b/lib/vagrant-libvirt/action/create_network_interfaces.rb
@@ -125,43 +125,46 @@ module VagrantPlugins
# Continue the middleware chain.
@app.call(env)
- # Configure interfaces that user requested. Machine should be up and
- # running now.
- networks_to_configure = []
- adapters.each_with_index do |options, slot_number|
- # Skip configuring the management network, which is on the first interface.
- # It's used for provisioning and it has to be available during provisioning,
- # ifdown command is not acceptable here.
- next if slot_number == 0
- next if options[:auto_config] === false
- @logger.debug "Configuring interface slot_number #{slot_number} options #{options}"
-
- network = {
- :interface => slot_number,
- :use_dhcp_assigned_default_route => options[:use_dhcp_assigned_default_route],
- :mac_address => options[:mac],
- }
-
- if options[:ip]
+ if env[:machine].box
+ # Configure interfaces that user requested. Machine should be up and
+ # running now.
+ networks_to_configure = []
+
+ adapters.each_with_index do |options, slot_number|
+ # Skip configuring the management network, which is on the first interface.
+ # It's used for provisioning and it has to be available during provisioning,
+ # ifdown command is not acceptable here.
+ next if slot_number == 0
+ next if options[:auto_config] === false
+ @logger.debug "Configuring interface slot_number #{slot_number} options #{options}"
+
network = {
- :type => :static,
- :ip => options[:ip],
- :netmask => options[:netmask],
- }.merge(network)
- else
- network[:type] = :dhcp
+ :interface => slot_number,
+ :use_dhcp_assigned_default_route => options[:use_dhcp_assigned_default_route],
+ :mac_address => options[:mac],
+ }
+
+ if options[:ip]
+ network = {
+ :type => :static,
+ :ip => options[:ip],
+ :netmask => options[:netmask],
+ }.merge(network)
+ else
+ network[:type] = :dhcp
+ end
+
+ # do not run configure_networks for tcp tunnel interfaces
+ next if options.fetch(:tcp_tunnel_type, nil)
+
+ networks_to_configure << network
end
-
- # do not run configure_networks for tcp tunnel interfaces
- next if options.fetch(:tcp_tunnel_type, nil)
-
- networks_to_configure << network
+
+ env[:ui].info I18n.t('vagrant.actions.vm.network.configuring')
+ env[:machine].guest.capability(
+ :configure_networks, networks_to_configure)
end
-
- env[:ui].info I18n.t('vagrant.actions.vm.network.configuring')
- env[:machine].guest.capability(
- :configure_networks, networks_to_configure)
end
private
diff --git a/lib/vagrant-libvirt/plugin.rb b/lib/vagrant-libvirt/plugin.rb
index 0b7cae3..f624cd5 100644
--- a/lib/vagrant-libvirt/plugin.rb
+++ b/lib/vagrant-libvirt/plugin.rb
@@ -23,7 +23,7 @@ module VagrantPlugins
Config
end
- provider('libvirt', parallel: true) do
+ provider('libvirt', parallel: true, box_optional: true) do
require_relative 'provider'
Provider
end
diff --git a/lib/vagrant-libvirt/templates/domain.xml.erb b/lib/vagrant-libvirt/templates/domain.xml.erb
index 2ac6f50..44e5012 100644
--- a/lib/vagrant-libvirt/templates/domain.xml.erb
+++ b/lib/vagrant-libvirt/templates/domain.xml.erb
@@ -49,12 +49,14 @@
+ <% if @domain_volume_path %>
<%# we need to ensure a unique target dev -%>
+ <% end %>
<%# additional disks -%>
<% @disks.each do |d| -%>