mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
[libvirt] refactored libvirt entire code
* moved to using requests * added vm nic/nics * kept compatability with the existing interfaces * moved util classes into util subdir Signed-off-by: Amos Benari <abenari@redhat.com>
This commit is contained in:
parent
12f539c577
commit
9d78d29a19
36 changed files with 986 additions and 1010 deletions
|
@ -1,13 +1,13 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'libvirt'))
|
||||
require 'fog/compute'
|
||||
|
||||
require 'fog/libvirt/models/compute/uri'
|
||||
require 'fog/libvirt/models/compute/util/util'
|
||||
require 'fog/libvirt/models/compute/util/uri'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Libvirt < Fog::Service
|
||||
|
||||
requires :libvirt_uri
|
||||
requires :libvirt_uri
|
||||
recognizes :libvirt_username, :libvirt_password
|
||||
recognizes :libvirt_ip_command
|
||||
|
||||
|
@ -24,18 +24,33 @@ module Fog
|
|||
collection :pools
|
||||
model :node
|
||||
collection :nodes
|
||||
model :nic
|
||||
collection :nics
|
||||
|
||||
request_path 'fog/libvirt/requests/compute'
|
||||
request :list_domains
|
||||
request :create_domain
|
||||
request :define_domain
|
||||
request :vm_action
|
||||
request :list_pools
|
||||
request :list_pool_volumes
|
||||
request :define_pool
|
||||
request :pool_action
|
||||
request :list_volumes
|
||||
request :volume_action
|
||||
request :create_volume
|
||||
request :list_networks
|
||||
request :destroy_network
|
||||
request :list_interfaces
|
||||
request :destroy_interface
|
||||
request :get_node_info
|
||||
|
||||
class Mock
|
||||
|
||||
def initialize(options={})
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Real
|
||||
|
||||
attr_reader :raw
|
||||
include Fog::Compute::LibvirtUtil
|
||||
attr_reader :client
|
||||
attr_reader :uri
|
||||
attr_reader :ip_command
|
||||
|
||||
|
@ -49,16 +64,16 @@ module Fog
|
|||
|
||||
begin
|
||||
if options[:libvirt_username] and options[:libvirt_password]
|
||||
@raw = ::Libvirt::open_auth(@uri.uri, [::Libvirt::CRED_AUTHNAME, ::Libvirt::CRED_PASSPHRASE]) do |cred|
|
||||
if cred['type'] == ::Libvirt::CRED_AUTHNAME
|
||||
res = options[:libvirt_username]
|
||||
elsif cred["type"] == ::Libvirt::CRED_PASSPHRASE
|
||||
res = options[:libvirt_password]
|
||||
else
|
||||
@client = ::Libvirt::open_auth(uri.uri, [::Libvirt::CRED_AUTHNAME, ::Libvirt::CRED_PASSPHRASE]) do |cred|
|
||||
case cred['type']
|
||||
when ::Libvirt::CRED_AUTHNAME
|
||||
options[:libvirt_username]
|
||||
when ::Libvirt::CRED_PASSPHRASE
|
||||
options[:libvirt_password]
|
||||
end
|
||||
end
|
||||
else
|
||||
@raw = ::Libvirt::open(@uri.uri)
|
||||
@client = ::Libvirt::open(uri.uri)
|
||||
end
|
||||
|
||||
rescue ::Libvirt::ConnectionError
|
||||
|
@ -67,6 +82,10 @@ module Fog
|
|||
|
||||
end
|
||||
|
||||
def terminate
|
||||
@client.close if @client and !@client.closed?
|
||||
end
|
||||
|
||||
def enhance_uri(uri)
|
||||
require 'cgi'
|
||||
append=""
|
||||
|
@ -89,19 +108,6 @@ module Fog
|
|||
uri+append
|
||||
end
|
||||
|
||||
def respond_to?(method, *)
|
||||
super or @connection.respond_to? method
|
||||
end
|
||||
|
||||
# hack to provide 'requests'
|
||||
def method_missing(method_sym, *arguments, &block)
|
||||
if @raw.respond_to?(method_sym)
|
||||
@raw.send(method_sym, *arguments)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,42 +7,22 @@ module Fog
|
|||
class Interface < Fog::Model
|
||||
|
||||
identity :name
|
||||
|
||||
attribute :mac
|
||||
attribute :xml
|
||||
attribute :active
|
||||
|
||||
def save
|
||||
raise Fog::Errors::Error.new('Creating a new interface is not yet implemented. Contributions welcome!')
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :raw
|
||||
raw.delete
|
||||
true
|
||||
def shutdown
|
||||
connection.destroy_interface(mac)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def raw
|
||||
@raw
|
||||
def active?
|
||||
active
|
||||
end
|
||||
|
||||
def raw=(new_raw)
|
||||
@raw = new_raw
|
||||
|
||||
raw_attributes = {
|
||||
:name => new_raw.name,
|
||||
:mac => new_raw.mac,
|
||||
:xml => new_raw.xml_desc,
|
||||
}
|
||||
|
||||
merge_attributes(raw_attributes)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,54 +9,16 @@ module Fog
|
|||
|
||||
model Fog::Compute::Libvirt::Interface
|
||||
|
||||
def all(filter=nil)
|
||||
data=[]
|
||||
if filter.nil?
|
||||
connection.raw.list_interfaces.each do |ifname|
|
||||
interface=connection.raw.lookup_interface_by_name(ifname)
|
||||
data << { :raw => interface }
|
||||
end
|
||||
connection.raw.list_defined_interfaces.each do |ifname|
|
||||
interface=connection.raw.lookup_interface_by_name(ifname)
|
||||
data << { :raw => interface }
|
||||
end
|
||||
|
||||
else
|
||||
interface=nil
|
||||
begin
|
||||
interface=get_by_name(filter[:name]) if filter.has_key?(:name)
|
||||
interface=get_by_mac(filter[:mac]) if filter.has_key?(:mac)
|
||||
rescue ::Libvirt::RetrieveError
|
||||
return nil
|
||||
end
|
||||
data << { :raw => interface}
|
||||
end
|
||||
|
||||
load(data)
|
||||
def all(filter={})
|
||||
load(connection.list_interfaces(filter))
|
||||
end
|
||||
|
||||
def get(key)
|
||||
self.all(:name => name).first
|
||||
end
|
||||
|
||||
#private # Making these private, screws up realod
|
||||
# Retrieve the interface by name
|
||||
def get_by_name(name)
|
||||
interface=connection.raw.lookup_interface_by_name(name)
|
||||
return interface
|
||||
# new(:raw => interface)
|
||||
end
|
||||
end
|
||||
|
||||
# Retrieve the interface by name
|
||||
def get_by_mac(mac)
|
||||
interface=connection.raw.lookup_interface_by_mac(mac)
|
||||
return interface
|
||||
# new(:raw => interface)
|
||||
end
|
||||
|
||||
|
||||
end #class
|
||||
|
||||
end #Class
|
||||
end #module
|
||||
end #module
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/libvirt/models/compute/util'
|
||||
require 'fog/libvirt/models/compute/util/util'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
|
@ -10,19 +10,10 @@ module Fog
|
|||
include Fog::Compute::LibvirtUtil
|
||||
|
||||
identity :uuid
|
||||
|
||||
attribute :name
|
||||
attribute :bridge_name
|
||||
attribute :xml
|
||||
|
||||
##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 = {})
|
||||
super
|
||||
end
|
||||
|
@ -31,30 +22,8 @@ module Fog
|
|||
raise Fog::Errors::Error.new('Creating a new network is not yet implemented. Contributions welcome!')
|
||||
end
|
||||
|
||||
def destroy()
|
||||
requires :raw
|
||||
raw.destroy
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def raw
|
||||
@raw
|
||||
end
|
||||
|
||||
def raw=(new_raw)
|
||||
@raw = new_raw
|
||||
|
||||
raw_attributes = {
|
||||
:uuid => new_raw.uuid,
|
||||
:name => new_raw.name,
|
||||
:bridge_name => new_raw.bridge_name,
|
||||
:xml => new_raw.xml_desc,
|
||||
}
|
||||
|
||||
merge_attributes(raw_attributes)
|
||||
|
||||
def shutdown
|
||||
connection.destroy_network(uuid)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,53 +9,16 @@ module Fog
|
|||
|
||||
model Fog::Compute::Libvirt::Network
|
||||
|
||||
def all(filter=nil)
|
||||
data=[]
|
||||
if filter.nil?
|
||||
connection.list_networks.each do |networkname|
|
||||
network=connection.lookup_network_by_name(networkname)
|
||||
data << { :raw => network }
|
||||
end
|
||||
connection.list_defined_networks.each do |networkname|
|
||||
network=connection.lookup_network_by_name(networkname)
|
||||
data << { :raw => network}
|
||||
end
|
||||
else
|
||||
network=nil
|
||||
begin
|
||||
network=get_by_uuid(filter[:uuid]) if filter.has_key?(:uuid)
|
||||
network=get_by_name(filter[:name]) if filter.has_key?(:name)
|
||||
rescue ::Libvirt::RetrieveError
|
||||
return nil
|
||||
end
|
||||
data << { :raw => network}
|
||||
end
|
||||
|
||||
load(data)
|
||||
def all(filter={})
|
||||
load(connection.list_networks(filter))
|
||||
end
|
||||
|
||||
def get(uuid)
|
||||
self.all(:uuid => uuid).first
|
||||
end
|
||||
|
||||
#private # Making these private, screws up realod
|
||||
# Retrieve the network by uuid
|
||||
def get_by_uuid(uuid)
|
||||
network=connection.lookup_network_by_uuid(uuid)
|
||||
return network
|
||||
# new(:raw => network)
|
||||
end
|
||||
end
|
||||
|
||||
# Retrieve the network by name
|
||||
def get_by_name(name)
|
||||
network=connection.lookup_network_by_name(name)
|
||||
return network
|
||||
# new(:raw => network)
|
||||
end
|
||||
|
||||
|
||||
end #class
|
||||
|
||||
end #Class
|
||||
end #module
|
||||
end #module
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
54
lib/fog/libvirt/models/compute/nic.rb
Normal file
54
lib/fog/libvirt/models/compute/nic.rb
Normal file
|
@ -0,0 +1,54 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
|
||||
class Nic < Fog::Model
|
||||
|
||||
identity :mac
|
||||
attribute :type
|
||||
attribute :network
|
||||
attribute :bridge
|
||||
attribute :model
|
||||
|
||||
attr_accessor :server
|
||||
|
||||
TYPES = ["network", "bridge", "user"]
|
||||
|
||||
def new?
|
||||
mac.nil?
|
||||
end
|
||||
|
||||
def initialize attributes
|
||||
super defaults.merge(attributes)
|
||||
raise Fog::Errors::Error.new("#{type} is not a supported nic type") if new? && !TYPES.include?(type)
|
||||
end
|
||||
|
||||
def save
|
||||
raise Fog::Errors::Error.new('Creating a new nic is not yet implemented. Contributions welcome!')
|
||||
#requires :server
|
||||
#connection.attach_nic(domain , self)
|
||||
end
|
||||
|
||||
def destroy
|
||||
raise Fog::Errors::Error.new('Destroying an interface is not yet implemented. Contributions welcome!')
|
||||
#requires :server
|
||||
##detach the nic
|
||||
#connection.detach_nic(domain, mac)
|
||||
end
|
||||
|
||||
private
|
||||
def defaults
|
||||
{
|
||||
:type => "bridge",
|
||||
:model => "virtio"
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
16
lib/fog/libvirt/models/compute/nics.rb
Normal file
16
lib/fog/libvirt/models/compute/nics.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/libvirt/models/compute/nic'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
|
||||
class Nics < Fog::Collection
|
||||
|
||||
model Fog::Compute::Libvirt::Nic
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,7 +6,7 @@ module Fog
|
|||
|
||||
class Node < Fog::Model
|
||||
|
||||
identity :uri
|
||||
identity :uuid
|
||||
|
||||
attribute :model
|
||||
attribute :memory
|
||||
|
@ -16,26 +16,14 @@ module Fog
|
|||
attribute :sockets
|
||||
attribute :cores
|
||||
attribute :threads
|
||||
|
||||
attribute :type
|
||||
attribute :version
|
||||
attribute :uri
|
||||
attribute :node_free_memory
|
||||
attribute :max_vcpus
|
||||
|
||||
private
|
||||
|
||||
def raw
|
||||
@raw
|
||||
end
|
||||
|
||||
def raw=(new_raw)
|
||||
@raw = new_raw
|
||||
|
||||
raw_attributes = new_raw
|
||||
|
||||
merge_attributes(raw_attributes)
|
||||
end
|
||||
attribute :manufacturer
|
||||
attribute :product
|
||||
attribute :serial
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -9,30 +9,15 @@ module Fog
|
|||
|
||||
model Fog::Compute::Libvirt::Node
|
||||
|
||||
def all(filter=nil)
|
||||
data=[]
|
||||
node_info=Hash.new
|
||||
[:model, :memory, :cpus, :mhz, :nodes, :sockets, :cores, :threads].each do |param|
|
||||
begin
|
||||
node_info[param]=connection.node_get_info.send(param)
|
||||
rescue ::Libvirt::RetrieveError
|
||||
node_info[param]=nil
|
||||
end
|
||||
end
|
||||
[:type, :version, :node_free_memory, :max_vcpus].each do |param|
|
||||
begin
|
||||
node_info[param] = connection.send(param)
|
||||
rescue ::Libvirt::RetrieveError
|
||||
node_info[param]=nil
|
||||
end
|
||||
end
|
||||
node_info[:uri]=connection.uri
|
||||
data << { :raw => node_info }
|
||||
load(data)
|
||||
def all(filter={ })
|
||||
load(connection.get_node_info)
|
||||
end
|
||||
|
||||
def get
|
||||
all.first
|
||||
end
|
||||
|
||||
end #class
|
||||
end #Class
|
||||
end #module
|
||||
end #Module
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,191 +5,79 @@ module Fog
|
|||
class Libvirt
|
||||
|
||||
class Pool < Fog::Model
|
||||
attr_reader :xml
|
||||
|
||||
identity :uuid
|
||||
|
||||
# These attributes are only used for creation
|
||||
attribute :xml
|
||||
attribute :create_persistent
|
||||
attribute :create_auto_build
|
||||
attribute :persistent
|
||||
attribute :autostart
|
||||
attribute :active
|
||||
attribute :name
|
||||
attribute :allocation
|
||||
attribute :capacity
|
||||
attribute :num_of_volumes
|
||||
attribute :state
|
||||
|
||||
# Can be created by passing in XML
|
||||
def initialize(attributes={} )
|
||||
self.xml ||= nil unless attributes[:xml]
|
||||
self.create_persistent ||= true unless attributes[:create_persistent]
|
||||
self.create_auto_build ||= true unless attributes[:create_auto_build]
|
||||
super
|
||||
# Can be created by passing in XML
|
||||
@xml = attributes.delete(:xml)
|
||||
super(attributes)
|
||||
end
|
||||
|
||||
def save
|
||||
requires :xml
|
||||
unless xml.nil?
|
||||
pool=nil
|
||||
if self.create_persistent
|
||||
pool=connection.raw.define_storage_pool_xml(xml)
|
||||
else
|
||||
pool=connection.raw.create_storage_pool_xml(xml)
|
||||
end
|
||||
self.raw=pool
|
||||
true
|
||||
else
|
||||
raise Fog::Errors::Error.new('Creating a new pool requires proper xml')
|
||||
false
|
||||
end
|
||||
raise Fog::Errors::Error.new('Creating a new pool requires proper xml') unless xml
|
||||
self.uuid = (persistent ? connection.define_pool(xml) : connection.create_pool(xml)).uuid
|
||||
reload
|
||||
end
|
||||
|
||||
|
||||
# Start the pool = make it active
|
||||
# Performs a libvirt create (= start)
|
||||
def start
|
||||
requires :raw
|
||||
|
||||
@raw.create
|
||||
connection.pool_action uuid, :create
|
||||
end
|
||||
|
||||
# Stop the pool = make it non-active
|
||||
# Performs a libvirt destroy (= stop)
|
||||
def stop
|
||||
requires :raw
|
||||
|
||||
@raw.destroy
|
||||
connection.pool_action uuid, :destroy
|
||||
end
|
||||
|
||||
# Shuts down the pool
|
||||
def shutdown
|
||||
requires :raw
|
||||
|
||||
@raw.destroy
|
||||
true
|
||||
stop
|
||||
end
|
||||
|
||||
# Build this storage pool
|
||||
def build
|
||||
requires :raw
|
||||
|
||||
@raw.build unless @raw.nil?
|
||||
connection.pool_action uuid, :build
|
||||
end
|
||||
|
||||
# Destroys the storage pool
|
||||
def destroy( destroy_options={})
|
||||
requires :raw
|
||||
|
||||
def destroy
|
||||
# Shutdown pool if active
|
||||
@raw.destroy if @raw.active?
|
||||
|
||||
# Delete corresponding data in this pool
|
||||
# @raw.delete
|
||||
|
||||
connection.pool_action uuid, :destroy if active?
|
||||
# If this is a persistent domain we need to undefine it
|
||||
@raw.undefine if @raw.persistent?
|
||||
|
||||
end
|
||||
|
||||
# Set autostart value of the storage pool (true|false)
|
||||
def auto_start=(flag)
|
||||
requires :raw
|
||||
|
||||
@raw.auto_start(flag)
|
||||
connection.pool_action uuid, :undefine if persistent?
|
||||
end
|
||||
|
||||
# Is the pool active or not?
|
||||
def active?
|
||||
requires :raw
|
||||
|
||||
@raw.active?
|
||||
active
|
||||
end
|
||||
|
||||
# Will the pool autostart or not?
|
||||
def auto_start?
|
||||
requires :raw
|
||||
|
||||
@raw.autostart?
|
||||
autostart
|
||||
end
|
||||
|
||||
# Is the pool persistent or not?
|
||||
def persistent?
|
||||
requires :raw
|
||||
@raw.persistent?
|
||||
end
|
||||
|
||||
# Returns the xml description of the current pool
|
||||
def xml_desc
|
||||
requires :raw
|
||||
|
||||
@raw.xml_desc unless @raw.nil?
|
||||
end
|
||||
|
||||
|
||||
# Retrieves the name of the pool
|
||||
def name
|
||||
requires :raw
|
||||
@raw.name
|
||||
end
|
||||
|
||||
# Retrieves the uuid of the pool
|
||||
def uuid
|
||||
requires :raw
|
||||
@raw.uuid
|
||||
end
|
||||
|
||||
# Retrieves the allocated disk space of the pool
|
||||
def allocation
|
||||
requires :raw
|
||||
@raw.info.allocation
|
||||
end
|
||||
|
||||
# Retrieves the capacity of disk space of the pool
|
||||
def capacity
|
||||
requires :raw
|
||||
@raw.info.capacity
|
||||
end
|
||||
|
||||
# Retrieves the number of volumes available in this pool
|
||||
def num_of_volumes
|
||||
requires :raw
|
||||
@raw.num_of_volumes
|
||||
end
|
||||
|
||||
def state
|
||||
requires :raw
|
||||
|
||||
#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)
|
||||
states=[:inactive, :building,:running,:degrated,:inaccessible]
|
||||
|
||||
return states[@raw.info.state]
|
||||
|
||||
persistent
|
||||
end
|
||||
|
||||
# Retrieves the volumes of this pool
|
||||
def volumes
|
||||
|
||||
volumes=Array.new
|
||||
@raw.list_volumes.each do |volume|
|
||||
fog_volume=connection.volumes.all(:name => volume).first
|
||||
volumes << fog_volume
|
||||
end
|
||||
return volumes
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def raw
|
||||
@raw
|
||||
end
|
||||
|
||||
def raw=(new_raw)
|
||||
@raw = new_raw
|
||||
|
||||
raw_attributes = {
|
||||
:uuid => new_raw.uuid,
|
||||
|
||||
}
|
||||
|
||||
merge_attributes(raw_attributes)
|
||||
connection.list_pool_volumes uuid
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,52 +9,16 @@ module Fog
|
|||
|
||||
model Fog::Compute::Libvirt::Pool
|
||||
|
||||
def all(filter=nil)
|
||||
data=[]
|
||||
if filter.nil?
|
||||
connection.raw.list_storage_pools.each do |poolname|
|
||||
pool=connection.raw.lookup_storage_pool_by_name(poolname)
|
||||
data << { :raw => pool }
|
||||
end
|
||||
connection.raw.list_defined_storage_pools.each do |poolname|
|
||||
data << {
|
||||
:raw => connection.raw.lookup_storage_pool_by_name(poolname)
|
||||
}
|
||||
end
|
||||
else
|
||||
pool=nil
|
||||
begin
|
||||
pool=get_by_uuid(filter[:uuid]) if filter.has_key?(:uuid)
|
||||
pool=get_by_name(filter[:name]) if filter.has_key?(:name)
|
||||
rescue ::Libvirt::RetrieveError
|
||||
return nil
|
||||
end
|
||||
data << { :raw => pool}
|
||||
end
|
||||
|
||||
load(data)
|
||||
def all(filter = {})
|
||||
load(connection.list_pools(filter))
|
||||
end
|
||||
|
||||
def get(uuid)
|
||||
self.all(:uuid => uuid).first
|
||||
end
|
||||
|
||||
#private # Making these private, screws up realod
|
||||
# Retrieve the pool by uuid
|
||||
def get_by_uuid(uuid)
|
||||
pool=connection.raw.lookup_storage_pool_by_uuid(uuid)
|
||||
return pool
|
||||
end
|
||||
end
|
||||
|
||||
# Retrieve the pool by name
|
||||
def get_by_name(name)
|
||||
pool=connection.raw.lookup_storage_pool_by_name(name)
|
||||
return pool
|
||||
# new(:raw => pool)
|
||||
end
|
||||
|
||||
end #class
|
||||
|
||||
end #Class
|
||||
end #module
|
||||
end #module
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,59 +1,54 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/libvirt/models/compute/util'
|
||||
require 'fog/compute/models/server'
|
||||
require 'fog/libvirt/models/compute/util/util'
|
||||
require 'net/ssh/proxy/command'
|
||||
require 'rexml/document'
|
||||
require 'erb'
|
||||
require 'securerandom'
|
||||
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
|
||||
class Server < Fog::Model
|
||||
class Server < Fog::Compute::Server
|
||||
|
||||
include Fog::Compute::LibvirtUtil
|
||||
attr_reader :xml
|
||||
|
||||
identity :id, :aliases => 'uuid'
|
||||
attribute :xml
|
||||
|
||||
attribute :cpus
|
||||
attribute :cputime
|
||||
attribute :os_type
|
||||
attribute :memory_size
|
||||
attribute :max_memory_size
|
||||
|
||||
attribute :name
|
||||
attribute :arch
|
||||
attribute :persistent
|
||||
attribute :domain_type
|
||||
attribute :uuid
|
||||
attribute :autostart
|
||||
attribute :vnc_port
|
||||
attribute :nics
|
||||
attribute :volumes
|
||||
attribute :active
|
||||
|
||||
attribute :state
|
||||
|
||||
# The following attributes are only needed when creating a new vm
|
||||
#TODO: Add depreciation warning
|
||||
attr_accessor :iso_dir, :iso_file
|
||||
attr_accessor :network_interface_type ,:network_nat_network, :network_bridge_name
|
||||
attr_accessor :volume_format_type, :volume_allocation,:volume_capacity, :volume_name, :volume_pool_name, :volume_template_name, :volume_path
|
||||
|
||||
attr_accessor :password
|
||||
attr_writer :private_key, :private_key_path, :public_key, :public_key_path, :username
|
||||
|
||||
# Can be created by passing in :xml => "<xml to create domain/server>"
|
||||
# or by providing :template_options => {
|
||||
# :name => "", :cpus => 1, :memory_size => 256 , :volume_template
|
||||
# :}
|
||||
#
|
||||
# @returns server/domain created
|
||||
# }
|
||||
|
||||
def initialize(attributes={} )
|
||||
|
||||
# setup all attributes.
|
||||
defaults.merge(attributes).each do |k,v|
|
||||
eval("self.#{k}= v") if self.respond_to?("#{k}=")
|
||||
end
|
||||
|
||||
super
|
||||
@xml = attributes.delete(:xml)
|
||||
super defaults.merge(attributes)
|
||||
initialize_nics
|
||||
initialize_volumes
|
||||
end
|
||||
|
||||
def new?
|
||||
|
@ -61,97 +56,13 @@ module Fog
|
|||
end
|
||||
|
||||
def save
|
||||
|
||||
raise Fog::Errors::Error.new('Resaving an existing server may create a duplicate') unless new?
|
||||
|
||||
validate_template_options
|
||||
|
||||
xml ||= xml_from_template
|
||||
|
||||
create_or_clone_volume
|
||||
|
||||
xml = xml_from_template
|
||||
|
||||
# We either now have xml provided by the user or generated by the template
|
||||
begin
|
||||
if xml
|
||||
self.raw = persistent ? connection.raw.define_domain_xml(xml) : connection.raw.create_domain_xml(xml)
|
||||
end
|
||||
rescue
|
||||
raise Fog::Errors::Error.new("Error saving the server: #{$!}")
|
||||
end
|
||||
end
|
||||
|
||||
#TODO move all of this to the volume class
|
||||
def create_or_clone_volume
|
||||
|
||||
volume_options = Hash.new
|
||||
|
||||
volume_options[:name] = volume_name || default_volume_name
|
||||
|
||||
# Check if a disk template was specified
|
||||
unless self.volume_template_name.nil?
|
||||
|
||||
template_volumes = connection.volumes.all(:name => self.volume_template_name)
|
||||
|
||||
raise Fog::Errors::Error.new("Template #{self.volume_template_name} not found") unless template_volumes.empty?
|
||||
|
||||
orig_volume = template_volumes.first
|
||||
volume = orig_volume.clone("#{volume_options[:name]}")
|
||||
|
||||
# if we cloned it, it has the original volume type.
|
||||
self.volume_format_type = orig_volume.format_type
|
||||
# This gets passed to the domain to know the path of the disk
|
||||
self.volume_path = volume.path
|
||||
|
||||
else
|
||||
# If no template volume was given, let's create our own volume
|
||||
|
||||
volume_options[:format_type] = self.volume_format_type if volume_format_type
|
||||
volume_options[:capacity] = self.volume_capacity if volume_capacity
|
||||
volume_options[:allocation] = self.volume_allocation if volume_allocation
|
||||
|
||||
begin
|
||||
volume = connection.volumes.create(volume_options)
|
||||
self.volume_path = volume.path
|
||||
self.volume_format_type ||= volume.format_type
|
||||
rescue
|
||||
raise Fog::Errors::Error.new("Error creating the volume : #{$!}")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def validate_template_options
|
||||
unless self.network_interface_type.nil?
|
||||
raise Fog::Errors::Error.new("#{self.network_interface_type} is not a supported interface type") unless ["nat", "bridge"].include?(self.network_interface_type)
|
||||
end
|
||||
end
|
||||
|
||||
def xml_from_template
|
||||
|
||||
template_options={
|
||||
:cpus => cpus,
|
||||
:memory_size => memory_size,
|
||||
:domain_type => domain_type,
|
||||
:name => name,
|
||||
:iso_file => iso_file,
|
||||
:iso_dir => iso_dir,
|
||||
:os_type => os_type,
|
||||
:arch => arch,
|
||||
:volume_path => volume_path,
|
||||
:volume_format_type => volume_format_type,
|
||||
:network_interface_type => network_interface_type,
|
||||
:network_nat_network => network_nat_network,
|
||||
:network_bridge_name => network_bridge_name
|
||||
}
|
||||
vars = ErbBinding.new(template_options)
|
||||
template_path = File.join(File.dirname(__FILE__),"templates","server.xml.erb")
|
||||
template = File.open(template_path).readlines.join
|
||||
erb = ERB.new(template)
|
||||
vars_binding = vars.send(:get_binding)
|
||||
|
||||
erb.result(vars_binding)
|
||||
raise Fog::Errors::Error.new('Saving an existing server may create a duplicate') unless new?
|
||||
create_or_clone_volume unless xml or @volumes
|
||||
@xml ||= to_xml
|
||||
self.id = (persistent ? connection.define_domain(xml) : connection.create_domain(xml)).uuid
|
||||
reload
|
||||
rescue => e
|
||||
raise Fog::Errors::Error.new("Error saving the server: #{e}")
|
||||
end
|
||||
|
||||
def username
|
||||
|
@ -159,74 +70,43 @@ module Fog
|
|||
end
|
||||
|
||||
def start
|
||||
requires :raw
|
||||
|
||||
unless @raw.active?
|
||||
begin
|
||||
@raw.create
|
||||
true
|
||||
rescue
|
||||
false
|
||||
end
|
||||
end
|
||||
return if active?
|
||||
connection.vm_action(uuid, :create)
|
||||
reload
|
||||
end
|
||||
|
||||
# In libvirt a destroy means a hard power-off of the domain
|
||||
# In fog a destroy means the remove of a machine
|
||||
def destroy(options={ :destroy_volumes => false})
|
||||
requires :raw
|
||||
poweroff unless stopped?
|
||||
#TODO: add handling of failure
|
||||
@raw.undefine
|
||||
def mac
|
||||
nics.first.mac if nics && nics.first
|
||||
end
|
||||
|
||||
if options[:destroy_volumes]
|
||||
# volumes.all filters do not handle nil keys well
|
||||
connection.volumes.all(:path => disk_path).each { |vol| vol.destroy}
|
||||
end
|
||||
def disk_path
|
||||
volumes.first.path if volumes and volumes.first
|
||||
end
|
||||
|
||||
def destroy(options={ :destroy_volumes => false})
|
||||
poweroff unless stopped?
|
||||
connection.vm_action(uuid, :undefine)
|
||||
volumes.each { |vol| vol.destroy } if options[:destroy_volumes]
|
||||
end
|
||||
|
||||
def reboot
|
||||
requires :raw
|
||||
@raw.reboot
|
||||
connection.vm_action :reboot
|
||||
end
|
||||
|
||||
# Alias for poweroff
|
||||
def halt
|
||||
poweroff
|
||||
end
|
||||
|
||||
# In libvirt a destroy means a hard power-off of the domain
|
||||
# In fog a destroy means the remove of a machine
|
||||
def poweroff
|
||||
requires :raw
|
||||
@raw.destroy
|
||||
connection.vm_action(uuid, :destroy)
|
||||
end
|
||||
|
||||
def shutdown
|
||||
requires :raw
|
||||
@raw.shutdown
|
||||
connection.vm_action(uuid, :shutdown)
|
||||
end
|
||||
|
||||
def resume
|
||||
requires :raw
|
||||
@raw.resume
|
||||
connection.vm_action(uuid, :resume)
|
||||
end
|
||||
|
||||
def suspend
|
||||
requires :raw
|
||||
@raw.suspend
|
||||
end
|
||||
|
||||
def to_fog_state(raw_state)
|
||||
state=case raw_state
|
||||
when 0 then "nostate"
|
||||
when 1 then "running"
|
||||
when 2 then "blocked"
|
||||
when 3 then "paused"
|
||||
when 4 then "shutting-down"
|
||||
when 5 then "shutoff"
|
||||
when 6 then "crashed"
|
||||
end
|
||||
connection.vm_action(uuid, :suspend)
|
||||
end
|
||||
|
||||
def stopped?
|
||||
|
@ -237,109 +117,14 @@ module Fog
|
|||
state == "running"
|
||||
end
|
||||
|
||||
def stop
|
||||
requires :raw
|
||||
@raw.shutdown
|
||||
end
|
||||
#alias methods
|
||||
alias :halt :poweroff
|
||||
alias :stop :shutdown
|
||||
alias :active? :active
|
||||
|
||||
# This retrieves the ip address of the mac address
|
||||
# It returns an array of public and private ip addresses
|
||||
# Currently only one ip address is returned, but in the future this could be multiple
|
||||
# if the server has multiple network interface
|
||||
#
|
||||
#TODO: move this into the util class
|
||||
def addresses(options={})
|
||||
mac=self.mac
|
||||
|
||||
# Aug 24 17:34:41 juno arpwatch: new station 10.247.4.137 52:54:00:88:5a:0a eth0.4
|
||||
# Aug 24 17:37:19 juno arpwatch: changed ethernet address 10.247.4.137 52:54:00:27:33:00 (52:54:00:88:5a:0a) eth0.4
|
||||
# Check if another ip_command string was provided
|
||||
ip_command_global=@connection.ip_command.nil? ? 'grep $mac /var/log/arpwatch.log|sed -e "s/new station//"|sed -e "s/changed ethernet address//g" |sed -e "s/reused old ethernet //" |tail -1 |cut -d ":" -f 4-| cut -d " " -f 3' : @connection.ip_command
|
||||
ip_command_local=options[:ip_command].nil? ? ip_command_global : options[:ip_command]
|
||||
|
||||
ip_command="mac=#{mac}; server_name=#{name}; "+ip_command_local
|
||||
|
||||
ip_address=nil
|
||||
|
||||
if @connection.uri.ssh_enabled?
|
||||
|
||||
# Retrieve the parts we need from the connection to setup our ssh options
|
||||
user=connection.uri.user #could be nil
|
||||
host=connection.uri.host
|
||||
keyfile=connection.uri.keyfile
|
||||
port=connection.uri.port
|
||||
|
||||
# Setup the options
|
||||
ssh_options={}
|
||||
ssh_options[:keys]=[ keyfile ] unless keyfile.nil?
|
||||
ssh_options[:port]=port unless keyfile.nil?
|
||||
ssh_options[:paranoid]=true if connection.uri.no_verify?
|
||||
|
||||
# TODO: we need to take the time into account, when IP's are re-allocated, we might be executing
|
||||
# On the wrong host
|
||||
|
||||
begin
|
||||
result=Fog::SSH.new(host, user, ssh_options).run(ip_command)
|
||||
rescue Errno::ECONNREFUSED
|
||||
raise Fog::Errors::Error.new("Connection was refused to host #{host} to retrieve the ip_address for #{mac}")
|
||||
rescue Net::SSH::AuthenticationFailed
|
||||
raise Fog::Errors::Error.new("Error authenticating over ssh to host #{host} and user #{user}")
|
||||
end
|
||||
|
||||
#TODO: We currently just retrieve the ip address through the ip_command
|
||||
#TODO: We need to check if that ip_address is still valid for that mac-address
|
||||
|
||||
# Check for a clean exit code
|
||||
if result.first.status == 0
|
||||
ip_address=result.first.stdout.strip
|
||||
else
|
||||
# We got a failure executing the command
|
||||
raise Fog::Errors::Error.new("The command #{ip_command} failed to execute with a clean exit code")
|
||||
end
|
||||
|
||||
else
|
||||
# It's not ssh enabled, so we assume it is
|
||||
if @connection.uri.transport=="tls"
|
||||
raise Fog::Errors::Error.new("TlS remote transport is not currently supported, only ssh")
|
||||
end
|
||||
|
||||
# Execute the ip_command locally
|
||||
# Initialize empty ip_address string
|
||||
ip_address=""
|
||||
|
||||
IO.popen("#{ip_command}") do |p|
|
||||
p.each_line do |l|
|
||||
ip_address+=l
|
||||
end
|
||||
status=Process.waitpid2(p.pid)[1].exitstatus
|
||||
if status!=0
|
||||
raise Fog::Errors::Error.new("The command #{ip_command} failed to execute with a clean exit code")
|
||||
end
|
||||
end
|
||||
|
||||
#Strip any new lines from the string
|
||||
ip_address=ip_address.chomp
|
||||
end
|
||||
|
||||
|
||||
# The Ip-address command has been run either local or remote now
|
||||
|
||||
if ip_address==""
|
||||
#The grep didn't find an ip address result"
|
||||
ip_address=nil
|
||||
else
|
||||
# To be sure that the command didn't return another random string
|
||||
# We check if the result is an actual ip-address
|
||||
# otherwise we return nil
|
||||
unless ip_address=~/^(\d{1,3}\.){3}\d{1,3}$/
|
||||
raise Fog::Errors::Error.new(
|
||||
"The result of #{ip_command} does not have valid ip-address format\n"+
|
||||
"Result was: #{ip_address}\n"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return { :public => [ip_address], :private => [ip_address]}
|
||||
def volumes
|
||||
# lazy loading of volumes
|
||||
@volumes ||= (@volumes_path || []).map{|path| connection.volumes.all(:path => path).first }
|
||||
end
|
||||
|
||||
def private_ip_address
|
||||
|
@ -350,15 +135,6 @@ module Fog
|
|||
ip_address(:public)
|
||||
end
|
||||
|
||||
def ip_address(key)
|
||||
ips=addresses[key]
|
||||
unless ips.nil?
|
||||
return ips.first
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def private_key_path
|
||||
@private_key_path ||= Fog.credentials[:private_key_path]
|
||||
@private_key_path &&= File.expand_path(@private_key_path)
|
||||
|
@ -390,19 +166,11 @@ module Fog
|
|||
|
||||
end
|
||||
|
||||
|
||||
def ssh_proxy
|
||||
proxy=nil
|
||||
if @connection.uri.ssh_enabled?
|
||||
relay=connection.uri.host
|
||||
user_string=""
|
||||
user_string="-l #{connection.uri.user}" unless connection.uri.user.nil?
|
||||
proxy = Net::SSH::Proxy::Command.new("ssh #{user_string} "+relay+" nc %h %p")
|
||||
return proxy
|
||||
else
|
||||
return nil
|
||||
# This is a direct connection, so we don't need a proxy to be set
|
||||
end
|
||||
# if this is a direct connection, we don't need a proxy to be set.
|
||||
return nil unless @connection.uri.ssh_enabled?
|
||||
user_string= connection.uri.user ? "-l #{connection.uri.user}" : ""
|
||||
Net::SSH::Proxy::Command.new("ssh #{user_string} #{connection.uri.host} nc %h %p")
|
||||
end
|
||||
|
||||
# Transfers a file
|
||||
|
@ -417,7 +185,6 @@ module Fog
|
|||
Fog::SCP.new(public_ip_address, username, scp_options).upload(local_path, remote_path, upload_options)
|
||||
end
|
||||
|
||||
|
||||
# Sets up a new key
|
||||
def setup(credentials = {})
|
||||
requires :public_key, :public_ip_address, :username
|
||||
|
@ -452,46 +219,145 @@ module Fog
|
|||
Fog::SSH.new(public_ip_address, username, credentials).run(commands)
|
||||
end
|
||||
|
||||
# Retrieves the mac address from parsing the XML of the domain
|
||||
def mac
|
||||
mac = document("domain/devices/interface/mac", "address")
|
||||
end
|
||||
|
||||
def vnc_port
|
||||
port = document("domain/devices/graphics[@type='vnc']", "port")
|
||||
end
|
||||
|
||||
def disk_path
|
||||
document("domain/devices/disk/source", "file")
|
||||
rescue
|
||||
[]
|
||||
end
|
||||
|
||||
private
|
||||
attr_reader :raw
|
||||
attr_accessor :volumes_path
|
||||
|
||||
def raw=(new_raw)
|
||||
@raw = new_raw
|
||||
# This retrieves the ip address of the mac address
|
||||
# It returns an array of public and private ip addresses
|
||||
# Currently only one ip address is returned, but in the future this could be multiple
|
||||
# if the server has multiple network interface
|
||||
def addresses(connection, options={})
|
||||
mac=self.mac
|
||||
|
||||
raw_attributes = {
|
||||
:id => new_raw.uuid,
|
||||
:uuid => new_raw.uuid,
|
||||
:name => new_raw.name,
|
||||
:max_memory_size => new_raw.info.max_mem,
|
||||
:cputime => new_raw.info.cpu_time,
|
||||
:memory_size => new_raw.info.memory,
|
||||
:vcpus => new_raw.info.nr_virt_cpu,
|
||||
:autostart => new_raw.autostart?,
|
||||
:os_type => new_raw.os_type,
|
||||
:xml => new_raw.xml_desc,
|
||||
:state => self.to_fog_state(new_raw.info.state)
|
||||
}
|
||||
# Aug 24 17:34:41 juno arpwatch: new station 10.247.4.137 52:54:00:88:5a:0a eth0.4
|
||||
# Aug 24 17:37:19 juno arpwatch: changed ethernet address 10.247.4.137 52:54:00:27:33:00 (52:54:00:88:5a:0a) eth0.4
|
||||
# Check if another ip_command string was provided
|
||||
ip_command_global=connection.ip_command.nil? ? 'grep $mac /var/log/arpwatch.log|sed -e "s/new station//"|sed -e "s/changed ethernet address//g" |sed -e "s/reused old ethernet //" |tail -1 |cut -d ":" -f 4-| cut -d " " -f 3' : connection.ip_command
|
||||
ip_command_local=options[:ip_command].nil? ? ip_command_global : options[:ip_command]
|
||||
|
||||
merge_attributes(raw_attributes)
|
||||
ip_command="mac=#{mac}; server_name=#{name}; "+ip_command_local
|
||||
|
||||
ip_address=nil
|
||||
|
||||
if connection.uri.ssh_enabled?
|
||||
|
||||
# Retrieve the parts we need from the connection to setup our ssh options
|
||||
user=connection.uri.user #could be nil
|
||||
host=connection.uri.host
|
||||
keyfile=connection.uri.keyfile
|
||||
port=connection.uri.port
|
||||
|
||||
# Setup the options
|
||||
ssh_options={}
|
||||
ssh_options[:keys]=[ keyfile ] unless keyfile.nil?
|
||||
ssh_options[:port]=port unless keyfile.nil?
|
||||
ssh_options[:paranoid]=true if connection.uri.no_verify?
|
||||
|
||||
|
||||
begin
|
||||
result=Fog::SSH.new(host, user, ssh_options).run(ip_command)
|
||||
rescue Errno::ECONNREFUSED
|
||||
raise Fog::Errors::Error.new("Connection was refused to host #{host} to retrieve the ip_address for #{mac}")
|
||||
rescue Net::SSH::AuthenticationFailed
|
||||
raise Fog::Errors::Error.new("Error authenticating over ssh to host #{host} and user #{user}")
|
||||
end
|
||||
|
||||
|
||||
# Check for a clean exit code
|
||||
if result.first.status == 0
|
||||
ip_address=result.first.stdout.strip
|
||||
else
|
||||
# We got a failure executing the command
|
||||
raise Fog::Errors::Error.new("The command #{ip_command} failed to execute with a clean exit code")
|
||||
end
|
||||
|
||||
else
|
||||
# It's not ssh enabled, so we assume it is
|
||||
if connection.uri.transport=="tls"
|
||||
raise Fog::Errors::Error.new("TlS remote transport is not currently supported, only ssh")
|
||||
end
|
||||
|
||||
# Execute the ip_command locally
|
||||
# Initialize empty ip_address string
|
||||
ip_address=""
|
||||
|
||||
IO.popen("#{ip_command}") do |p|
|
||||
p.each_line do |l|
|
||||
ip_address+=l
|
||||
end
|
||||
status=Process.waitpid2(p.pid)[1].exitstatus
|
||||
if status!=0
|
||||
raise Fog::Errors::Error.new("The command #{ip_command} failed to execute with a clean exit code")
|
||||
end
|
||||
end
|
||||
|
||||
#Strip any new lines from the string
|
||||
ip_address=ip_address.chomp
|
||||
end
|
||||
|
||||
|
||||
# The Ip-address command has been run either local or remote now
|
||||
|
||||
if ip_address==""
|
||||
#The grep didn't find an ip address result"
|
||||
ip_address=nil
|
||||
else
|
||||
# To be sure that the command didn't return another random string
|
||||
# We check if the result is an actual ip-address
|
||||
# otherwise we return nil
|
||||
unless ip_address=~/^(\d{1,3}\.){3}\d{1,3}$/
|
||||
raise Fog::Errors::Error.new(
|
||||
"The result of #{ip_command} does not have valid ip-address format\n"+
|
||||
"Result was: #{ip_address}\n"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return { :public => [ip_address], :private => [ip_address]}
|
||||
end
|
||||
|
||||
def randomized_name
|
||||
"fog-#{SecureRandom.random_number*10E14.to_i.round}"
|
||||
def ip_address(key)
|
||||
addresses[key].nil? ? nil : addresses[key].first
|
||||
end
|
||||
|
||||
def initialize_nics
|
||||
if nics
|
||||
nics.map! { |nic| nic.is_a?(Hash) ? connection.nics.new(nic) : nic }
|
||||
else
|
||||
self.nics = [connection.nics.new({:type => network_interface_type, :bridge => network_bridge_name, :network => network_nat_network})]
|
||||
end
|
||||
end
|
||||
|
||||
def initialize_volumes
|
||||
if attributes[:volumes] && !attributes[:volumes].empty?
|
||||
@volumes = attributes[:volumes].map { |vol| vol.is_a?(Hash) ? connection.volumes.new(vol) : vol }
|
||||
end
|
||||
end
|
||||
|
||||
def create_or_clone_volume
|
||||
options = {:name => volume_name || default_volume_name}
|
||||
# Check if a disk template was specified
|
||||
if volume_template_name
|
||||
template_volume = connection.volumes.all(:name => volume_template_name).first
|
||||
raise Fog::Errors::Error.new("Template #{volume_template_name} not found") unless template_volume
|
||||
begin
|
||||
volume = template_volume.clone("#{options[:name]}")
|
||||
rescue => e
|
||||
raise Fog::Errors::Error.new("Error creating the volume : #{e}")
|
||||
end
|
||||
else
|
||||
# If no template volume was given, let's create our own volume
|
||||
options[:format_type] = volume_format_type if volume_format_type
|
||||
options[:capacity] = volume_capacity if volume_capacity
|
||||
options[:allocation] = volume_allocation if volume_allocation
|
||||
|
||||
begin
|
||||
volume = connection.volumes.create(options)
|
||||
rescue => e
|
||||
raise Fog::Errors::Error.new("Error creating the volume : #{e}")
|
||||
end
|
||||
end
|
||||
@volumes.nil? ? @volumes = [volume] : @volumes << volume
|
||||
end
|
||||
|
||||
def default_iso_dir
|
||||
|
@ -511,8 +377,8 @@ module Fog
|
|||
:os_type => "hvm",
|
||||
:arch => "x86_64",
|
||||
:domain_type => "kvm",
|
||||
:iso_dir => default_iso_dir ,
|
||||
:network_interface_type => "nat",
|
||||
:iso_dir => default_iso_dir,
|
||||
:network_interface_type => "network",
|
||||
:network_nat_network => "default",
|
||||
:network_bridge_name => "br0"
|
||||
}
|
||||
|
|
|
@ -9,71 +9,16 @@ module Fog
|
|||
|
||||
model Fog::Compute::Libvirt::Server
|
||||
|
||||
def all(filter=nil)
|
||||
data=[]
|
||||
filter={} if filter.nil?
|
||||
include_defined=filter.has_key?(:defined) ? filter[:defined] : true
|
||||
include_active=filter.has_key?(:active) ? filter[:active] : true
|
||||
|
||||
unless filter.has_key?(:name) || filter.has_key?(:uuid)
|
||||
if include_defined
|
||||
connection.raw.list_defined_domains.map do |domain|
|
||||
data << { :raw => connection.raw.lookup_domain_by_name(domain) }
|
||||
end
|
||||
end
|
||||
if include_active
|
||||
connection.raw.list_domains.each do |domain|
|
||||
data << { :raw => connection.raw.lookup_domain_by_id(domain) }
|
||||
end
|
||||
end
|
||||
else
|
||||
domain=nil
|
||||
begin
|
||||
domain=self.get_by_name(filter[:name]) if filter.has_key?(:name)
|
||||
domain=self.get_by_uuid(filter[:uuid]) if filter.has_key?(:uuid)
|
||||
|
||||
rescue ::Libvirt::RetrieveError
|
||||
return nil
|
||||
end
|
||||
unless domain.nil?
|
||||
data << { :raw => domain }
|
||||
end
|
||||
end
|
||||
|
||||
load(data)
|
||||
def all(filter={})
|
||||
load(connection.list_domains(filter))
|
||||
end
|
||||
|
||||
def get(uuid)
|
||||
vm = all(:uuid => uuid)
|
||||
vm.first if vm
|
||||
data = connection.list_domains(:uuid => uuid)
|
||||
new data.first if 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
|
||||
|
||||
# private #making these internals private screws up reload
|
||||
|
||||
# Retrieve the server by uuid
|
||||
def get_by_uuid(uuid)
|
||||
server=connection.raw.lookup_domain_by_uuid(uuid)
|
||||
return server
|
||||
# new(:raw => machine)
|
||||
end
|
||||
|
||||
# Retrieve the server by name
|
||||
def get_by_name(name)
|
||||
server=connection.raw.lookup_domain_by_name(name)
|
||||
return server
|
||||
# new(:raw => machine)
|
||||
end
|
||||
|
||||
end #class
|
||||
end #Class
|
||||
end #module
|
||||
end #Module
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
<os>
|
||||
<type arch='<%= arch %>'><%= os_type %></type>
|
||||
<boot dev='hd'/>
|
||||
<% if !iso_file.nil? %>
|
||||
|
||||
<% if iso_file -%>
|
||||
<boot dev='cdrom'/>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
|
@ -17,12 +16,14 @@
|
|||
</features>
|
||||
<clock offset='utc'/>
|
||||
<devices>
|
||||
<% volumes.each do |vol| -%>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='<%= volume_format_type %>'/>
|
||||
<source file='<%= "#{volume_path}" %>'/>
|
||||
<driver name='qemu' type='<%= vol.format_type %>'/>
|
||||
<source file='<%= vol.path %>'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
</disk>
|
||||
<% if !iso_file.nil? %>
|
||||
<% end -%>
|
||||
<% if iso_file -%>
|
||||
<disk type='file' device='cdrom'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file='<%= "#{iso_dir}/#{iso_file}" %>'/>
|
||||
|
@ -30,18 +31,13 @@
|
|||
<readonly/>
|
||||
<address type='drive' controller='0' bus='1' unit='0'/>
|
||||
</disk>
|
||||
<% end %>
|
||||
<% if network_interface_type=="bridge" %>
|
||||
<interface type="bridge">
|
||||
<source bridge='<%= network_bridge_name %>'/>
|
||||
<model type='virtio'/>
|
||||
<% end %>
|
||||
<% if network_interface_type=="nat" %>
|
||||
<interface type='network'>
|
||||
<source network='<%= network_nat_network %>'/>
|
||||
<model type='virtio'/>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
<% nics.each do |nic| -%>
|
||||
<interface type='<%= nic.type %>'>
|
||||
<source <%= nic.type == 'bridge' ? "bridge='#{nic.bridge}'" : "network='#{nic.network}'" %> />
|
||||
<model type='<%= nic.model %>'/>
|
||||
</interface>
|
||||
<% end -%>
|
||||
<serial type='pty'>
|
||||
<target port='0'/>
|
||||
</serial>
|
||||
|
@ -49,7 +45,7 @@
|
|||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<graphics type='vnc' port='-1' autoport='yes' keymap='en-us'/>
|
||||
<graphics type='vnc' port='-1' autoport='yes'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='9216' heads='1'/>
|
||||
</video>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<volume>
|
||||
<name><%= name %></name>
|
||||
<allocation unit="<%= allocation_unit %>"><%= allocation_size %>"></allocation>
|
||||
<capacity unit="<%= capacity_unit %>"><%= capacity_size %>"></capacity>
|
||||
<allocation unit="<%= split_size_unit(allocation)[1] %>"><%= split_size_unit(allocation)[0] %></allocation>
|
||||
<capacity unit="<%= split_size_unit(capacity)[1] %>"><%= split_size_unit(capacity)[0] %></capacity>
|
||||
<target>
|
||||
<format type="<%= format_type %>"/>
|
||||
<permissions>
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
require "rexml/document"
|
||||
require 'erb'
|
||||
require 'ostruct'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
module LibvirtUtil
|
||||
|
||||
# finds a value from xml
|
||||
def document path, attribute=nil
|
||||
return nil if new?
|
||||
xml = REXML::Document.new(self.xml)
|
||||
attribute.nil? ? xml.elements[path].text : xml.elements[path].attributes[attribute]
|
||||
end
|
||||
|
||||
class ErbBinding < OpenStruct
|
||||
def get_binding
|
||||
return binding()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,6 @@
|
|||
require 'uri'
|
||||
require 'cgi'
|
||||
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
module LibvirtUtil
|
33
lib/fog/libvirt/models/compute/util/util.rb
Normal file
33
lib/fog/libvirt/models/compute/util/util.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require 'nokogiri'
|
||||
require 'erb'
|
||||
require 'ostruct'
|
||||
require 'securerandom'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
module LibvirtUtil
|
||||
|
||||
def xml_element(xml, path, attribute=nil)
|
||||
xml = Nokogiri::XML(xml)
|
||||
attribute.nil? ? (xml/path).first.text : (xml/path).first[attribute.to_sym]
|
||||
end
|
||||
|
||||
def xml_elements(xml, path, attribute=nil)
|
||||
xml = Nokogiri::XML(xml)
|
||||
attribute.nil? ? (xml/path).map : (xml/path).map{|element| element[attribute.to_sym]}
|
||||
end
|
||||
|
||||
def to_xml template_name = nil
|
||||
# figure out our ERB template filename
|
||||
erb = template_name || self.class.to_s.split("::").last.downcase
|
||||
path = File.join(File.dirname(__FILE__), "..", "templates", "#{erb}.xml.erb")
|
||||
template = File.read(path)
|
||||
ERB.new(template, nil, '-').result(binding)
|
||||
end
|
||||
|
||||
def randomized_name
|
||||
"fog-#{(SecureRandom.random_number*10E14).to_i.round}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +1,5 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/libvirt/models/compute/util'
|
||||
require 'rexml/document'
|
||||
require 'erb'
|
||||
require 'securerandom'
|
||||
require 'fog/libvirt/models/compute/util/util'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
|
@ -10,17 +7,15 @@ module Fog
|
|||
|
||||
class Volume < Fog::Model
|
||||
|
||||
attr_reader :xml
|
||||
include Fog::Compute::LibvirtUtil
|
||||
|
||||
identity :id , :aliases => 'key'
|
||||
identity :id, :aliases => 'key'
|
||||
|
||||
attribute :pool_name
|
||||
|
||||
attribute :xml
|
||||
|
||||
attribute :key
|
||||
attribute :path
|
||||
attribute :name
|
||||
attribute :path
|
||||
attribute :capacity
|
||||
attribute :allocation
|
||||
attribute :format_type
|
||||
|
@ -28,146 +23,83 @@ module Fog
|
|||
# Can be created by passing in :xml => "<xml to create volume>"
|
||||
# A volume always belongs to a pool, :pool_name => "<name of pool>"
|
||||
#
|
||||
# @returns volume created
|
||||
def initialize(attributes={} )
|
||||
self.xml ||= nil unless attributes[:xml]
|
||||
self.key = nil
|
||||
self.format_type ||= "raw" unless attributes[:format_type]
|
||||
extension = self.format_type=="raw" ? "img" : self.format_type
|
||||
self.name ||= "fog-#{SecureRandom.random_number*10E14.to_i.round}.#{extension}" unless attributes[:name]
|
||||
self.capacity ||= "10G" unless attributes[:capacity]
|
||||
self.allocation ||= "1G" unless attributes[:allocation]
|
||||
super
|
||||
def initialize(attributes={ })
|
||||
@xml = attributes.delete(:xml)
|
||||
super(defaults.merge(attributes))
|
||||
|
||||
#We need a connection to calculate the poolname
|
||||
#This is why we do this after super
|
||||
self.pool_name ||= default_pool_name unless attributes[:pool_name]
|
||||
end
|
||||
|
||||
# Try to guess the default/first pool of no pool_name was specificed
|
||||
def default_pool_name
|
||||
default_name="default"
|
||||
default_pool=@connection.pools.all(:name => default_name)
|
||||
|
||||
if default_pool.nil?
|
||||
first_pool=@connection.pools.first
|
||||
if first_pool.nil?
|
||||
raise Fog::Errors::Error.new('We could not find a pool called "default" and there was no other pool defined')
|
||||
else
|
||||
default_name=first_pool.name
|
||||
end
|
||||
end
|
||||
return default_name
|
||||
# We need a connection to calculate the pool_name
|
||||
# This is why we do this after super
|
||||
self.pool_name ||= default_pool_name
|
||||
end
|
||||
|
||||
# Takes a pool and either :xml or other settings
|
||||
def save
|
||||
requires :pool_name
|
||||
|
||||
raise Fog::Errors::Error.new('Resaving an existing volume may create a duplicate') if key
|
||||
|
||||
xml=xml_from_template if xml.nil?
|
||||
|
||||
begin
|
||||
volume=nil
|
||||
pool=connection.raw.lookup_storage_pool_by_name(pool_name)
|
||||
volume=pool.create_volume_xml(xml)
|
||||
self.raw=volume
|
||||
true
|
||||
rescue
|
||||
raise Fog::Errors::Error.new("Error creating volume: #{$!}")
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def split_size_unit(text)
|
||||
matcher=text.match(/(\d+)(.+)/)
|
||||
size=matcher[1]
|
||||
unit=matcher[2]
|
||||
return size , unit
|
||||
end
|
||||
|
||||
# Create a valid xml for the volume based on the template
|
||||
def xml_from_template
|
||||
|
||||
allocation_size,allocation_unit=split_size_unit(self.allocation)
|
||||
capacity_size,capacity_unit=split_size_unit(self.capacity)
|
||||
|
||||
template_options={
|
||||
:name => self.name,
|
||||
:format_type => self.format_type,
|
||||
:allocation_size => allocation_size,
|
||||
:allocation_unit => allocation_unit,
|
||||
:capacity_size => capacity_size,
|
||||
:capacity_unit => capacity_unit
|
||||
}
|
||||
|
||||
# We only want specific variables for ERB
|
||||
vars = ErbBinding.new(template_options)
|
||||
template_path=File.join(File.dirname(__FILE__),"templates","volume.xml.erb")
|
||||
template=File.open(template_path).readlines.join
|
||||
erb = ERB.new(template)
|
||||
vars_binding = vars.send(:get_binding)
|
||||
result=erb.result(vars_binding)
|
||||
return result
|
||||
raise Fog::Errors::Error.new('Reserving an existing volume may create a duplicate') if key
|
||||
@xml ||= to_xml
|
||||
self.path = connection.create_volume(pool_name, xml).path
|
||||
end
|
||||
|
||||
# Destroy a volume
|
||||
def destroy
|
||||
requires :raw
|
||||
raw.delete
|
||||
true
|
||||
connection.volume_action key, :delete
|
||||
end
|
||||
|
||||
# Wipes a volume , zeroes disk
|
||||
def wipe
|
||||
requires :raw
|
||||
raw.wipe
|
||||
true
|
||||
connection.volume_action key, :wipe
|
||||
end
|
||||
|
||||
# Clones this volume to the name provided
|
||||
def clone(name)
|
||||
pool=@raw.pool
|
||||
xml = REXML::Document.new(self.xml)
|
||||
xml.root.elements['/volume/name'].text=name
|
||||
xml.root.elements['/volume/key'].text=name
|
||||
xml.delete_element('/volume/target/path')
|
||||
pool.create_volume_xml_from(xml.to_s,@raw)
|
||||
return connection.volumes.all(:name => name).first
|
||||
end
|
||||
new_volume = self.dup
|
||||
new_volume.key = nil
|
||||
new_volume.name = name
|
||||
new_volume.save
|
||||
|
||||
#def xml_desc
|
||||
#requires :raw
|
||||
#raw.xml_desc
|
||||
#end
|
||||
new_volume.reload
|
||||
end
|
||||
|
||||
private
|
||||
def raw
|
||||
@raw
|
||||
|
||||
def image_suffix
|
||||
retrun "img" if format_type == "raw"
|
||||
format_type
|
||||
end
|
||||
|
||||
def raw=(new_raw)
|
||||
@raw = new_raw
|
||||
def randominzed_name
|
||||
"#{super}.#{image_suffix}"
|
||||
end
|
||||
|
||||
xml = REXML::Document.new(new_raw.xml_desc)
|
||||
format_type=xml.root.elements['/volume/target/format'].attributes['type']
|
||||
# Try to guess the default/first pool of no pool_name was specified
|
||||
def default_pool_name
|
||||
name = "default"
|
||||
return name unless (connection.pools.all(:name => name)).empty?
|
||||
|
||||
raw_attributes = {
|
||||
:key => new_raw.key,
|
||||
:id => new_raw.key,
|
||||
:path => new_raw.path,
|
||||
:name => new_raw.name,
|
||||
:format_type => format_type,
|
||||
:allocation => new_raw.info.allocation,
|
||||
:capacity => new_raw.info.capacity,
|
||||
:xml => new_raw.xml_desc
|
||||
# we default to the first pool we find.
|
||||
first_pool = connection.pools.first
|
||||
|
||||
raise Fog::Errors::Error.new('No storage pools are defined') unless first_pool
|
||||
first_pool.name
|
||||
end
|
||||
|
||||
def defaults
|
||||
{
|
||||
:persistent => true,
|
||||
:format_type => "raw",
|
||||
:name => randomized_name,
|
||||
:capacity => "10G",
|
||||
:allocation => "1G",
|
||||
}
|
||||
|
||||
merge_attributes(raw_attributes)
|
||||
end
|
||||
|
||||
def split_size_unit(text)
|
||||
matcher=text.match(/(\d+)(.+)/)
|
||||
size = matcher[1]
|
||||
unit = matcher[2]
|
||||
[size, unit]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -9,77 +9,14 @@ module Fog
|
|||
|
||||
model Fog::Compute::Libvirt::Volume
|
||||
|
||||
def all(filter=nil)
|
||||
data=[]
|
||||
if filter.nil?
|
||||
connection.raw.list_storage_pools.each do |poolname|
|
||||
pool=connection.raw.lookup_storage_pool_by_name(poolname)
|
||||
pool.list_volumes.each do |volumename|
|
||||
data << { :raw => pool.lookup_volume_by_name(volumename) }
|
||||
end
|
||||
end
|
||||
else
|
||||
volume=nil
|
||||
begin
|
||||
volume=self.get_by_name(filter[:name]) if filter.has_key?(:name)
|
||||
volume=self.get_by_key(filter[:key]) if filter.has_key?(:key)
|
||||
volume=self.get_by_path(filter[:path]) if filter.has_key?(:path)
|
||||
return nil if volume.nil?
|
||||
|
||||
rescue ::Libvirt::RetrieveError
|
||||
return nil
|
||||
end
|
||||
data << { :raw => volume}
|
||||
end
|
||||
|
||||
load(data)
|
||||
def all(filter = {})
|
||||
load(connection.list_volumes(filter))
|
||||
end
|
||||
|
||||
def get(key)
|
||||
self.all(:key => key).first
|
||||
end
|
||||
|
||||
|
||||
# Retrieve the volume by name
|
||||
def get_by_name(name)
|
||||
connection.raw.list_storage_pools.each do |poolname|
|
||||
pool=connection.raw.lookup_storage_pool_by_name(poolname)
|
||||
volume=pool.lookup_volume_by_name(name)
|
||||
unless volume.nil?
|
||||
return volume
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
# Retrieve the volume by key
|
||||
def get_by_key(key)
|
||||
connection.raw.list_storage_pools.each do |poolname|
|
||||
pool=connection.raw.lookup_storage_pool_by_name(poolname)
|
||||
volume=pool.lookup_volume_by_key(key)
|
||||
unless volume.nil?
|
||||
return volume
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
# Retrieve the volume by key
|
||||
def get_by_path(path)
|
||||
connection.raw.list_storage_pools.each do |poolname|
|
||||
pool=connection.raw.lookup_storage_pool_by_name(poolname)
|
||||
volume=pool.lookup_volume_by_key(path)
|
||||
unless volume.nil?
|
||||
return volume
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
17
lib/fog/libvirt/requests/compute/create_domain.rb
Normal file
17
lib/fog/libvirt/requests/compute/create_domain.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def create_domain(xml)
|
||||
client.create_domain_xml(xml)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def create_domain(xml)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
lib/fog/libvirt/requests/compute/create_volume.rb
Normal file
17
lib/fog/libvirt/requests/compute/create_volume.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def create_volume(pool_name, xml)
|
||||
client.lookup_storage_pool_by_name(pool_name).create_vol_xml(xml)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def create_volume(xml)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
lib/fog/libvirt/requests/compute/define_domain.rb
Normal file
17
lib/fog/libvirt/requests/compute/define_domain.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def define_domain(xml)
|
||||
client.define_domain_xml(xml)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def define_domain(xml)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
lib/fog/libvirt/requests/compute/define_pool.rb
Normal file
17
lib/fog/libvirt/requests/compute/define_pool.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def define_pool(xml)
|
||||
client.define_storage_pool_xml(xml)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def define_pool(xml)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
lib/fog/libvirt/requests/compute/destroy_interface.rb
Normal file
18
lib/fog/libvirt/requests/compute/destroy_interface.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
#shutdown the interface
|
||||
def destroy_interface(uuid)
|
||||
client.lookup_interface_by_uuid(uuid).destroy
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def destroy_interface(uuid)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
lib/fog/libvirt/requests/compute/destroy_network.rb
Normal file
17
lib/fog/libvirt/requests/compute/destroy_network.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def destroy_network(uuid)
|
||||
client.lookup_network_by_uuid(uuid).destroy
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def destroy_network(uuid)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
38
lib/fog/libvirt/requests/compute/get_node_info.rb
Normal file
38
lib/fog/libvirt/requests/compute/get_node_info.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def get_node_info
|
||||
node_hash = Hash.new
|
||||
node_info = client.node_get_info
|
||||
[:model, :memory, :cpus, :mhz, :nodes, :sockets, :cores, :threads].each do |param|
|
||||
node_hash[param] = node_info.send(param) rescue nil
|
||||
end
|
||||
[:type, :version, :node_free_memory, :max_vcpus].each do |param|
|
||||
node_hash[param] = client.send(param) rescue nil
|
||||
end
|
||||
node_hash[:uri] = client.uri
|
||||
xml = client.sys_info
|
||||
[:uuid, :manufacturer, :product, :serial].each do |attr|
|
||||
node_hash[attr] = node_attr(attr, xml)
|
||||
end
|
||||
|
||||
[node_hash]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def node_attr attr, xml
|
||||
xml_element(xml, "sysinfo/system/entry[@name='#{attr}']").strip
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
def get_node_info
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
74
lib/fog/libvirt/requests/compute/list_domains.rb
Normal file
74
lib/fog/libvirt/requests/compute/list_domains.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def list_domains(filter = { })
|
||||
data=[]
|
||||
|
||||
if filter.has_key?(:uuid)
|
||||
data << client.lookup_domain_by_uuid(filter[:uuid])
|
||||
elsif filter.has_key?(:name)
|
||||
data << client.lookup_domain_by_name(filter[:name])
|
||||
else
|
||||
client.list_defined_domains.each { |name| data << client.lookup_domain_by_name(name) } unless filter[:defined] == false
|
||||
client.list_domains.each { |id| data << client.lookup_domain_by_id(id) } unless filter[:active] == false
|
||||
end
|
||||
data.compact.map { |d| domain_to_attributes d }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def vnc_port xml
|
||||
xml_element(xml, "domain/devices/graphics[@type='vnc']", "port")
|
||||
rescue => e
|
||||
# we might be using SPICE display, or no VNC display at all
|
||||
nil
|
||||
end
|
||||
|
||||
def domain_volumes xml
|
||||
xml_elements(xml, "domain/devices/disk/source", "file")
|
||||
end
|
||||
|
||||
def domain_interfaces xml
|
||||
ifs = xml_elements(xml, "domain/devices/interface")
|
||||
ifs.map { |i|
|
||||
nics.new({
|
||||
:type => i['type'],
|
||||
:mac => (i/'mac').first[:address],
|
||||
:network => ((i/'source').first[:network] rescue nil),
|
||||
:bridge => ((i/'source').first[:bridge] rescue nil),
|
||||
:model => ((i/'model').first[:type] rescue nil),
|
||||
}.reject{|k,v| v.nil?})
|
||||
}
|
||||
end
|
||||
|
||||
def domain_to_attributes(dom)
|
||||
states= %w(nostate running blocked paused shutting-down shutoff crashed)
|
||||
{
|
||||
:id => dom.uuid,
|
||||
:uuid => dom.uuid,
|
||||
:name => dom.name,
|
||||
:max_memory_size => dom.info.max_mem,
|
||||
:cputime => dom.info.cpu_time,
|
||||
:memory_size => dom.info.memory,
|
||||
:vcpus => dom.info.nr_virt_cpu,
|
||||
:autostart => dom.autostart?,
|
||||
:os_type => dom.os_type,
|
||||
:active => dom.active?,
|
||||
:vnc_port => vnc_port(dom.xml_desc),
|
||||
:nics => domain_interfaces(dom.xml_desc),
|
||||
:volumes_path => domain_volumes(dom.xml_desc),
|
||||
:state => states[dom.info.state]
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
def list_vms(filter = { })
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
47
lib/fog/libvirt/requests/compute/list_interfaces.rb
Normal file
47
lib/fog/libvirt/requests/compute/list_interfaces.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def list_interfaces(filter = { })
|
||||
data=[]
|
||||
if filter.keys.empty?
|
||||
(client.list_interfaces + client.list_defined_interfaces).each do |ifname|
|
||||
data << interface_to_attributes(client.lookup_interface_by_name(ifname))
|
||||
end
|
||||
else
|
||||
data = [interface_to_attributes(get_interface_by_filter(filter))]
|
||||
end
|
||||
data.compact
|
||||
end
|
||||
|
||||
private
|
||||
# Retrieve the interface by mac or by name
|
||||
def get_interface_by_filter(filter)
|
||||
case filter.keys.first
|
||||
when :mac
|
||||
client.lookup_interface_by_mac(filter[:mac])
|
||||
when :name
|
||||
client.lookup_interface_by_name(filter[:name])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def interface_to_attributes(net)
|
||||
return if net.nil? || net.name == 'lo'
|
||||
{
|
||||
:mac => net.mac,
|
||||
:name => net.name,
|
||||
:active => net.active?
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
def list_interfaces(filters={ })
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
48
lib/fog/libvirt/requests/compute/list_networks.rb
Normal file
48
lib/fog/libvirt/requests/compute/list_networks.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def list_networks(filter = { })
|
||||
|
||||
data=[]
|
||||
if filter.keys.empty?
|
||||
(client.list_networks + client.list_defined_networks).each do |network_name|
|
||||
data << network_to_attributes(client.lookup_network_by_name(network_name))
|
||||
end
|
||||
else
|
||||
data = [network_to_attributes(get_network_by_filter(filter))]
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
private
|
||||
# Retrieve the network by uuid or name
|
||||
def get_network_by_filter(filter)
|
||||
case filter.keys.first
|
||||
when :uuid
|
||||
client.lookup_network_by_uuid(filter[:uuid])
|
||||
when :name
|
||||
client.lookup_network_by_name(filter[:name])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def network_to_attributes(net)
|
||||
return if net.nil?
|
||||
{
|
||||
:uuid => net.uuid,
|
||||
:name => net.name,
|
||||
:bridge_name => net.bridge_name
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
def list_networks(filters={ })
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/libvirt/requests/compute/list_pool_volumes.rb
Normal file
21
lib/fog/libvirt/requests/compute/list_pool_volumes.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def list_pool_volumes(uuid)
|
||||
pool = client.lookup_storage_pool_by_uuid uuid
|
||||
pool.list_volumes.map do |volume_name|
|
||||
volume_to_attributes(pool.lookup_volume_by_name(volume_name))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
def list_pool_volumes(uuid)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
56
lib/fog/libvirt/requests/compute/list_pools.rb
Normal file
56
lib/fog/libvirt/requests/compute/list_pools.rb
Normal file
|
@ -0,0 +1,56 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def list_pools(filter = { })
|
||||
data=[]
|
||||
if filter.has_key?(:name)
|
||||
data << find_pool_by_name(filter[:name])
|
||||
elsif filter.has_key?(:uuid)
|
||||
data << find_pool_by_uuid(filter[:uuid])
|
||||
else
|
||||
(client.list_storage_pools + client.list_defined_storage_pools).each do |name|
|
||||
data << find_pool_by_name(name)
|
||||
end
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
private
|
||||
def pool_to_attributes(pool)
|
||||
states=[:inactive, :building, :running, :degrated, :inaccessible]
|
||||
{
|
||||
:uuid => pool.uuid,
|
||||
:persistent => pool.persistent?,
|
||||
:autostart => pool.autostart?,
|
||||
:active => pool.active?,
|
||||
:name => pool.name,
|
||||
:allocation => pool.info.allocation,
|
||||
:capacity => pool.info.capacity,
|
||||
:num_of_volumes => pool.num_of_volumes,
|
||||
:state => states[pool.info.state]
|
||||
}
|
||||
end
|
||||
|
||||
def find_pool_by_name name
|
||||
pool_to_attributes(client.lookup_storage_pool_by_name(name))
|
||||
rescue ::Libvirt::RetrieveError
|
||||
nil
|
||||
end
|
||||
|
||||
def find_pool_by_uuid uuid
|
||||
pool_to_attributes(client.lookup_storage_pool_by_uuid(uuid))
|
||||
rescue ::Libvirt::RetrieveError
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
def list_pools(filter = { })
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
74
lib/fog/libvirt/requests/compute/list_volumes.rb
Normal file
74
lib/fog/libvirt/requests/compute/list_volumes.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
require 'erb'
|
||||
require "rexml/document"
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def list_volumes(filter = { })
|
||||
data = []
|
||||
if filter.keys.empty?
|
||||
raw_volumes do |pool|
|
||||
pool.list_volumes.each do |volume_name|
|
||||
data << volume_to_attributes(pool.lookup_volume_by_name(volume_name))
|
||||
end
|
||||
end
|
||||
else
|
||||
return [get_volume(filter)]
|
||||
end
|
||||
data.compact
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def volume_to_attributes(vol)
|
||||
|
||||
xml = REXML::Document.new(vol.xml_desc)
|
||||
format_type = xml.root.elements['/volume/target/format'].attributes['type']
|
||||
return nil if format_type == "dir"
|
||||
|
||||
{
|
||||
:pool_name => vol.pool.name,
|
||||
:key => vol.key,
|
||||
:id => vol.key,
|
||||
:path => vol.path,
|
||||
:name => vol.name,
|
||||
:format_type => format_type,
|
||||
:allocation => vol.info.allocation,
|
||||
:capacity => vol.info.capacity,
|
||||
}
|
||||
end
|
||||
|
||||
def raw_volumes
|
||||
client.list_storage_pools.each do |pool_name|
|
||||
pool = client.lookup_storage_pool_by_name(pool_name)
|
||||
yield(pool)
|
||||
end
|
||||
end
|
||||
|
||||
def get_volume filter = { }, raw = false
|
||||
raw_volumes do |pool|
|
||||
vol = case filter.keys.first
|
||||
when :name
|
||||
pool.lookup_volume_by_name(filter[:name]) rescue nil
|
||||
when :key
|
||||
pool.lookup_volume_by_key(filter[:key]) rescue nil
|
||||
when :path
|
||||
pool.lookup_volume_by_path(filter[:path]) rescue nil
|
||||
end
|
||||
if vol
|
||||
return raw ? vol : volume_to_attributes(vol)
|
||||
end
|
||||
end
|
||||
{ }
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def list_volumes(filters={ })
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
lib/fog/libvirt/requests/compute/pool_action.rb
Normal file
19
lib/fog/libvirt/requests/compute/pool_action.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def pool_action(uuid, action)
|
||||
pool = client.lookup_storage_pool_by_uuid uuid
|
||||
pool.send(action)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def pool_action(uuid, action)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
lib/fog/libvirt/requests/compute/vm_action.rb
Normal file
19
lib/fog/libvirt/requests/compute/vm_action.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def vm_action(uuid, action)
|
||||
domain = client.lookup_domain_by_uuid(uuid)
|
||||
domain.send(action)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def vm_action(uuid, action)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
lib/fog/libvirt/requests/compute/volume_action.rb
Normal file
18
lib/fog/libvirt/requests/compute/volume_action.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Libvirt
|
||||
class Real
|
||||
def volume_action(key, action, options={})
|
||||
get_volume({:key => key}, true).send(action)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def volume_action(action, options={})
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue