diff --git a/lib/fog/libvirt/compute.rb b/lib/fog/libvirt/compute.rb
index 14f6c20..e3949cd 100644
--- a/lib/fog/libvirt/compute.rb
+++ b/lib/fog/libvirt/compute.rb
@@ -45,6 +45,10 @@ class Compute < Fog::Service
request :get_node_info
request :update_autostart
request :update_display
+ request :upload_iso
+ request :attach_iso
+ request :detach_iso
+ request :destroy_iso
request :libversion
module Shared
diff --git a/lib/fog/libvirt/models/compute/server.rb b/lib/fog/libvirt/models/compute/server.rb
index 805898f..5c9bd53 100644
--- a/lib/fog/libvirt/models/compute/server.rb
+++ b/lib/fog/libvirt/models/compute/server.rb
@@ -61,6 +61,33 @@ def initialize(attributes={} )
@user_data = attributes.delete(:user_data)
end
+ def upload_iso(file_path, volume_name = nil, pool_name = nil)
+ raise ArgumentError, "file_path is a required parameter" if file_path.nil?
+
+ volume_name ||= File.basename(file_path)
+ pool_name ||= default_iso_pool_name
+ service.upload_iso(pool_name, volume_name, file_path)
+ end
+
+ def attach_iso(path, options = {})
+ raise ArgumentError, "path is a required parameter" if path.nil?
+
+ iso_path = File.absolute_path?(path) ? path : File.join(iso_dir || default_iso_dir, path)
+ service.attach_iso(uuid, iso_path, options)
+ end
+
+ def detach_iso(options = {})
+ service.detach_iso(uuid, options)
+ end
+
+ def destroy_iso(volume_name, pool_name = nil)
+ raise ArgumentError, "volume_name is a required parameter" if volume_name.nil?
+
+ iso_name = File.basename(volume_name)
+ pool_name ||= service.volumes.all(:name => iso_name).first&.pool_name || default_iso_pool_name
+ service.destroy_iso(pool_name, iso_name)
+ end
+
def new?
uuid.nil?
end
@@ -531,14 +558,15 @@ def create_or_clone_volume
@volumes.nil? ? @volumes = [volume] : @volumes << volume
end
- def default_iso_dir
- "/var/lib/libvirt/images"
- end
-
def default_volume_name
"#{name}.#{volume_format_type || 'img'}"
end
+ def default_iso_pool_name
+ volume = volumes&.first
+ volume&.pool_name || "default"
+ end
+
def defaults
{
:persistent => true,
diff --git a/lib/fog/libvirt/models/compute/util/util.rb b/lib/fog/libvirt/models/compute/util/util.rb
index e0eee24..231d7da 100644
--- a/lib/fog/libvirt/models/compute/util/util.rb
+++ b/lib/fog/libvirt/models/compute/util/util.rb
@@ -4,6 +4,9 @@
module Fog
module Libvirt
module Util
+ DEFAULT_CDROM_TARGET_DEV = "sdc".freeze
+ DEFAULT_CDROM_BUS = "sata".freeze
+
def xml_element(xml, path, attribute=nil)
xml = Nokogiri::XML(xml)
attribute.nil? ? (xml/path).first.text : (xml/path).first[attribute.to_sym]
@@ -17,6 +20,10 @@ def xml_elements(xml, path, attribute=nil)
def randomized_name
"fog-#{(SecureRandom.random_number*10E14).to_i.round}"
end
+
+ def default_iso_dir
+ "/var/lib/libvirt/images"
+ end
end
end
end
diff --git a/lib/fog/libvirt/requests/compute/attach_iso.rb b/lib/fog/libvirt/requests/compute/attach_iso.rb
new file mode 100644
index 0000000..ae8266e
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/attach_iso.rb
@@ -0,0 +1,61 @@
+require "nokogiri"
+
+module Fog
+ module Libvirt
+ class Compute
+ module Shared
+ include Fog::Libvirt::Util
+
+ def attach_iso(uuid, iso_path, options = {})
+ raise ArgumentError, "uuid is a required parameter" if uuid.nil?
+ raise ArgumentError, "iso_path is a required parameter" if iso_path.nil?
+
+ options ||= {}
+ raise ArgumentError, "options must be a hash" unless options.is_a?(Hash)
+
+ target_dev = options.fetch(:target_dev, DEFAULT_CDROM_TARGET_DEV)
+ bus = options.fetch(:bus, DEFAULT_CDROM_BUS)
+ flags = options.fetch(:flags, ::Libvirt::Domain::AFFECT_CONFIG)
+
+ resolved_iso_path = File.absolute_path?(iso_path) ? iso_path : File.join(default_iso_dir, iso_path)
+ xml = attach_cdrom_xml(resolved_iso_path, target_dev, bus)
+
+ domain = client.lookup_domain_by_uuid(uuid)
+ begin
+ domain.attach_device(xml, flags)
+ rescue ::Libvirt::Error => e
+ begin
+ domain.update_device(xml, flags)
+ rescue ::Libvirt::Error
+ raise e
+ end
+ end
+
+ # if we get no exception, we assume the operation was successful
+ true
+ end
+
+ private
+
+ def attach_cdrom_xml(iso_path, target_dev, bus)
+ Nokogiri::XML::Builder.new do |x|
+ x.disk(:type => "file", :device => "cdrom") do
+ x.driver(:name => "qemu", :type => "raw")
+ x.source(:file => iso_path)
+ x.target(:dev => target_dev, :bus => bus)
+ x.readonly
+ end
+ end.to_xml
+ end
+ end
+
+ class Real
+ include Shared
+ end
+
+ class Mock
+ include Shared
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/destroy_iso.rb b/lib/fog/libvirt/requests/compute/destroy_iso.rb
new file mode 100644
index 0000000..10ff182
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/destroy_iso.rb
@@ -0,0 +1,39 @@
+module Fog
+ module Libvirt
+ class Compute
+ module Shared
+ def destroy_iso(pool_name, volume_name)
+ raise ArgumentError, "pool_name is a required parameter" if pool_name.nil?
+ raise ArgumentError, "volume_name is a required parameter" if volume_name.nil?
+
+ pool = client.lookup_storage_pool_by_name(pool_name)
+ begin
+ pool.lookup_volume_by_name(volume_name).delete
+ rescue ::Libvirt::RetrieveError
+ # already absent, treat as success if not present afterwards
+ end
+
+ # if the ISO is absent, then we are good
+ volume_absent?(pool, volume_name)
+ end
+
+ private
+
+ def volume_absent?(pool, volume_name)
+ pool.lookup_volume_by_name(volume_name)
+ false
+ rescue ::Libvirt::RetrieveError
+ true
+ end
+ end
+
+ class Real
+ include Shared
+ end
+
+ class Mock
+ include Shared
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/detach_iso.rb b/lib/fog/libvirt/requests/compute/detach_iso.rb
new file mode 100644
index 0000000..79d49b3
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/detach_iso.rb
@@ -0,0 +1,81 @@
+require "nokogiri"
+
+module Fog
+ module Libvirt
+ class Compute
+ module Shared
+ include Fog::Libvirt::Util
+
+ def detach_iso(uuid, options = {})
+ raise ArgumentError, "uuid is a required parameter" if uuid.nil?
+
+ options ||= {}
+ raise ArgumentError, "options must be a hash" unless options.is_a?(Hash)
+
+ target_dev = options.fetch(:target_dev, DEFAULT_CDROM_TARGET_DEV)
+ bus = options.fetch(:bus, DEFAULT_CDROM_BUS)
+ flags = options.fetch(:flags, ::Libvirt::Domain::AFFECT_CONFIG)
+ domain = client.lookup_domain_by_uuid(uuid)
+ domain_active = domain.active?
+ flags = effective_detach_iso_flags(flags, domain_active)
+
+ if domain_active
+ domain.update_device(eject_cdrom_xml(target_dev, bus), flags)
+ begin
+ domain.detach_device(detach_cdrom_xml(target_dev, bus), flags)
+ rescue ::Libvirt::Error
+ # Some backends don't allow to detach the cdrom if the host is running.
+ # In this case, we just eject the cdrom and leave it attached to the VM.
+ # Return true that maybe the ISO file can be removed in further steps.
+ true
+ end
+ else
+ begin
+ domain.detach_device(detach_cdrom_xml(target_dev, bus), flags)
+ true
+ rescue ::Libvirt::Error
+ false
+ end
+ end
+ end
+
+ private
+
+ def detach_cdrom_xml(target_dev, bus)
+ Nokogiri::XML::Builder.new do |x|
+ x.disk(:type => "file", :device => "cdrom") do
+ x.target(:dev => target_dev, :bus => bus)
+ end
+ end.to_xml
+ end
+
+ def eject_cdrom_xml(target_dev, bus)
+ Nokogiri::XML::Builder.new do |x|
+ x.disk(:type => "file", :device => "cdrom", :tray => "open") do
+ x.driver(:name => "qemu", :type => "raw")
+ x.target(:dev => target_dev, :bus => bus)
+ x.readonly
+ end
+ end.to_xml
+ end
+
+ def effective_detach_iso_flags(flags, domain_active)
+ return flags unless (flags & ::Libvirt::Domain::AFFECT_CONFIG) == ::Libvirt::Domain::AFFECT_CONFIG
+ return flags unless domain_active
+
+ flags | ::Libvirt::Domain::AFFECT_LIVE
+ rescue ::Libvirt::Error
+ flags
+ end
+ end
+
+ class Real
+ include Shared
+ end
+
+ class Mock
+ include Shared
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/upload_iso.rb b/lib/fog/libvirt/requests/compute/upload_iso.rb
new file mode 100644
index 0000000..306811b
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/upload_iso.rb
@@ -0,0 +1,54 @@
+require "nokogiri"
+
+module Fog
+ module Libvirt
+ class Compute
+ module Shared
+ def upload_iso(pool_name, volume_name, file_path)
+ raise ArgumentError, "pool_name is a required parameter" if pool_name.nil?
+ raise ArgumentError, "volume_name is a required parameter" if volume_name.nil?
+ raise ArgumentError, "file_path is a required parameter" if file_path.nil?
+
+ pool = client.lookup_storage_pool_by_name(pool_name)
+ pool.lookup_volume_by_name(volume_name).delete if pool.list_volumes.include?(volume_name)
+
+ create_volume(pool_name, iso_volume_xml(volume_name, file_path))
+ upload_volume(pool_name, volume_name, file_path)
+
+ volume = pool.lookup_volume_by_name(volume_name)
+ {
+ :pool_name => pool_name,
+ :name => volume_name,
+ :key => volume.key,
+ :path => volume.path
+ }
+ end
+
+ private
+
+ def iso_volume_xml(volume_name, file_path)
+ iso_size = File.size(file_path)
+
+ Nokogiri::XML::Builder.new do |x|
+ x.volume do
+ x.name(volume_name)
+ x.allocation(0, :unit => "B")
+ x.capacity(iso_size, :unit => "B")
+ x.target do
+ x.format(:type => "raw")
+ end
+ end
+ end.to_xml
+ end
+ end
+
+ class Real
+ include Shared
+ end
+
+ class Mock
+ include Shared
+ end
+ end
+ end
+end
diff --git a/tests/libvirt/compute_tests.rb b/tests/libvirt/compute_tests.rb
index b28f79c..c5904e1 100644
--- a/tests/libvirt/compute_tests.rb
+++ b/tests/libvirt/compute_tests.rb
@@ -12,7 +12,7 @@
%w{ create_domain create_volume define_domain define_pool destroy_interface destroy_network get_node_info
update_autostart list_domains
list_interfaces list_networks list_pools list_pool_volumes list_volumes pool_action vm_action volume_action
- dhcp_leases }.each do |request|
+ dhcp_leases upload_iso attach_iso detach_iso destroy_iso }.each do |request|
test("it should respond to #{request}") { compute.respond_to? request }
end
end
diff --git a/tests/libvirt/models/compute/server_tests.rb b/tests/libvirt/models/compute/server_tests.rb
index 448baef..16d03cc 100644
--- a/tests/libvirt/models/compute/server_tests.rb
+++ b/tests/libvirt/models/compute/server_tests.rb
@@ -13,6 +13,9 @@
%w{ start stop destroy reboot suspend }.each do |action|
test(action) { server.respond_to? action }
end
+ %w{ upload_iso attach_iso detach_iso destroy_iso }.each do |action|
+ test(action) { server.respond_to? action }
+ end
%w{ start reboot suspend stop }.each do |action|
test("#{action} returns successfully") {
begin
diff --git a/tests/libvirt/requests/compute/attach_iso_tests.rb b/tests/libvirt/requests/compute/attach_iso_tests.rb
new file mode 100644
index 0000000..3b77f18
--- /dev/null
+++ b/tests/libvirt/requests/compute/attach_iso_tests.rb
@@ -0,0 +1,128 @@
+require File.expand_path("../../../helper", __dir__)
+require "fog/libvirt"
+
+class AttachIsoFakeDomain
+ attr_reader :xml, :flags, :calls, :xml_desc
+
+ def initialize(xml_desc, fail_attach: false, fail_update: false)
+ @xml_desc = xml_desc
+ @calls = []
+ @fail_attach = fail_attach
+ @fail_update = fail_update
+ end
+
+ def update_device(xml, flags = 0)
+ raise ::Libvirt::Error, "update failed" if @fail_update
+
+ @calls << :update
+ @xml = xml
+ @flags = flags
+ true
+ end
+
+ def attach_device(xml, flags = 0)
+ raise ::Libvirt::Error, "attach failed" if @fail_attach
+
+ @calls << :attach
+ @xml = xml
+ @flags = flags
+ true
+ end
+end
+
+class AttachIsoFakeClient
+ def initialize(domain)
+ @domain = domain
+ end
+
+ def lookup_domain_by_uuid(_uuid)
+ @domain
+ end
+end
+
+Shindo.tests("Fog::Compute[:libvirt] | attach_iso") do
+ tests("attach_iso") do
+ returns(true, "attaches cdrom device directly when attach succeeds") do
+ domain = AttachIsoFakeDomain.new("")
+ client = AttachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+ iso = "/var/lib/libvirt/images/os.iso"
+
+ ok = service.attach_iso(uuid, iso, :target_dev => "sdc", :bus => "sata", :flags => 0)
+
+ ok &&
+ domain.calls == [:attach] &&
+ domain.xml.include?('device="cdrom"') &&
+ domain.xml.include?('type="file"') &&
+ domain.xml.include?("',
+ :fail_attach => true
+ )
+ client = AttachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+ iso = "/var/lib/libvirt/images/os.iso"
+
+ ok = service.attach_iso(uuid, iso, :target_dev => "sdc", :bus => "sata", :flags => 0)
+
+ ok &&
+ domain.calls == [:update] &&
+ domain.xml.include?('device="cdrom"') &&
+ domain.xml.include?('type="file"') &&
+ domain.xml.include?("")
+ client = AttachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+ iso = "os.iso"
+
+ ok = service.attach_iso(uuid, iso)
+
+ ok &&
+ domain.calls == [:attach] &&
+ domain.xml.include?('file="/var/lib/libvirt/images/os.iso"')
+ end
+
+ raises(::Libvirt::Error, "raises when both attach and update fail") do
+ domain = AttachIsoFakeDomain.new(
+ "",
+ :fail_attach => true,
+ :fail_update => true
+ )
+ client = AttachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+ iso = "/var/lib/libvirt/images/os.iso"
+
+ service.attach_iso(uuid, iso, :target_dev => "sdc", :bus => "sata", :flags => 0)
+ end
+ end
+end
diff --git a/tests/libvirt/requests/compute/destroy_iso_tests.rb b/tests/libvirt/requests/compute/destroy_iso_tests.rb
new file mode 100644
index 0000000..7fd29a1
--- /dev/null
+++ b/tests/libvirt/requests/compute/destroy_iso_tests.rb
@@ -0,0 +1,69 @@
+require File.expand_path("../../../helper", __dir__)
+require "fog/libvirt"
+
+class DeleteIsoFakeVolume
+ attr_reader :name, :deleted
+
+ def initialize(name, &on_delete)
+ @name = name
+ @on_delete = on_delete
+ end
+
+ def delete
+ @deleted = true
+ @on_delete&.call(name)
+ true
+ end
+end
+
+class DeleteIsoFakePool
+ def initialize(volumes = {})
+ @volumes = volumes
+ end
+
+ def lookup_volume_by_name(volume_name)
+ volume = @volumes[volume_name]
+ raise ::Libvirt::RetrieveError, "volume not found" unless volume
+
+ volume
+ end
+end
+
+class DeleteIsoFakeClient
+ def initialize(pool)
+ @pool = pool
+ end
+
+ def lookup_storage_pool_by_name(_pool_name)
+ @pool
+ end
+end
+
+Shindo.tests("Fog::Compute[:libvirt] | destroy_iso") do
+ tests("destroy_iso") do
+ returns(true, "deletes an iso storage volume from a pool and verifies absence") do
+ volumes = {}
+ volume = DeleteIsoFakeVolume.new("os.iso") { |name| volumes.delete(name) }
+ volumes["os.iso"] = volume
+ pool = DeleteIsoFakePool.new(volumes)
+ client = DeleteIsoFakeClient.new(pool)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ ok = service.destroy_iso("default", "os.iso")
+
+ ok && volume.deleted
+ end
+
+ returns(true, "returns true when iso volume is already absent") do
+ pool = DeleteIsoFakePool.new({})
+ client = DeleteIsoFakeClient.new(pool)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ service.destroy_iso("default", "os.iso")
+ end
+ end
+end
diff --git a/tests/libvirt/requests/compute/detach_iso_tests.rb b/tests/libvirt/requests/compute/detach_iso_tests.rb
new file mode 100644
index 0000000..6c504c2
--- /dev/null
+++ b/tests/libvirt/requests/compute/detach_iso_tests.rb
@@ -0,0 +1,114 @@
+require File.expand_path("../../../helper", __dir__)
+require "fog/libvirt"
+
+class DetachIsoFakeDomain
+ attr_reader :xml, :flags, :update_xml, :update_flags, :calls
+
+ def initialize(active: false, fail_detach: false)
+ @active = active
+ @fail_detach = fail_detach
+ @calls = []
+ end
+
+ def active?
+ @active
+ end
+
+ def update_device(xml, flags = 0)
+ @calls << :update
+ @update_xml = xml
+ @update_flags = flags
+ true
+ end
+
+ def detach_device(xml, flags = 0)
+ raise ::Libvirt::Error, "detach not supported" if @fail_detach
+
+ @calls << :detach
+ @xml = xml
+ @flags = flags
+ true
+ end
+end
+
+class DetachIsoFakeClient
+ def initialize(domain)
+ @domain = domain
+ end
+
+ def lookup_domain_by_uuid(_uuid)
+ @domain
+ end
+end
+
+Shindo.tests("Fog::Compute[:libvirt] | detach_iso") do
+ tests("detach_iso") do
+ returns(true, "detaches a cdrom device via libvirt detach_device") do
+ domain = DetachIsoFakeDomain.new(:active => false)
+ client = DetachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+ ok = service.detach_iso(uuid, :target_dev => "sdc", :bus => "sata", :flags => 0)
+
+ ok &&
+ domain.calls == [:detach] &&
+ domain.xml.include?('device="cdrom"') &&
+ domain.xml.include?('type="file"') &&
+ domain.xml.include?('dev="sdc"') &&
+ domain.xml.include?('bus="sata"') &&
+ domain.flags.zero?
+ end
+
+ returns(true, "uses AFFECT_LIVE and AFFECT_CONFIG for active domains by default") do
+ domain = DetachIsoFakeDomain.new(:active => true)
+ client = DetachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+
+ ok = service.detach_iso(uuid)
+
+ ok &&
+ domain.calls == [:update, :detach] &&
+ domain.update_xml.include?('tray="open"') &&
+ domain.flags == (::Libvirt::Domain::AFFECT_CONFIG | ::Libvirt::Domain::AFFECT_LIVE)
+ end
+
+ returns(true, "returns ejection success when live cdrom detach is unsupported") do
+ domain = DetachIsoFakeDomain.new(:active => true, :fail_detach => true)
+ client = DetachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+
+ ok = service.detach_iso(uuid)
+
+ ok &&
+ domain.calls == [:update] &&
+ domain.update_xml.include?('tray="open"')
+ end
+
+ returns(true, "respects combined flags that already include AFFECT_CONFIG") do
+ domain = DetachIsoFakeDomain.new(:active => true)
+ client = DetachIsoFakeClient.new(domain)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ uuid = "11111111-2222-3333-4444-555555555555"
+ combined_flags = ::Libvirt::Domain::AFFECT_CONFIG | ::Libvirt::Domain::AFFECT_LIVE
+
+ ok = service.detach_iso(uuid, :flags => combined_flags)
+
+ ok &&
+ domain.flags == combined_flags
+ end
+ end
+end
diff --git a/tests/libvirt/requests/compute/upload_iso_tests.rb b/tests/libvirt/requests/compute/upload_iso_tests.rb
new file mode 100644
index 0000000..4331cc3
--- /dev/null
+++ b/tests/libvirt/requests/compute/upload_iso_tests.rb
@@ -0,0 +1,122 @@
+require File.expand_path("../../../helper", __dir__)
+require "fog/libvirt"
+require "tempfile"
+
+class UploadIsoFakeVolume
+ attr_reader :name, :path, :key, :deleted
+
+ def initialize(name, path, key, &on_delete)
+ @name = name
+ @path = path
+ @key = key
+ @on_delete = on_delete
+ end
+
+ def upload(_stream, _offset, _length)
+ true
+ end
+
+ def delete
+ @deleted = true
+ @on_delete&.call(name)
+ true
+ end
+end
+
+class UploadIsoFakePool
+ attr_reader :xml, :volume, :deleted_volume_names
+
+ def initialize(existing_volume_names = [])
+ @existing_volume_names = existing_volume_names
+ @deleted_volume_names = []
+ end
+
+ def create_vol_xml(xml)
+ @xml = xml
+ true
+ end
+
+ def list_volumes
+ @existing_volume_names
+ end
+
+ def lookup_volume_by_name(name)
+ on_delete = proc { |deleted_name| @deleted_volume_names << deleted_name } if @existing_volume_names.include?(name)
+ UploadIsoFakeVolume.new(name, "/var/lib/libvirt/images/#{name}", "pool/#{name}", &on_delete)
+ end
+end
+
+class UploadIsoFakeStream
+ def sendall
+ loop do
+ count, _chunk = yield(nil, 4096)
+ break if count.zero?
+ end
+ end
+
+ def finish; end
+end
+
+class UploadIsoFakeClient
+ def initialize(pool)
+ @pool = pool
+ end
+
+ def lookup_storage_pool_by_name(_pool_name)
+ @pool
+ end
+
+ def stream
+ UploadIsoFakeStream.new
+ end
+end
+
+Shindo.tests("Fog::Compute[:libvirt] | upload_iso") do
+ tests("upload_iso") do
+ returns(true, "creates and uploads an iso volume in the pool") do
+ pool = UploadIsoFakePool.new
+ client = UploadIsoFakeClient.new(pool)
+
+ service = Fog::Libvirt::Compute::Real.allocate
+ service.instance_variable_set(:@client, client)
+
+ file = Tempfile.new(["os", ".iso"])
+ file.write("test-iso")
+ file.flush
+
+ result = service.upload_iso("default", "os.iso", file.path)
+
+ !pool.xml.nil? &&
+ pool.xml.include?("os.iso") &&
+ pool.xml.include?("os.iso") &&
+ result[:name] == "os.iso"
+ ensure
+ file.close
+ file.unlink
+ end
+ end
+end