mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2025-02-25 18:55:27 -06:00
Restore handling of disk_device domain setting (#1365)
Re-enable handling of the disk_device domain volume setting to ensure it can be overridden from the default of vda to a value chosen. Provide a disk resolver to resolve devices after the box has been downloaded so that initial devices can be correctly allocated and avoid conflicts with additional disks added that would otherwise get assigned the same device. Removes hack for destroy domain when more than one disk, as now devices in the config are only present if provided by the configuration. Fixes: #1353
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
require 'log4r'
|
||||
|
||||
require 'vagrant-libvirt/util/resolvers'
|
||||
|
||||
module VagrantPlugins
|
||||
module ProviderLibvirt
|
||||
module Action
|
||||
@@ -140,6 +142,8 @@ module VagrantPlugins
|
||||
|
||||
@os_type = 'hvm'
|
||||
|
||||
resolver = ::VagrantPlugins::ProviderLibvirt::Util::DiskDeviceResolver.new(prefix=@disk_device[0..1])
|
||||
|
||||
# Get path to domain image from the storage pool selected if we have a box.
|
||||
if env[:machine].config.vm.box
|
||||
if @snapshot_pool_name != @storage_pool_name
|
||||
@@ -147,6 +151,12 @@ module VagrantPlugins
|
||||
else
|
||||
pool_name = @storage_pool_name
|
||||
end
|
||||
|
||||
# special handling for domain volume
|
||||
env[:box_volumes][0][:device] = env[:box_volumes][0].fetch(:device, @disk_device)
|
||||
|
||||
resolver.resolve!(env[:box_volumes])
|
||||
|
||||
@logger.debug "Search for volumes in pool: #{pool_name}"
|
||||
env[:box_volumes].each_index do |index|
|
||||
suffix_index = index > 0 ? "_#{index}" : ''
|
||||
@@ -154,14 +164,16 @@ module VagrantPlugins
|
||||
name: "#{@name}#{suffix_index}.img"
|
||||
).find { |x| x.pool_name == pool_name }
|
||||
raise Errors::DomainVolumeExists if domain_volume.nil?
|
||||
|
||||
@domain_volumes.push({
|
||||
:dev => (index+1).vdev.to_s,
|
||||
:dev => env[:box_volumes][index][:device],
|
||||
:cache => @domain_volume_cache,
|
||||
:bus => @disk_bus,
|
||||
:path => domain_volume.path,
|
||||
:virtual_size => env[:box_volumes][index][:virtual_size]
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# If we have a box, take the path from the domain volume and set our storage_prefix.
|
||||
@@ -173,19 +185,7 @@ module VagrantPlugins
|
||||
storage_prefix = get_disk_storage_prefix(env, @storage_pool_name)
|
||||
end
|
||||
|
||||
@serials = config.serials
|
||||
|
||||
@serials.each do |serial|
|
||||
next unless serial[:source] && serial[:source][:path]
|
||||
|
||||
dir = File.dirname(serial[:source][:path])
|
||||
begin
|
||||
FileUtils.mkdir_p(dir)
|
||||
rescue ::Errno::EACCES
|
||||
raise Errors::SerialCannotCreatePathError,
|
||||
path: dir
|
||||
end
|
||||
end
|
||||
resolver.resolve!(@disks)
|
||||
|
||||
@disks.each do |disk|
|
||||
disk[:path] ||= _disk_name(@name, disk)
|
||||
@@ -235,6 +235,20 @@ module VagrantPlugins
|
||||
end
|
||||
end
|
||||
|
||||
@serials = config.serials
|
||||
|
||||
@serials.each do |serial|
|
||||
next unless serial[:source] && serial[:source][:path]
|
||||
|
||||
dir = File.dirname(serial[:source][:path])
|
||||
begin
|
||||
FileUtils.mkdir_p(dir)
|
||||
rescue ::Errno::EACCES
|
||||
raise Errors::SerialCannotCreatePathError,
|
||||
path: dir
|
||||
end
|
||||
end
|
||||
|
||||
# Output the settings we're going to use to the user
|
||||
env[:ui].info(I18n.t('vagrant_libvirt.creating_domain'))
|
||||
env[:ui].info(" -- Name: #{@name}")
|
||||
@@ -284,7 +298,7 @@ module VagrantPlugins
|
||||
end
|
||||
env[:ui].info(" -- Storage pool: #{@storage_pool_name}")
|
||||
@domain_volumes.each do |volume|
|
||||
env[:ui].info(" -- Image(#{volume[:device]}): #{volume[:path]}, #{volume[:virtual_size].to_GB}G")
|
||||
env[:ui].info(" -- Image(#{volume[:dev]}): #{volume[:path]}, #{volume[:virtual_size].to_GB}G")
|
||||
end
|
||||
|
||||
if not @disk_driver_opts.empty?
|
||||
|
||||
@@ -128,12 +128,7 @@ module VagrantPlugins
|
||||
else
|
||||
# otherwise fallback to find the disk by device if specified by user
|
||||
# and finally index counting with offset and hope the match is correct
|
||||
if offset > 1
|
||||
# Currently disk devices are resolved incorrectly if the box has more than one device
|
||||
# this should be solved subsequently by delaying the resolution, however for now
|
||||
# default to using offset when more than one box volume.
|
||||
domain_disk = disks_xml[offset + index]
|
||||
elsif !disk[:device].nil?
|
||||
if !disk[:device].nil?
|
||||
domain_disk = REXML::XPath.match(disks_xml, './target[@dev="' + disk[:device] + '"]').first
|
||||
domain_disk = domain_disk.parent if !domain_disk.nil?
|
||||
else
|
||||
|
||||
@@ -4,15 +4,8 @@ require 'cgi'
|
||||
|
||||
require 'vagrant'
|
||||
|
||||
class Numeric
|
||||
Alphabet = ('a'..'z').to_a
|
||||
def vdev
|
||||
s = String.new
|
||||
q = self
|
||||
(q, r = (q - 1).divmod(26)) && s.prepend(Alphabet[r]) until q.zero?
|
||||
"vd#{s}"
|
||||
end
|
||||
end
|
||||
require 'vagrant-libvirt/errors'
|
||||
require 'vagrant-libvirt/util/resolvers'
|
||||
|
||||
module VagrantPlugins
|
||||
module ProviderLibvirt
|
||||
@@ -353,17 +346,6 @@ module VagrantPlugins
|
||||
@boot_order << device # append
|
||||
end
|
||||
|
||||
def _get_device(disks)
|
||||
# skip existing devices and also the first one (vda)
|
||||
exist = disks.collect { |x| x[:device] } + [1.vdev.to_s]
|
||||
skip = 1 # we're 1 based, not 0 based...
|
||||
loop do
|
||||
dev = skip.vdev # get lettered device
|
||||
return dev unless exist.include?(dev)
|
||||
skip += 1
|
||||
end
|
||||
end
|
||||
|
||||
def _get_cdrom_dev(cdroms)
|
||||
exist = Hash[cdroms.collect { |x| [x[:dev], true] }]
|
||||
# hda - hdc
|
||||
@@ -914,10 +896,6 @@ module VagrantPlugins
|
||||
|
||||
# Storage
|
||||
@disks = [] if @disks == UNSET_VALUE
|
||||
@disks.map! do |disk|
|
||||
disk[:device] = _get_device(@disks) if disk[:device].nil?
|
||||
disk
|
||||
end
|
||||
@cdroms = [] if @cdroms == UNSET_VALUE
|
||||
@cdroms.map! do |cdrom|
|
||||
cdrom[:dev] = _get_cdrom_dev(@cdroms) if cdrom[:dev].nil?
|
||||
@@ -998,7 +976,6 @@ module VagrantPlugins
|
||||
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"
|
||||
@@ -1011,6 +988,16 @@ module VagrantPlugins
|
||||
end
|
||||
end
|
||||
|
||||
# this won't be able to fully resolve the disks until the box has
|
||||
# been downloaded and any devices that need to be assigned to the
|
||||
# disks contained have been allocated
|
||||
disk_resolver = ::VagrantPlugins::ProviderLibvirt::Util::DiskDeviceResolver.new
|
||||
begin
|
||||
disk_resolver.resolve(machine.provider_config.disks)
|
||||
rescue Errors::VagrantLibvirtError => e
|
||||
errors << "#{e}"
|
||||
end
|
||||
|
||||
machine.config.vm.networks.each do |_type, opts|
|
||||
if opts[:mac]
|
||||
if opts[:mac] =~ /\A([0-9a-fA-F]{12})\z/
|
||||
|
||||
@@ -18,6 +18,14 @@ module VagrantPlugins
|
||||
error_key(:package_not_supported)
|
||||
end
|
||||
|
||||
class DuplicateDiskDevice < VagrantLibvirtError
|
||||
error_key(:duplicate_disk_device)
|
||||
end
|
||||
|
||||
class NoDiskDeviceAvailable < VagrantLibvirtError
|
||||
error_key(:no_disk_device_available)
|
||||
end
|
||||
|
||||
# Storage pools and volumes exceptions
|
||||
class NoStoragePool < VagrantLibvirtError
|
||||
error_key(:no_storage_pool)
|
||||
|
||||
80
lib/vagrant-libvirt/util/resolvers.rb
Normal file
80
lib/vagrant-libvirt/util/resolvers.rb
Normal file
@@ -0,0 +1,80 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'log4r'
|
||||
|
||||
require 'vagrant-libvirt/errors'
|
||||
|
||||
module VagrantPlugins
|
||||
module ProviderLibvirt
|
||||
module Util
|
||||
class DiskDeviceResolver
|
||||
attr_reader :existing
|
||||
|
||||
def initialize(prefix='vd')
|
||||
@default_prefix = prefix
|
||||
|
||||
@device_indicies = Hash.new
|
||||
@existing = Hash.new
|
||||
end
|
||||
|
||||
def resolve!(disks, options={})
|
||||
# check for duplicate device entries and raise an exception if one found
|
||||
# with enough details that the user should be able to determine what
|
||||
# to do to resolve.
|
||||
disks.select { |x| !x[:device].nil? }.each do |x|
|
||||
if @existing.has_key?(x[:device])
|
||||
raise Errors::DuplicateDiskDevice, new_disk: x, existing_disk: @existing[x[:device]]
|
||||
end
|
||||
|
||||
@existing[x[:device]] = x
|
||||
end
|
||||
|
||||
disks.each_index do |index|
|
||||
dev = disks[index][:device]
|
||||
if dev.nil?
|
||||
prefix = options.fetch(:prefix, @default_prefix)
|
||||
dev = next_device(prefix=prefix)
|
||||
if dev.nil?
|
||||
raise Errors::NoDiskDeviceAvailable, prefix: prefix
|
||||
end
|
||||
|
||||
disks[index][:device] = dev
|
||||
@existing[dev] = disks[index]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve(disks)
|
||||
new_disks = []
|
||||
disks.each do |disk|
|
||||
new_disks.push disk.dup
|
||||
end
|
||||
|
||||
resolve!(new_disks)
|
||||
|
||||
new_disks
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def next_device(prefix)
|
||||
curr = device_index(prefix)
|
||||
while curr <= 'z'.ord
|
||||
dev = prefix + curr.chr
|
||||
if !@existing[dev].nil?
|
||||
curr += 1
|
||||
next
|
||||
else
|
||||
@device_indicies[prefix] = curr
|
||||
return dev
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def device_index(prefix)
|
||||
@device_indicies[prefix] ||= 'a'.ord
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user