diff --git a/lib/fog/bin.rb b/lib/fog/bin.rb
index 7e17f451e..fe2a088e1 100644
--- a/lib/fog/bin.rb
+++ b/lib/fog/bin.rb
@@ -61,6 +61,7 @@ require 'fog/bin/dnsmadeeasy'
require 'fog/bin/ecloud'
require 'fog/bin/go_grid'
require 'fog/bin/google'
+require 'fog/bin/libvirt'
require 'fog/bin/linode'
require 'fog/bin/local'
require 'fog/bin/new_servers'
diff --git a/lib/fog/bin/libvirt.rb b/lib/fog/bin/libvirt.rb
new file mode 100644
index 000000000..b42ae67d9
--- /dev/null
+++ b/lib/fog/bin/libvirt.rb
@@ -0,0 +1,53 @@
+module Libvirt # deviates from other bin stuff to accomodate gem
+ class << self
+
+ def class_for(key)
+ case key
+ when :compute
+ Fog::Compute::Libvirt
+ else
+ raise ArgumentError, "Unrecognized service: #{key}"
+ end
+ end
+
+ def [](service)
+ @@connections ||= Hash.new do |hash, key|
+ hash[key] = case key
+ when :compute
+ Formatador.display_line("[yellow][WARN] Libvirt[:compute] is deprecated, use Compute[:libvirt] instead[/]")
+ Fog::Compute.new(:provider => 'Libvirt')
+ else
+ raise ArgumentError, "Unrecognized service: #{key.inspect}"
+ end
+ end
+ @@connections[service]
+ end
+
+ def available?
+ availability = !Gem.source_index.find_name('ruby-libvirt').empty?
+ if availability
+ for service in services
+ for collection in self.class_for(service).collections
+ unless self.respond_to?(collection)
+ self.class_eval <<-EOS, __FILE__, __LINE__
+ def self.#{collection}
+ self[:#{service}].#{collection}
+ end
+ EOS
+ end
+ end
+ end
+ end
+ availability
+ end
+
+ def collections
+ services.map {|service| self[service].collections}.flatten.sort_by {|service| service.to_s}
+ end
+
+ def services
+ Fog::Libvirt.services
+ end
+
+ end
+end
diff --git a/lib/fog/compute.rb b/lib/fog/compute.rb
index e5ca41d4f..79d534373 100644
--- a/lib/fog/compute.rb
+++ b/lib/fog/compute.rb
@@ -47,6 +47,9 @@ module Fog
when 'VirtualBox'
require 'fog/compute/virtual_box'
Fog::Compute::VirtualBox.new(attributes)
+ when :libvirt
+ require 'fog/compute/libvirt'
+ Fog::Compute::Libvirt.new(attributes)
when :voxel
require 'fog/compute/voxel'
Fog::Compute::Voxel.new(attributes)
@@ -57,7 +60,7 @@ module Fog
def self.servers
servers = []
- for provider in [:aws, :bluebox, :brightbox, :ecloud, :gogrid, :linode, :newservers, :ninefold, :rackspace, :slicehost, :stormondemand, :virtualbox, :voxel]
+ for provider in [:aws, :bluebox, :brightbox, :ecloud, :gogrid, :libvirt, :linode, :newservers, :ninefold, :rackspace, :slicehost, :stormondemand, :virtualbox, :voxel]
begin
servers.concat(self[provider].servers)
rescue # ignore any missing credentials/etc
diff --git a/lib/fog/compute/libvirt.rb b/lib/fog/compute/libvirt.rb
new file mode 100644
index 000000000..3aca18877
--- /dev/null
+++ b/lib/fog/compute/libvirt.rb
@@ -0,0 +1,49 @@
+module Fog
+ module Compute
+ class Libvirt < Fog::Service
+
+ requires :libvirt_uri
+
+ model_path 'fog/compute/models/libvirt'
+ model :server
+ collection :servers
+ model :network
+ collection :networks
+ model :interface
+ collection :interfaces
+ model :volume
+ collection :volumes
+ model :pool
+ collection :pools
+
+ class Mock
+
+ def initialize(options={})
+ Fog::Mock.not_implemented
+ end
+
+ end
+
+ class Real
+
+ def initialize(options={})
+ @uri = options[:libvirt_uri]
+
+ #libvirt is part of the gem => ruby-libvirt
+ require 'libvirt'
+ @connection = ::Libvirt::open(@uri)
+ end
+
+ # hack to provide 'requests'
+ def method_missing(method_sym, *arguments, &block)
+ if @connection.respond_to?(method_sym)
+ @connection.send(method_sym, *arguments)
+ else
+ super
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/fog/compute/models/libvirt/interface.rb b/lib/fog/compute/models/libvirt/interface.rb
new file mode 100644
index 000000000..741a46276
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/interface.rb
@@ -0,0 +1,46 @@
+require 'fog/core/model'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Interface < Fog::Model
+
+ identity :id
+
+ attribute :mac
+ attribute :name
+ attribute :xml_desc
+
+ def destroy
+ requires :raw
+ raw.delete
+ true
+ end
+
+ private
+
+ def raw
+ @raw
+ end
+
+ def raw=(new_raw)
+ @raw = new_raw
+
+ raw_attributes = {
+ :id => new_raw.name,
+ :name => new_raw.name,
+ :mac => new_raw.mac,
+ :xml_desc => new_raw.xml_desc,
+ }
+
+ merge_attributes(raw_attributes)
+
+ end
+
+ end
+
+ end
+ end
+
+end
diff --git a/lib/fog/compute/models/libvirt/interfaces.rb b/lib/fog/compute/models/libvirt/interfaces.rb
new file mode 100644
index 000000000..b567e31bb
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/interfaces.rb
@@ -0,0 +1,31 @@
+require 'fog/core/collection'
+require 'fog/compute/models/libvirt/interface'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Interfaces < Fog::Collection
+
+ model Fog::Compute::Libvirt::Interface
+
+ def all
+ data=[]
+ connection.list_interfaces.each do |ifname|
+ interface=connection.lookup_interface_by_name(ifname)
+ data << { :raw => interface }
+ end
+ load(data)
+ end
+
+ # Retrieve the interface by name
+ def get(name)
+ interface=connection.lookup_interface_by_name(name)
+ new(:raw => interface)
+ end
+
+ end #class
+
+ end #Class
+ end #module
+end #module
diff --git a/lib/fog/compute/models/libvirt/network.rb b/lib/fog/compute/models/libvirt/network.rb
new file mode 100644
index 000000000..524e5d33f
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/network.rb
@@ -0,0 +1,70 @@
+require 'fog/core/model'
+require 'fog/compute/models/libvirt/util'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Network < Fog::Model
+
+ include Fog::Compute::LibvirtUtil
+
+ identity :id
+ attribute :uuid
+ attribute :name
+ attribute :bridge_name
+
+ attribute :xml_desc
+
+ attr_reader :template_path,:network_mode,:bridge_name
+
+ ##https://www.redhat.com/archives/libvirt-users/2011-May/msg00091.html
+ # Bridged VLAN
+
+ # https://www.redhat.com/archives/libvirt-users/2011-April/msg00006.html
+ # Routed network without IP
+
+ # http://wiki.libvirt.org/page/Networking
+ #http://wiki.libvirt.org/page/VirtualNetworking#Virtual_network_switches
+ def initialize(attributes = {})
+
+ @template_path = attributes[:template_path] || "network.xml.erb"
+ @network_mode = attributes[:network_mode] || "nat"
+ @bridge_name = attributes[:bridge_name] || "virbr0"
+ template_xml
+ end
+
+ def destroy()
+ requires :raw
+ raw.destroy
+# raw.undefine
+ true
+ end
+
+ private
+
+ def raw
+ @raw
+ end
+
+ def raw=(new_raw)
+ @raw = new_raw
+
+ raw_attributes = {
+ :id => new_raw.uuid,
+ :uuid => new_raw.uuid,
+ :name => new_raw.name,
+ :bridge_name => new_raw.bridge_name,
+ :xml_desc => new_raw.xml_desc,
+ }
+
+ merge_attributes(raw_attributes)
+
+ end
+
+ end
+
+ end
+ end
+
+end
diff --git a/lib/fog/compute/models/libvirt/networks.rb b/lib/fog/compute/models/libvirt/networks.rb
new file mode 100644
index 000000000..359ef8727
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/networks.rb
@@ -0,0 +1,31 @@
+require 'fog/core/collection'
+require 'fog/compute/models/libvirt/network'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Networks < Fog::Collection
+
+ model Fog::Compute::Libvirt::Network
+
+ def all
+ data=[]
+ connection.list_networks.each do |networkname|
+ network=connection.lookup_network_by_name(networkname)
+ data << { :raw => network }
+ end
+ load(data)
+ end
+
+ # Retrieve the network by uuid
+ def get(uuid)
+ network=connection.lookup_network_by_uuid(uuid)
+ new(:raw => network)
+ end
+
+ end #class
+
+ end #Class
+ end #module
+end #module
diff --git a/lib/fog/compute/models/libvirt/pool.rb b/lib/fog/compute/models/libvirt/pool.rb
new file mode 100644
index 000000000..b3cb528df
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/pool.rb
@@ -0,0 +1,96 @@
+require 'fog/core/model'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Pool < Fog::Model
+
+ identity :id
+
+ attribute :name
+ attribute :uuid
+ attribute :xml
+
+ attr_reader :allocation
+ attr_reader :available
+ attr_reader :xml_desc
+ attr_reader :num_of_volumes
+ attr_reader :state
+
+ # There are two options to initialize a new Pool
+ # 1. provide :xml as an argument
+ # 2. provide :name, :path
+ def initialize(attributes={})
+# unless attributes.has_key?(:xml)
+# name = attributes[:name] || raise("Must provide a pool name")
+# path = attributes[:path] || "/var/lib/libvirt/images"
+# else
+# @xml = attributes[:xml]
+# end
+ super
+
+ end
+
+ def save
+ unless @xml.nil?
+ #connection.
+ end
+ end
+
+ def destroy
+ requires :raw
+
+ # Shutdown pool if active
+ if raw.active?
+ raw.destroy
+ end
+ # Delete corresponding data in this pool
+ raw.delete
+
+ true
+ end
+
+ def shutdown
+ requires :raw
+ raw.destroy
+ true
+ end
+
+ private
+
+ def raw
+ @raw
+ end
+
+ def raw=(new_raw)
+ @raw = new_raw
+
+ raw_attributes = {
+ :id => new_raw.uuid,
+ :uuid => new_raw.uuid,
+ :name => new_raw.name,
+ :xml_desc => new_raw.xml_desc,
+ :num_of_volumes => new_raw.num_of_volumes,
+ :allocation => new_raw.info.allocation,
+ :available => new_raw.info.available,
+ :capacity => new_raw.info.capacity,
+ :state => new_raw.info.state,
+ }
+
+ # State
+ #INACTIVE = INT2NUM(VIR_STORAGE_POOL_INACTIVE) virStoragePoolState
+ #BUILDING = INT2NUM(VIR_STORAGE_POOL_BUILDING)
+ #RUNNING = INT2NUM(VIR_STORAGE_POOL_RUNNING)
+ #DEGRADED = INT2NUM(VIR_STORAGE_POOL_DEGRADED)
+ #INACCESSIBLE = INT2NUM(VIR_STORAGE_POOL_INACCESSIBLE)
+
+ merge_attributes(raw_attributes)
+ end
+
+ end
+
+ end
+ end
+
+end
diff --git a/lib/fog/compute/models/libvirt/pools.rb b/lib/fog/compute/models/libvirt/pools.rb
new file mode 100644
index 000000000..56daa14f0
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/pools.rb
@@ -0,0 +1,31 @@
+require 'fog/core/collection'
+require 'fog/compute/models/libvirt/pool'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Pools < Fog::Collection
+
+ model Fog::Compute::Libvirt::Pool
+
+ def all
+ data=[]
+ connection.list_storage_pools.each do |poolname|
+ pool=connection.lookup_storage_pool_by_name(poolname)
+ data << { :raw => pool }
+ end
+ load(data)
+ end
+
+ # Retrieve the pool by uuid
+ def get(uuid)
+ pool=connection.lookup_storage_pool_by_uuid(uuid)
+ new(:raw => pool)
+ end
+
+ end #class
+
+ end #Class
+ end #module
+end #module
diff --git a/lib/fog/compute/models/libvirt/server.rb b/lib/fog/compute/models/libvirt/server.rb
new file mode 100644
index 000000000..285adcf10
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/server.rb
@@ -0,0 +1,237 @@
+require 'fog/core/model'
+require 'fog/compute/models/libvirt/util'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Server < Fog::Model
+
+ include Fog::Compute::LibvirtUtil
+
+ identity :id , :aliases => 'uuid'
+
+ attribute :memory_size
+ attribute :name
+ attribute :os, :aliases => :os_type_id
+ attribute :xml_desc
+ attribute :cpus
+ attribute :arch
+ attribute :bridge_name
+
+ attr_writer :private_key, :private_key_path, :public_key, :public_key_path, :username
+ attr_reader :bridge_name,:arch, :cpus,:bridge_name, :name,:template_path,:memory_size,:os,:volume_path
+
+ def initialize(attributes = {})
+ super
+ end
+
+ def create(attributes = {})
+ @name = attributes[:name] || raise("we need a name")
+ @bridge_name = attributes[:bridge_name] || "br0"
+ @cpus = attributes[:cpus] || 1
+ @memory_size = attributes[:memory_size] || 256
+ @username = attributes[:username] || "mccloud"
+ @os = attributes[:os] || "hvm"
+ @arch = attributes[:arch] || "x86_64"
+ @template_path = attributes[:template_path] || "guest.xml.erb"
+ # super
+ volume=connection.volumes.get("ubuntu-10_10_amd64.qcow2").clone("#{name}.qcow2")
+ @volume_path=volume.path
+ connection.define_domain_xml(template_xml)
+
+ end
+
+ def start
+ requires :raw
+
+ unless @raw.active?
+ begin
+ @raw.create
+ rescue
+ print "An error occured :",$!,"\n"
+ end
+ end
+ end
+
+
+ def destroy(options={ :destroy_volumes => false})
+
+ #connection.volumes(name).destroy
+ requires :raw
+ if @raw.active?
+ @raw.destroy
+ end
+ @raw.undefine
+ end
+
+
+ def ready?
+
+ status == :running
+ end
+
+ def reboot
+ requires :raw
+
+ @raw.reboot
+ end
+
+
+ def halt
+ requires :raw
+
+ @raw.shutdown
+ end
+
+ def resume
+ requires :raw
+
+ @raw.resume
+ end
+
+ def suspend
+ requires :raw
+
+ @raw.suspend
+ end
+
+ def status
+ state=case @raw.info.state
+ when 0 then :nostate
+ when 1 then :running
+ when 2 then :paused
+ when 3 then :shuttingdown
+ when 4 then :shutoff
+ when 5 then :crashed
+ end
+ return state
+ end
+
+ def save()
+
+ raise Fog::Errors::Error.new('Updating an existing server is not yet implemented. Contributions welcome!')
+ end
+
+ def scp(local_path, remote_path, upload_options = {})
+ raise 'Not Implemented'
+ requires :addresses, :username
+
+ scp_options = {}
+ scp_options[:key_data] = [private_key] if private_key
+ Fog::SCP.new(addresses['public'].first, username, options).upload(local_path, remote_path, scp_options)
+ end
+
+ def setup(credentials = {})
+ requires :addresses, :identity, :public_key, :username
+ Fog::SSH.new(addresses['public'].first, username, credentials).run([
+ %{mkdir .ssh},
+ %{echo "#{public_key}" >> ~/.ssh/authorized_keys},
+ %{echo "#{attributes.to_json}" >> ~/attributes.json},
+ %{echo "#{metadata.to_json}" >> ~/metadata.json}
+ ])
+ rescue Errno::ECONNREFUSED
+ sleep(1)
+ retry
+ end
+
+
+ ##Note this requires arpwatch to be running
+ ##and chmod o+x /var/lib/arpwatch
+
+ def addresses
+ mac=self.mac
+ options={}
+ ipaddress=nil
+ if connected_by_ssh?
+ #command="arp -an|grep #{mac}|cut -d ' ' -f 2| cut -d '(' -f 2| cut -d ')' -f 1"
+ #command="grep #{mac} /var/log/daemon.log |sed -e 's/^.*address //'|cut -d ' ' -f 1"
+ command="grep #{mac} /var/lib/arpwatch/arp.dat|cut -f 2"
+ result=Fog::SSH.new(connection.hostname, "patrick.debois", options).run(command)
+ if result.first.status == 0
+ ipaddress=result.first.stdout.strip
+ #TODO check for valid IP
+ #TODO check time validity
+ else
+ #cat /var/log/daemon.log|grep "52:54:00:52:f6:22"|
+ end
+ else
+ #local execute arp -an to get the ip
+ end
+ return { 'public' => [ipaddress], 'private' => [ipaddress]}
+ end
+
+
+ def ssh(commands)
+ requires :addresses, :identity, :username
+
+ options = {}
+ #options[:key_data] = [private_key] if private_key
+
+ require 'net/ssh/proxy/command'
+ options={ :password => "mccloud"}
+ if connected_by_ssh?
+ relay=connection.hostname
+ proxy = Net::SSH::Proxy::Command.new('ssh -l patrick.debois '+relay+' nc %h %p')
+ options[:proxy]= proxy
+ end
+ #Fog::SSH.new("192.168.122.48", "vagrant", options).run(commands)
+ Fog::SSH.new(addresses['public'].first, "mccloud", options).run(commands)
+
+ end
+
+ def stop
+ requires :raw
+
+ @raw.shutdown
+ end
+
+ def username
+ @username ||= 'root'
+ end
+
+ def mac
+ require "rexml/document"
+ require 'erb'
+
+ mac = document("domain/devices/interface/mac", "address")
+ return mac
+ end
+
+ private
+
+ def raw
+ @raw
+ end
+
+ def raw=(new_raw)
+ @raw = new_raw
+
+ raw_attributes = {
+ :id => new_raw.uuid,
+ :memory_size => new_raw.info.max_mem ,
+ :name => new_raw.name,
+ :cpus => new_raw.info.nr_virt_cpu,
+ :os_type_id => new_raw.os_type,
+ :xml_desc => new_raw.xml_desc,
+
+ }
+
+ merge_attributes(raw_attributes)
+ end
+
+ # finds a value from xml
+ def document path, attribute=nil
+ xml = REXML::Document.new(xml_desc)
+ attribute.nil? ? xml.elements[path].text : xml.elements[path].attributes[attribute]
+ end
+
+ def connected_by_ssh?
+ return connection.uri.include?("+ssh")
+ end
+ end
+
+ end
+ end
+
+end
diff --git a/lib/fog/compute/models/libvirt/servers.rb b/lib/fog/compute/models/libvirt/servers.rb
new file mode 100644
index 000000000..1eadb4531
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/servers.rb
@@ -0,0 +1,52 @@
+require 'fog/core/collection'
+require 'fog/compute/models/libvirt/server'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Servers < Fog::Collection
+
+ model Fog::Compute::Libvirt::Server
+
+ def all
+
+ data = connection.list_defined_domains.map do |machine|
+ {
+ :raw => connection.lookup_domain_by_name(machine)
+ }
+ end
+
+ connection.list_domains.each do |machine|
+ data << {
+ :raw => connection.lookup_domain_by_id(machine)
+ }
+ end
+ load(data)
+ end
+
+ def bootstrap(new_attributes = {})
+ raise 'Not Implemented'
+ # server = create(new_attributes)
+ # server.start
+ # server.wait_for { ready? }
+ # server.setup(:password => server.password)
+ # server
+ end
+
+ # Retrieve the server by uuid
+ def get(server_id)
+ machine=connection.lookup_domain_by_uuid(server_id)
+ new(:raw => machine)
+ end
+
+ # Retrieve the server by name
+ def get_by_name(name)
+ machine=connection.lookup_domain_by_name(name)
+ new(:raw => machine)
+ end
+
+ end #class
+ end #Class
+ end #module
+end #Module
diff --git a/lib/fog/compute/models/libvirt/templates/guest.xml.erb b/lib/fog/compute/models/libvirt/templates/guest.xml.erb
new file mode 100644
index 000000000..fdb90a0f8
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/templates/guest.xml.erb
@@ -0,0 +1,37 @@
+
+ <%= name %>
+ <%= memory_size %>
+ <%= cpus %>
+
+ <%= os %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/fog/compute/models/libvirt/templates/network.xml.erb b/lib/fog/compute/models/libvirt/templates/network.xml.erb
new file mode 100644
index 000000000..977557f5d
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/templates/network.xml.erb
@@ -0,0 +1,6 @@
+
+ <%= name %>
+
+
+
+
\ No newline at end of file
diff --git a/lib/fog/compute/models/libvirt/templates/pool.xml.erb b/lib/fog/compute/models/libvirt/templates/pool.xml.erb
new file mode 100644
index 000000000..e70137e11
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/templates/pool.xml.erb
@@ -0,0 +1,6 @@
+
+ <%= name %>
+
+ <%= path %>
+
+
\ No newline at end of file
diff --git a/lib/fog/compute/models/libvirt/templates/volume.xml b/lib/fog/compute/models/libvirt/templates/volume.xml
new file mode 100644
index 000000000..ca94c34c5
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/templates/volume.xml
@@ -0,0 +1,14 @@
+
+ ubuntu.qcow2
+ 10
+ 10
+
+
+
+ 0
+ 0
+ 0744
+
+
+
+
\ No newline at end of file
diff --git a/lib/fog/compute/models/libvirt/util.rb b/lib/fog/compute/models/libvirt/util.rb
new file mode 100644
index 000000000..b3c19289a
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/util.rb
@@ -0,0 +1,28 @@
+require "rexml/document"
+require 'erb'
+
+module Fog
+ module Compute
+ module LibvirtUtil
+ # return templated xml to be used by libvirt
+ def template_xml
+ ERB.new(template, nil, '-').result(binding)
+ end
+
+ private
+ # template file that contain our xml template
+ def template
+ File.read("#{File.dirname(__FILE__)}/templates/#{template_path}")
+ rescue => e
+ warn "failed to read template #{template_path}: #{e}"
+ end
+
+ # finds a value from xml
+ def document path, attribute=nil
+ return nil if new?
+ xml = REXML::Document.new(@xml_desc)
+ attribute.nil? ? xml.elements[path].text : xml.elements[path].attributes[attribute]
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/fog/compute/models/libvirt/volume.rb b/lib/fog/compute/models/libvirt/volume.rb
new file mode 100644
index 000000000..bd2a241f9
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/volume.rb
@@ -0,0 +1,70 @@
+require 'fog/core/model'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Volume < Fog::Model
+
+ identity :id
+
+ attribute :key
+ attribute :path
+ attribute :name
+ attribute :type
+ attribute :allocation
+ attribute :capacity
+ attribute :xml_desc
+
+ def destroy
+ requires :raw
+ raw.delete
+ true
+ end
+
+ def wipe
+ requires :raw
+ raw.wipe
+ true
+ end
+
+ def clone(name)
+ pool=@raw.pool
+ xml = REXML::Document.new(xml_desc)
+ xml.root.elements['/volume/name'].text=name
+ xml.root.elements['/volume/key'].text=name
+ xml.delete_element('/volume/target/path')
+ puts "cloning this might take a while"
+ pool.create_volume_xml_from(xml.to_s,@raw)
+ return connection.volumes.get(name)
+ end
+
+ private
+
+ def raw
+ @raw
+ end
+
+ def raw=(new_raw)
+ @raw = new_raw
+
+ raw_attributes = {
+ :id => new_raw.key,
+ :key => new_raw.key,
+ :path => new_raw.path ,
+ :name => new_raw.name,
+ :xml_desc => new_raw.xml_desc,
+ :allocation => new_raw.info.allocation,
+ :capacity => new_raw.info.capacity,
+ :type => new_raw.info.type
+ }
+
+ merge_attributes(raw_attributes)
+ end
+
+ end
+
+ end
+ end
+
+end
diff --git a/lib/fog/compute/models/libvirt/volumes.rb b/lib/fog/compute/models/libvirt/volumes.rb
new file mode 100644
index 000000000..53fc18519
--- /dev/null
+++ b/lib/fog/compute/models/libvirt/volumes.rb
@@ -0,0 +1,40 @@
+require 'fog/core/collection'
+require 'fog/compute/models/libvirt/volume'
+
+module Fog
+ module Compute
+ class Libvirt
+
+ class Volumes < Fog::Collection
+
+ model Fog::Compute::Libvirt::Volume
+
+ def all
+ data=[]
+ connection.list_storage_pools.each do |poolname|
+ pool=connection.lookup_storage_pool_by_name(poolname)
+ pool.list_volumes.each do |volumename|
+ data << { :raw => pool.lookup_volume_by_name(volumename) }
+ end
+ end
+ load(data)
+ end
+
+ # Retrieve the volume by uuid
+ def get(key)
+ connection.list_storage_pools.each do |poolname|
+ pool=connection.lookup_storage_pool_by_name(poolname)
+ volume=pool.lookup_volume_by_name(key)
+ unless volume.nil?
+ return new(:raw => volume)
+ end
+ end
+
+ return nil
+ end
+
+ end
+
+ end
+ end
+end
diff --git a/lib/fog/providers.rb b/lib/fog/providers.rb
index 9d42d9ada..e48f83138 100644
--- a/lib/fog/providers.rb
+++ b/lib/fog/providers.rb
@@ -14,6 +14,7 @@ require 'fog/providers/dnsmadeeasy'
require 'fog/providers/ecloud'
require 'fog/providers/go_grid'
require 'fog/providers/google'
+require 'fog/providers/libvirt'
require 'fog/providers/linode'
require 'fog/providers/local'
require 'fog/providers/new_servers'
diff --git a/lib/fog/providers/libvirt.rb b/lib/fog/providers/libvirt.rb
new file mode 100644
index 000000000..eb567a1b6
--- /dev/null
+++ b/lib/fog/providers/libvirt.rb
@@ -0,0 +1,11 @@
+require 'fog/core'
+
+module Fog
+ module Libvirt
+
+ extend Fog::Provider
+
+ service(:compute, 'compute/libvirt')
+
+ end
+end