1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Merge branch 'master' into vmware_customization_spec

This commit is contained in:
Francois Herbert 2015-04-29 06:32:21 +12:00
commit b96e9cf7e2
86 changed files with 180 additions and 2524 deletions

View file

@ -85,10 +85,6 @@ Gem::Specification.new do |s|
s.add_development_dependency("thor")
s.add_development_dependency("yard")
if ENV["FOG_USE_LIBVIRT"]
s.add_development_dependency("ruby-libvirt","~> 0.5.0")
end
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {spec,tests}/*`.split("\n")
end

View file

@ -39,7 +39,6 @@ require 'fog/hp'
require 'fog/ibm'
require 'fog/internet_archive'
require 'fog/joyent'
require 'fog/libvirt'
require 'fog/linode'
require 'fog/local'
require 'fog/bare_metal_cloud'

View file

@ -71,7 +71,6 @@ require 'fog/bin/hp'
require 'fog/bin/ibm'
require 'fog/bin/internet_archive'
require 'fog/bin/joyent'
require 'fog/bin/libvirt'
require 'fog/bin/linode'
require 'fog/bin/local'
require 'fog/bin/bare_metal_cloud'

View file

@ -1,58 +0,0 @@
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
Fog::Logger.warning("Libvirt[:compute] is not recommended, use Compute[:libvirt] for portability")
Fog::Compute.new(:provider => 'Libvirt')
else
raise ArgumentError, "Unrecognized service: #{key.inspect}"
end
end
@@connections[service]
end
def available?
begin
availability=true unless Gem::Specification::find_by_name("ruby-libvirt").nil?
rescue Gem::LoadError
availability=false
rescue
availability_gem=Gem.available?("ruby-libvirt")
end
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

View file

@ -14,7 +14,6 @@ module Fog
data = []
service.get_all_records(zone.domain, options).body['data'].each do |records|
(type, list) = records
next if %w{soa_records ns_records}.include?(type)
list.each do |record|
data << {
:identity => record['record_id'],

View file

@ -74,13 +74,11 @@ module Fog
:disksize => disksize || "10",
:memorysize => memorysize || "512",
:cpucores => cpucores || "1",
:rootpassword => rootpassword,
:transfer => transfer || "500",
:bandwidth => bandwidth || "10",
:rootpassword => rootpassword
}
# optional options when creating a server:
[:ip, :ipv6, :description].each do |k|
[:description, :ip, :ipv6, :transfer, :bandwidth, :campaigncode, :sshkeyids, :sshkey].each do |k|
options[k] = attributes[k] if attributes[k]
end

View file

@ -1 +0,0 @@
require 'fog/libvirt/compute'

View file

@ -1,137 +0,0 @@
require 'fog/libvirt/core'
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
recognizes :libvirt_username, :libvirt_password
recognizes :libvirt_ip_command
model_path 'fog/libvirt/models/compute'
model :server
collection :servers
model :network
collection :networks
model :interface
collection :interfaces
model :volume
collection :volumes
model :pool
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 :clone_volume
request :list_networks
request :destroy_network
request :list_interfaces
request :destroy_interface
request :get_node_info
request :update_display
module Shared
include Fog::Compute::LibvirtUtil
end
class Mock
include Shared
def initialize(options={})
# libvirt is part of the gem => ruby-libvirt
require 'libvirt'
end
private
def client
return @client if defined?(@client)
end
#read mocks xml
def read_xml(file_name)
file_path = File.join(File.dirname(__FILE__),"requests","compute","mock_files",file_name)
File.read(file_path)
end
end
class Real
include Shared
attr_reader :client
attr_reader :uri
attr_reader :ip_command
def initialize(options={})
@uri = ::Fog::Compute::LibvirtUtil::URI.new(enhance_uri(options[:libvirt_uri]))
@ip_command = options[:libvirt_ip_command]
# libvirt is part of the gem => ruby-libvirt
begin
require 'libvirt'
rescue LoadError => e
retry if require('rubygems')
raise e.message
end
begin
if options[:libvirt_username] and options[:libvirt_password]
@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
@client = ::Libvirt::open(uri.uri)
end
rescue ::Libvirt::ConnectionError
raise Fog::Errors::Error.new("Error making a connection to libvirt URI #{uri.uri}:\n#{$!}")
end
end
def terminate
@client.close if @client and !@client.closed?
end
def enhance_uri(uri)
require 'cgi'
append=""
# on macosx, chances are we are using libvirt through homebrew
# the client will default to a socket location based on it's own location (/opt)
# we conveniently point it to /var/run/libvirt/libvirt-sock
# if no socket option has been specified explicitly
if RUBY_PLATFORM =~ /darwin/
querystring=::URI.parse(uri).query
if querystring.nil?
append="?socket=/var/run/libvirt/libvirt-sock"
else
if !::CGI.parse(querystring).key?("socket")
append="&socket=/var/run/libvirt/libvirt-sock"
end
end
end
uri+append
end
end
end
end
end

View file

@ -1,11 +0,0 @@
require 'fog/core'
require 'fog/xml'
require 'fog/json'
module Fog
module Libvirt
extend Fog::Provider
service(:compute, 'Compute')
end
end

View file

@ -1,76 +0,0 @@
This model implements the connection with a libvirt URI.
A libvirt URI can either be local or remote.
To learn more on the specific libvirt URI syntax see:
- [http://libvirt.org/uri.html](http://libvirt.org/uri.html)
- [http://libvirt.org/remote.html#Remote_URI_reference](http://libvirt.org/remote.html#Remote_URI_reference)
Only ssh is supported as the transport for remote URI's. TLS is NOT supported, as we can't easily login to the server
## Dependencies
- the interaction with libvirt is done through the official libvirt gem called 'ruby-libvirt'.
- be aware that there is another libvirt gem called 'libvirt', which is not compatible
- If this gem is not installed the models for libvirt will not be available
- libvirt needs to be setup so that it can be used
- for a remote ssh connection this requires to be member of the libvirt group before you can use the libvirt commands
- verify if you can execute virsh command to see if you have correct access
## Libvirt on Macosx
- There is a libvirt client for Macosx, available via homebrew
- By default this will install things in /usr/local/somewhere
- This means that also the default locations of the libvirt-socket are assumed to be in /usr/local
- To check the connection you need to override your libvirt socket location in the URI
- "qemu+ssh://patrick@myserver/system?socket=/var/run/libvirt/libvirt-sock"
## Configuration
The URI can be configured in two ways:
1) via the .fog file
:default
:libvirt_uri: "qemu+ssh://patrick@myserver/system?socket=/var/run/libvirt/libvirt-sock"
2) you can also pass it during creation :
f=Fog::Compute.new(:provider => "Libvirt", :libvirt_uri => "qemu+ssh://patrick@myserver/system")
## IP-addresses of guests
Libvirt does not provide a way to query guests for Ip-addresses.
The way we solve this problem is by installing arpwatch: this watches an interface for new mac-addresses and ip-addresses requested by DHCP
We query that logfile for the mac-address and can retrieve the ip-address
vi /etc/rsyslog.d/30-arpwatch.conf
#:msg, contains, "arpwatch:" -/var/log/arpwatch.log
#& ~
if $programname =='arpwatch' then /var/log/arpwatch.log
& ~
This log files needs to be readable for the users of libvirt
## SSh-ing into the guests
Once we have retrieved the ip-address of the guest we can ssh into it. This works great if the URI is local.
But when the URI is remote our machine can't ssh directly into the guest sometimes (due to NAT or firewall issues)
Luckily libvirt over ssh requires netcat to be installed on the libvirt server.
We use this to proxy our ssh requests to the guest over the ssh connection to the libvirt server.
Thanks to the requirement that you need ssh login to work to a libvirt server, we can login and tunnel the ssh to the guest.
## Bridge configuration (slowness)
We had noticed that sometimes it takes about 30 seconds before the server gets a DHCP response from the server.
In our case it was because the new machine Mac-address was not allowed immediately by the bridge.
Adding the flag 'bridge_fd 0' solved that problem.
/etc/network/interfaces
auto br0
iface br0 inet static
address 10.247.4.13
netmask 255.255.255.0
network 10.247.4.0
broadcast 10.247.4.255
bridge_ports eth0.4
bridge_stp on
bridge_maxwait 0
bridge_fd 0

View file

@ -1,25 +0,0 @@
require 'fog/core/model'
module Fog
module Compute
class Libvirt
class Interface < Fog::Model
identity :name
attribute :mac
attribute :active
def save
raise Fog::Errors::Error.new('Creating a new interface is not yet implemented. Contributions welcome!')
end
def shutdown
service.destroy_interface(mac)
end
def active?
active
end
end
end
end
end

View file

@ -1,20 +0,0 @@
require 'fog/core/collection'
require 'fog/libvirt/models/compute/interface'
module Fog
module Compute
class Libvirt
class Interfaces < Fog::Collection
model Fog::Compute::Libvirt::Interface
def all(filter={})
load(service.list_interfaces(filter))
end
def get(name)
self.all(:name => name).first
end
end
end
end
end

View file

@ -1,29 +0,0 @@
require 'fog/core/model'
require 'fog/libvirt/models/compute/util/util'
module Fog
module Compute
class Libvirt
class Network < Fog::Model
include Fog::Compute::LibvirtUtil
identity :uuid
attribute :name
attribute :bridge_name
attribute :xml
def initialize(attributes = {})
super
end
def save
raise Fog::Errors::Error.new('Creating a new network is not yet implemented. Contributions welcome!')
end
def shutdown
service.destroy_network(uuid)
end
end
end
end
end

View file

@ -1,20 +0,0 @@
require 'fog/core/collection'
require 'fog/libvirt/models/compute/network'
module Fog
module Compute
class Libvirt
class Networks < Fog::Collection
model Fog::Compute::Libvirt::Network
def all(filter={})
load(service.list_networks(filter))
end
def get(uuid)
self.all(:uuid => uuid).first
end
end
end
end
end

View file

@ -1,50 +0,0 @@
require 'fog/core/model'
module Fog
module Compute
class Libvirt
class Nic < Fog::Model
identity :mac
attribute :id
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
#service.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
#service.detach_nic(domain, mac)
end
private
def defaults
{
:type => "bridge",
:model => "virtio"
}
end
end
end
end
end

View file

@ -1,12 +0,0 @@
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

View file

@ -1,29 +0,0 @@
require 'fog/core/model'
module Fog
module Compute
class Libvirt
class Node < Fog::Model
identity :uuid
attribute :model
attribute :memory
attribute :cpus
attribute :mhz
attribute :nodes
attribute :sockets
attribute :cores
attribute :threads
attribute :type
attribute :version
attribute :uri
attribute :node_free_memory
attribute :max_vcpus
attribute :manufacturer
attribute :product
attribute :serial
attribute :hostname
end
end
end
end

View file

@ -1,20 +0,0 @@
require 'fog/core/collection'
require 'fog/libvirt/models/compute/node'
module Fog
module Compute
class Libvirt
class Nodes < Fog::Collection
model Fog::Compute::Libvirt::Node
def all(filter={ })
load(service.get_node_info)
end
def get
all.first
end
end
end
end
end

View file

@ -1,84 +0,0 @@
require 'fog/core/model'
module Fog
module Compute
class Libvirt
class Pool < Fog::Model
attr_reader :xml
identity :uuid
attribute :persistent
attribute :autostart
attribute :active
attribute :name
attribute :allocation
attribute :capacity
attribute :num_of_volumes
attribute :state
def initialize(attributes={} )
# Can be created by passing in XML
@xml = attributes.delete(:xml)
super(attributes)
end
def save
raise Fog::Errors::Error.new('Creating a new pool requires proper xml') unless xml
self.uuid = (persistent ? service.define_pool(xml) : service.create_pool(xml)).uuid
reload
end
# Start the pool = make it active
# Performs a libvirt create (= start)
def start
service.pool_action uuid, :create
end
# Stop the pool = make it non-active
# Performs a libvirt destroy (= stop)
def stop
service.pool_action uuid, :destroy
end
# Shuts down the pool
def shutdown
stop
end
# Build this storage pool
def build
service.pool_action uuid, :build
end
# Destroys the storage pool
def destroy
# Shutdown pool if active
service.pool_action uuid, :destroy if active?
# If this is a persistent domain we need to undefine it
service.pool_action uuid, :undefine if persistent?
end
# Is the pool active or not?
def active?
active
end
# Will the pool autostart or not?
def auto_start?
autostart
end
# Is the pool persistent or not?
def persistent?
persistent
end
# Retrieves the volumes of this pool
def volumes
service.list_pool_volumes uuid
end
end
end
end
end

View file

@ -1,20 +0,0 @@
require 'fog/core/collection'
require 'fog/libvirt/models/compute/pool'
module Fog
module Compute
class Libvirt
class Pools < Fog::Collection
model Fog::Compute::Libvirt::Pool
def all(filter = {})
load(service.list_pools(filter))
end
def get(uuid)
self.all(:uuid => uuid).first
end
end
end
end
end

View file

@ -1,401 +0,0 @@
require 'fog/compute/models/server'
require 'fog/libvirt/models/compute/util/util'
require 'net/ssh/proxy/command'
module Fog
module Compute
class Libvirt
class Server < Fog::Compute::Server
include Fog::Compute::LibvirtUtil
attr_reader :xml
identity :id, :aliases => 'uuid'
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 :nics
attribute :volumes
attribute :active
attribute :boot_order
attribute :display
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
# 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
# }
def initialize(attributes={} )
@xml = attributes.delete(:xml)
verify_boot_order(attributes[:boot_order])
super defaults.merge(attributes)
initialize_nics
initialize_volumes
end
def new?
uuid.nil?
end
def save
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 ? service.define_domain(xml) : service.create_domain(xml)).uuid
reload
rescue => e
raise Fog::Errors::Error.new("Error saving the server: #{e}")
end
def start
return true if active?
action_status = service.vm_action(uuid, :create)
reload
action_status
end
def mac
nics.first.mac if nics && nics.first
end
def disk_path
volumes.first.path if volumes and volumes.first
end
def destroy(options={ :destroy_volumes => false})
poweroff unless stopped?
service.vm_action(uuid, :undefine)
volumes.each { |vol| vol.destroy } if options[:destroy_volumes]
true
end
def reboot
action_status = service.vm_action(uuid, :reboot)
reload
action_status
end
def poweroff
action_status = service.vm_action(uuid, :destroy)
reload
action_status
end
def shutdown
action_status = service.vm_action(uuid, :shutdown)
reload
action_status
end
def resume
action_status = service.vm_action(uuid, :resume)
reload
action_status
end
def suspend
action_status = service.vm_action(uuid, :suspend)
reload
action_status
end
def stopped?
state == "shutoff"
end
def ready?
state == "running"
end
#alias methods
alias_method :halt, :poweroff
alias_method :stop, :shutdown
alias_method :active?, :active
def volumes
# lazy loading of volumes
@volumes ||= (@volumes_path || []).map{|path| service.volumes.all(:path => path).first }
end
def private_ip_address
ip_address(:private)
end
def public_ip_address
ip_address(:public)
end
def ssh(commands)
requires :ssh_ip_address, :username
ssh_options={}
ssh_options[:password] = password unless password.nil?
ssh_options[:proxy]= ssh_proxy unless ssh_proxy.nil?
super(commands, ssh_options)
end
def ssh_proxy
# if this is a direct connection, we don't need a proxy to be set.
return nil unless connection.uri.ssh_enabled?
user_string= service.uri.user ? "-l #{service.uri.user}" : ""
Net::SSH::Proxy::Command.new("ssh #{user_string} #{service.uri.host} nc %h %p")
end
# Transfers a file
def scp(local_path, remote_path, upload_options = {})
requires :ssh_ip_address, :username
scp_options = {}
scp_options[:password] = password unless self.password.nil?
scp_options[:key_data] = [private_key] if self.private_key
scp_options[:proxy]= ssh_proxy unless self.ssh_proxy.nil?
Fog::SCP.new(ssh_ip_address, username, scp_options).upload(local_path, remote_path, upload_options)
end
# Sets up a new key
def setup(credentials = {})
requires :public_key, :ssh_ip_address, :username
credentials[:proxy]= ssh_proxy unless ssh_proxy.nil?
credentials[:password] = password unless self.password.nil?
credentails[:key_data] = [private_key] if self.private_key
commands = [
%{mkdir .ssh},
# %{passwd -l #{username}}, #Not sure if we need this here
# %{echo "#{Fog::JSON.encode(attributes)}" >> ~/attributes.json}
]
if public_key
commands << %{echo "#{public_key}" >> ~/.ssh/authorized_keys}
end
# wait for domain to be ready
Timeout::timeout(360) do
begin
Timeout::timeout(8) do
Fog::SSH.new(ssh_ip_address, username, credentials.merge(:timeout => 4)).run('pwd')
end
rescue Errno::ECONNREFUSED
sleep(2)
retry
rescue Net::SSH::AuthenticationFailed, Timeout::Error
retry
end
end
Fog::SSH.new(ssh_ip_address, username, credentials).run(commands)
end
def update_display attrs = {}
service.update_display attrs.merge(:uuid => uuid)
reload
end
# can't use deprecate method, as the value is part of the display hash
def vnc_port
Fog::Logger.deprecation("#{self.class} => #vnc_port is deprecated, use #display[:port] instead [light_black](#{caller.first})[/]")
display[:port]
end
private
attr_accessor :volumes_path
# 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(service_arg=service, 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=service_arg.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' : service_arg.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 service_arg.uri.ssh_enabled?
# Retrieve the parts we need from the service to setup our ssh options
user=service_arg.uri.user #could be nil
host=service_arg.uri.host
keyfile=service_arg.uri.keyfile
port=service_arg.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 service_arg.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 service_arg.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 ip_address(key)
addresses[key].nil? ? nil : addresses[key].first
end
def initialize_nics
if nics
nics.map! { |nic| nic.is_a?(Hash) ? service.nics.new(nic) : nic }
else
self.nics = [service.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) ? service.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 = service.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[:pool_name] = volume_pool_name if volume_pool_name
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 = service.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
"/var/lib/libvirt/images"
end
def default_volume_name
"#{name}.#{volume_format_type || 'img'}"
end
def defaults
{
:persistent => true,
:cpus => 1,
:memory_size => 256 *1024,
:name => randomized_name,
:os_type => "hvm",
:arch => "x86_64",
:domain_type => "kvm",
:iso_dir => default_iso_dir,
:network_interface_type => "network",
:network_nat_network => "default",
:network_bridge_name => "br0",
:boot_order => default_boot_order,
:display => default_display
}
end
def default_boot_order
%w[hd cdrom network]
end
def verify_boot_order order = []
if order
order.each do |b|
raise "invalid boot order, possible values are: hd, network and/or cdrom" unless default_boot_order.include?(b)
end
end
end
def default_display
{:port => '-1', :listen => '127.0.0.1', :type => 'vnc', :password => '' }
end
end
end
end
end

View file

@ -1,21 +0,0 @@
require 'fog/core/collection'
require 'fog/libvirt/models/compute/server'
module Fog
module Compute
class Libvirt
class Servers < Fog::Collection
model Fog::Compute::Libvirt::Server
def all(filter={})
load(service.list_domains(filter))
end
def get(uuid)
data = service.list_domains(:uuid => uuid)
new data.first if data
end
end
end
end
end

View file

@ -1,6 +0,0 @@
<network>
<name><%= name %></name>
<forward mode='<%= network_mode %>'/>
<bridge name='<%= bridge_name %>' stp='on' delay='0' />
</ip>
</network>

View file

@ -1,6 +0,0 @@
<pool type="dir">
<name><%= name %></name>
<target>
<path><%= path %></path>
</target>
</pool>

View file

@ -1,54 +0,0 @@
<domain type='<%= domain_type %>'>
<name><%= name %></name>
<memory><%= memory_size %></memory>
<vcpu><%= cpus %></vcpu>
<os>
<type arch='<%= arch %>'><%= os_type %></type>
<% boot_order.each do |dev| -%>
<boot dev='<%= dev %>'/>
<% end -%>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<devices>
<% volumes.each do |vol| -%>
<disk type='file' device='disk'>
<driver name='qemu' type='<%= vol.format_type %>'/>
<source file='<%= vol.path %>'/>
<%# we need to ensure a unique target dev -%>
<target dev='vd<%= ('a'..'z').to_a[volumes.index(vol)] %>' bus='virtio'/>
</disk>
<% end -%>
<% if iso_file -%>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='<%= "#{iso_dir}/#{iso_file}" %>'/>
<target dev='hdc' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='1' unit='0'/>
</disk>
<% 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>
<console type='pty'>
<target port='0'/>
</console>
<input type='tablet' bus='usb'/>
<input type='mouse' bus='ps2'/>
<graphics type='<%= display[:type] %>' port='<%= display[:port] %>' autoport='yes' <% if display[:listen] and !(display[:listen].empty?) %> listen='<%= display[:listen] %>'<% end %> <% if display[:password] and !(display[:password].empty?) %>passwd='<%=display[:password] %>'<% end %> />
<video>
<model type='cirrus' vram='9216' heads='1'/>
</video>
</devices>
</domain>

View file

@ -1,26 +0,0 @@
<volume>
<name><%= name %></name>
<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>
<owner>0</owner>
<group>0</group>
<mode>0744</mode>
<label>virt_image_t</label>
</permissions>
</target>
<% if backing_volume -%>
<backingStore>
<path><%= backing_volume.path %></path>
<format type="<%= backing_volume.format_type %>"/>
<permissions>
<owner>0</owner>
<group>0</group>
<mode>0744</mode>
<label>virt_image_t</label>
</permissions>
</backingStore>
<% end -%>
</volume>

View file

@ -1,138 +0,0 @@
require 'uri'
require 'cgi'
module Fog
module Compute
module LibvirtUtil
class URI
attr_reader :uri
def initialize(uri)
@parsed_uri=::URI.parse(uri)
@uri=uri
return self
end
# Transport will be part of the scheme
# The part after the plus sign
# f.i. qemu+ssh
def transport
scheme=@parsed_uri.scheme
return nil if scheme.nil?
return scheme.split(/\+/)[1]
end
def scheme
return @parsed_uri.scheme
end
def driver
scheme=@parsed_uri.scheme
return nil if scheme.nil?
return scheme.split(/\+/).first
end
def ssh_enabled?
if remote?
return transport.include?("ssh")
else
return false
end
end
def remote?
return !transport.nil?
end
def user
@parsed_uri.user
end
def host
@parsed_uri.host
end
def port
@parsed_uri.port
end
def password
@parsed_uri.password
end
def name
value("name")
end
def command
value("command")
end
def socket
value("socket")
end
def keyfile
value("keyfile")
end
def netcat
value("netcat")
end
def no_verify?
no_verify=value("no_verify")
return false if no_verify.nil?
if no_verify.to_s=="0"
return false
else
return true
end
end
def verify?
return !no_verify?
end
def no_tty?
no_tty=value("no_tty")
return false if no_tty.nil?
if no_tty=="0"
return false
else
return true
end
end
def tty?
return !no_tty?
end
def pkipath
value("pkipath")
end
# A libvirt URI allows you to specify extra params
# http://libvirt.org/remote.html
private
def value(name)
unless @parsed_uri.query.nil?
params=CGI.parse(@parsed_uri.query)
if params.key?(name)
return params[name].first
else
return nil
end
else
return nil
end
end
end
end
end
end

View file

@ -1,32 +0,0 @@
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

View file

@ -1,122 +0,0 @@
require 'fog/core/model'
require 'fog/libvirt/models/compute/util/util'
module Fog
module Compute
class Libvirt
class Volume < Fog::Model
attr_reader :xml
include Fog::Compute::LibvirtUtil
identity :id, :aliases => 'key'
attribute :pool_name
attribute :key
attribute :name
attribute :path
attribute :capacity
attribute :allocation
attribute :format_type
attribute :backing_volume
# Can be created by passing in :xml => "<xml to create volume>"
# A volume always belongs to a pool, :pool_name => "<name of pool>"
#
def initialize(attributes={ })
@xml = attributes.delete(:xml)
super(defaults.merge(attributes))
# 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('Reserving an existing volume may create a duplicate') if key
@xml ||= to_xml
self.path = service.create_volume(pool_name, xml).path
end
# Destroy a volume
def destroy
service.volume_action key, :delete
end
# Wipes a volume , zeroes disk
def wipe
service.volume_action key, :wipe
end
# Clones this volume to the name provided
def clone(name)
new_volume = self.dup
new_volume.key = nil
new_volume.name = name
new_volume.save
new_volume.reload
end
def clone_volume(new_name)
requires :pool_name
new_volume = self.dup
new_volume.key = nil
new_volume.name = new_name
new_volume.path = service.clone_volume(pool_name, new_volume.to_xml, self.name).path
new_volume.reload
end
private
def image_suffix
return "img" if format_type == "raw"
format_type
end
def randominzed_name
"#{super}.#{image_suffix}"
end
# Try to guess the default/first pool of no pool_name was specified
def default_pool_name
name = "default"
return name unless (service.pools.all(:name => name)).empty?
# we default to the first pool we find.
first_pool = service.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",
}
end
def split_size_unit(text)
if text.kind_of? Integer
# if text is an integer, match will fail
size = text
unit = 'G'
else
matcher = text.match(/(\d+)(.+)/)
size = matcher[1]
unit = matcher[2]
end
[size, unit]
end
end
end
end
end

View file

@ -1,20 +0,0 @@
require 'fog/core/collection'
require 'fog/libvirt/models/compute/volume'
module Fog
module Compute
class Libvirt
class Volumes < Fog::Collection
model Fog::Compute::Libvirt::Volume
def all(filter = {})
load(service.list_volumes(filter))
end
def get(key)
self.all(:key => key).first
end
end
end
end
end

View file

@ -1,18 +0,0 @@
module Fog
module Compute
class Libvirt
class Real
def clone_volume (pool_name, xml, name)
vol = client.lookup_storage_pool_by_name(pool_name).lookup_volume_by_name(name)
client.lookup_storage_pool_by_name(pool_name).create_vol_xml_from(xml, vol)
end
end
class Mock
def clone_volume(pool_name, xml, name)
Fog::Compute::Libvirt::Volume.new({:pool_name => pool_name, :xml => xml})
end
end
end
end
end

View file

@ -1,17 +0,0 @@
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)
::Libvirt::Domain.new()
end
end
end
end
end

View file

@ -1,16 +0,0 @@
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(pool_name, xml)
end
end
end
end
end

View file

@ -1,17 +0,0 @@
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)
::Libvirt::Domain.new()
end
end
end
end
end

View file

@ -1,16 +0,0 @@
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

View file

@ -1,18 +0,0 @@
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

View file

@ -1,17 +0,0 @@
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

View file

@ -1,37 +0,0 @@
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 rescue nil
[:uuid, :manufacturer, :product, :serial].each do |attr|
node_hash[attr] = node_attr(attr, xml) rescue nil
end if xml
node_hash[:hostname] = client.hostname
[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

View file

@ -1,105 +0,0 @@
module Fog
module Compute
class Libvirt
class Real
def list_domains(filter = { })
data=[]
if filter.key?(:uuid)
data << client.lookup_domain_by_uuid(filter[:uuid])
elsif filter.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
end
module Shared
private
def domain_display xml
attrs = {}
[:type, :port, :password, :listen].each do |element|
attrs[element] = xml_element(xml, "domain/devices/graphics",element.to_s) rescue nil
end
attrs.reject{|k,v| v.nil? or v == ""}
end
def domain_volumes xml
xml_elements(xml, "domain/devices/disk/source", "file")
end
def boot_order xml
xml_elements(xml, "domain/os/boot", "dev")
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,
:cpus => dom.info.nr_virt_cpu,
:autostart => dom.autostart?,
:os_type => dom.os_type,
:active => dom.active?,
:display => domain_display(dom.xml_desc),
:boot_order => boot_order(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_domains(filter = { })
dom1 = mock_domain 'fog-dom1'
dom2 = mock_domain 'fog-dom2'
dom3 = mock_domain 'a-fog-dom3'
[dom1, dom2, dom3]
end
def mock_domain name
xml = read_xml 'domain.xml'
{
:id => "dom.uuid",
:uuid => "dom.uuid",
:name => name,
:max_memory_size => 8,
:cputime => 7,
:memory_size => 6,
:cpus => 5,
:autostart => false,
:os_type => "RHEL6",
:active => false,
:vnc_port => 5910,
:boot_order => boot_order(xml),
:nics => domain_interfaces(xml),
:volumes_path => domain_volumes(xml),
:state => 'shutoff'
}
end
end
end
end
end

View file

@ -1,57 +0,0 @@
module Fog
module Compute
class Libvirt
class Real
def list_interfaces(filter = { })
data=[]
if filter.keys.empty?
active_networks = client.list_interfaces rescue []
defined_networks = client.list_defined_interfaces rescue []
(active_networks + defined_networks).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={ })
if1 = mock_interface 'if1'
if2 = mock_interface 'if2'
[if1, if2]
end
def mock_interface name
{
:mac => 'aa:bb:cc:dd:ee:ff',
:name => name,
:active => true
}
end
end
end
end
end

View file

@ -1,55 +0,0 @@
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={ })
net1 = mock_network 'net1'
net2 = mock_network 'net2'
[net1, net2]
end
def mock_network name
{
:uuid => 'net.uuid',
:name => name,
:bridge_name => 'net.bridge_name'
}
end
end
end
end
end

View file

@ -1,19 +0,0 @@
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

View file

@ -1,71 +0,0 @@
module Fog
module Compute
class Libvirt
class Real
def list_pools(filter = { })
data=[]
if filter.key?(:name)
data << find_pool_by_name(filter[:name])
elsif filter.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.compact
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 = { })
pool1 = mock_pool 'pool1'
pool2 = mock_pool 'pool1'
[pool1, pool2]
end
def mock_pool name
{
:uuid => 'pool.uuid',
:persistent => true,
:autostart => true,
:active => true,
:name => name,
:allocation => 123456789,
:capacity => 123456789,
:num_of_volumes => 3,
:state => :running
}
end
end
end
end
end

View file

@ -1,88 +0,0 @@
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)
format_type = xml_element(vol.xml_desc, "/volume/target/format", "type") rescue nil # not all volumes have types, e.g. LVM
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 => bytes_to_gb(vol.info.allocation),
:capacity => bytes_to_gb(vol.info.capacity),
}
end
def bytes_to_gb bytes
bytes / 1024**3
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={ })
vol1 = mock_volume 'vol1'
vol2 = mock_volume 'vol2'
[vol1, vol2]
end
def mock_volume name
{
:pool_name => 'vol.pool.name',
:key => 'vol.key',
:id => 'vol.key',
:path => 'vol.path',
:name => name,
:format_type => 'raw',
:allocation => 123,
:capacity => 123,
}
end
end
end
end
end

View file

@ -1,40 +0,0 @@
<domain type='kvm'>
<name>fog-449765558356062</name>
<memory>262144</memory>
<vcpu>1</vcpu>
<os>
<type arch='x86_64'>hvm</type>
<boot dev='hd'/>
<boot dev='cdrom'/>
<boot dev='network'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<devices>
<interface type='network'>
<mac address="aa:bb:cc:dd:ee:ff" />
<source network='net1' />
<model type='virtio'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target port='0'/>
</console>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
</video>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='path/to/disk'/>
<target dev='vda' bus='virtio'/>
</disk>
</devices>
</domain>

View file

@ -1,19 +0,0 @@
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

View file

@ -1,31 +0,0 @@
module Fog
module Compute
class Libvirt
class Real
def update_display(options = { })
raise ArgumentError, "uuid is a required parameter" unless options.key? :uuid
display = { }
display[:type] = options[:type] || 'vnc'
display[:port] = (options[:port] || -1).to_s
display[:listen] = options[:listen].to_s if options[:listen]
display[:passwd] = options[:password].to_s if options[:password]
display[:autoport] = 'yes' if display[:port] == '-1'
builder = Nokogiri::XML::Builder.new { graphics_ (display) }
xml = Nokogiri::XML(builder.to_xml).root.to_s
client.lookup_domain_by_uuid(options[:uuid]).update_device(xml, 0)
# if we got no exceptions, then we're good'
true
end
end
class Mock
def update_display(options = { })
raise ArgumentError, "uuid is a required parameter" unless options.key? :uuid
true
end
end
end
end
end

View file

@ -1,19 +0,0 @@
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

View file

@ -1,18 +0,0 @@
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

View file

@ -28,6 +28,9 @@ module Fog
request :vm_resume
request :vm_stop
request :template_pool
request :vm_disk_snapshot
request :vm_shutdown
request :image_pool
class Mock
include Collections

View file

@ -19,6 +19,10 @@ module Fog
new data.first unless data.empty?
end
def shutdown(id)
service.vm_shutdown(id)
end
end
end
end

View file

@ -0,0 +1,27 @@
module Fog
module Compute
class OpenNebula
class Real
def image_pool(filter = { })
images = ::OpenNebula::ImagePool.new(client)
if filter[:mine].nil?
images.info!
else
images.info_mine!
end # if filter[:mine].nil?
if not filter[:id].nil?
images.each do |i|
if filter[:id] == i.id
return [ i ] # return an array with only one element - found image
end
end
end
images.delete nil
images
end #def image_pool
end #class Real
end #class OpenNebula
end #module Compute
end #module Fog

View file

@ -0,0 +1,22 @@
module Fog
module Compute
class OpenNebula
class Real
def vm_disk_snapshot(id, disk_id, image_name)
vmpool = ::OpenNebula::VirtualMachinePool.new(client)
vmpool.info!(-2,id,id,-1)
rc = 0
vmpool.each do |vm|
rc = vm.disk_snapshot(disk_id, image_name)
if(rc.is_a? ::OpenNebula::Error)
raise(rc)
end
end
rc
end #def vm_disk_snapshot
end
end
end
end

View file

@ -0,0 +1,18 @@
module Fog
module Compute
class OpenNebula
class Real
def vm_shutdown(id)
vmpool = ::OpenNebula::VirtualMachinePool.new(client)
vmpool.info!(-2,id,id,-1)
vmpool.each do |vm|
vm.shutdown()
end
end #def vm_shutdown
end
end
end
end

View file

@ -10,7 +10,7 @@ module Fog
:openstack_api_key, :openstack_username, :openstack_identity_endpoint,
:current_user, :current_tenant, :openstack_region,
:openstack_endpoint_type,
:openstack_prj_domain, :openstack_user_domain
:openstack_project_domain, :openstack_user_domain
## MODELS
#
@ -252,7 +252,7 @@ module Fog
def initialize(options={})
@openstack_username = options[:openstack_username]
@openstack_user_domain = options[:openstack_user_domain] || options[:openstack_domain]
@openstack_prj_domain = options[:openstack_prj_domain] || options[:openstack_domain] || 'Default'
@openstack_project_domain = options[:openstack_project_domain] || options[:openstack_domain] || 'Default'
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
@current_tenant = options[:openstack_tenant]
@ -295,7 +295,7 @@ module Fog
attr_reader :current_tenant
attr_reader :current_tenant_id
attr_reader :openstack_user_domain
attr_reader :openstack_prj_domain
attr_reader :openstack_project_domain
def initialize(options={})
@openstack_auth_token = options[:openstack_auth_token]
@ -307,7 +307,7 @@ module Fog
@openstack_api_key = options[:openstack_api_key]
@openstack_username = options[:openstack_username]
@openstack_user_domain = options[:openstack_user_domain] || options[:openstack_domain]
@openstack_prj_domain = options[:openstack_prj_domain] || options[:openstack_domain] || 'Default'
@openstack_project_domain = options[:openstack_project_domain] || options[:openstack_domain] || 'Default'
missing_credentials << :openstack_api_key unless @openstack_api_key
missing_credentials << :openstack_username unless @openstack_username
@ -317,7 +317,7 @@ module Fog
@openstack_tenant = options[:openstack_tenant]
@openstack_tenant_id = options[:openstack_tenant_id]
@openstack_user_domain = options[:openstack_user_domain] || options[:openstack_domain]
@openstack_prj_domain = options[:openstack_prj_domain] || options[:openstack_domain] || 'Default'
@openstack_project_domain = options[:openstack_project_domain] || options[:openstack_domain] || 'Default'
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
@openstack_management_url = options[:openstack_management_url]
@openstack_must_reauthenticate = false
@ -341,7 +341,7 @@ module Fog
def credentials
{ :provider => 'openstack',
:openstack_user_domain => @openstack_user_domain,
:openstack_prj_domain => @openstack_prj_domain,
:openstack_project_domain => @openstack_project_domain,
:openstack_auth_url => @openstack_auth_uri.to_s,
:openstack_auth_token => @auth_token,
:openstack_management_url => @openstack_management_url,
@ -398,7 +398,7 @@ module Fog
:openstack_api_key => @openstack_api_key,
:openstack_username => @openstack_username,
:openstack_user_domain => @openstack_user_domain,
:openstack_prj_domain => @openstack_prj_domain,
:openstack_project_domain => @openstack_project_domain,
:openstack_auth_token => @openstack_must_reauthenticate ? nil : @auth_token,
:openstack_auth_uri => @openstack_auth_uri,
:openstack_region => @openstack_region,

View file

@ -327,7 +327,7 @@ module Fog
auth_token = options[:openstack_auth_token] || options[:unscoped_token]
uri = options[:openstack_auth_uri]
userdomain = options[:openstack_user_domain] || options[:openstack_domain]
prj_domain = options[:openstack_prj_domain] || options[:openstack_domain] || 'Default'
project_domain = options[:openstack_project_domain] || options[:openstack_domain] || 'Default'
connection = Fog::Core::Connection.new(uri.to_s, false, connection_options)
request_body = {:auth => Hash.new}
@ -359,7 +359,7 @@ module Fog
request_body[:auth][:scope] = {
:project => {
:domain => {
:name => prj_domain
:name => project_domain
},
:name => tenant_name
}

View file

@ -11,7 +11,7 @@ module Fog
:openstack_tenant_id,
:openstack_api_key, :openstack_username, :openstack_endpoint_type,
:current_user, :current_tenant, :openstack_region,
:openstack_prj_domain, :openstack_user_domain
:openstack_project_domain, :openstack_user_domain
## MODELS
#
@ -229,7 +229,7 @@ module Fog
attr_reader :current_user
attr_reader :current_tenant
attr_reader :openstack_user_domain
attr_reader :openstack_prj_domain
attr_reader :openstack_project_domain
def initialize(options={})
@openstack_auth_token = options[:openstack_auth_token]
@ -239,7 +239,7 @@ module Fog
@openstack_api_key = options[:openstack_api_key]
@openstack_username = options[:openstack_username]
@openstack_user_domain = options[:openstack_user_domain] || options[:openstack_domain]
@openstack_prj_domain = options[:openstack_prj_domain] || options[:openstack_domain] || 'Default'
@openstack_project_domain = options[:openstack_project_domain] || options[:openstack_domain] || 'Default'
missing_credentials << :openstack_api_key unless @openstack_api_key
missing_credentials << :openstack_username unless @openstack_username
@ -249,7 +249,7 @@ module Fog
@openstack_tenant = options[:openstack_tenant]
@openstack_tenant_id = options[:openstack_tenant_id]
@openstack_user_domain = options[:openstack_user_domain] || options[:openstack_domain]
@openstack_prj_domain = options[:openstack_prj_domain] || options[:openstack_domain] || 'Default'
@openstack_project_domain = options[:openstack_project_domain] || options[:openstack_domain] || 'Default'
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
@openstack_management_url = options[:openstack_management_url]
@openstack_must_reauthenticate = false
@ -273,7 +273,7 @@ module Fog
{ :provider => 'openstack',
:openstack_tenant_id => @openstack_tenant_id,
:openstack_user_domain => @openstack_user_domain,
:openstack_prj_domain => @openstack_prj_domain,
:openstack_project_domain => @openstack_project_domain,
:openstack_auth_url => @openstack_auth_uri.to_s,
:openstack_auth_token => @auth_token,
:openstack_management_url => @openstack_management_url,
@ -328,7 +328,7 @@ module Fog
:openstack_api_key => @openstack_api_key,
:openstack_username => @openstack_username,
:openstack_user_domain => @openstack_user_domain,
:openstack_prj_domain => @openstack_prj_domain,
:openstack_project_domain => @openstack_project_domain,
:openstack_auth_uri => @openstack_auth_uri,
:openstack_auth_token => @openstack_must_reauthenticate ? nil : @openstack_auth_token,
:openstack_service_type => @openstack_service_type,

View file

@ -485,6 +485,10 @@ The `create` method also supports the following key values:
<td>Whether a read-only configuration drive is attached. Refer to Next Gen Server API documentation - <a
href="http://docs.rackspace.com/servers/api/v2/cs-devguide/content/config_drive_ext.html">Config Drive Extension</a>.</td>
</tr>
<tr>
<td>:networks</td>
<td>Array of uuids corresponding to cloud networks that should be attached to the server, and defaults to two elements (all-zeros for public internet and all-ones for ServiceNet). Please refer to the Rackspace <a href="http://docs.rackspace.com/servers/api/v2/cs-devguide/content/CreateServers.html">Create Server </a> API documentation for further information.</td>
</tr>
</table>
## Bootstrap

View file

@ -3,8 +3,11 @@ class Fog::Rackspace::CDNV2::Real
request(
:expects => [201, 202],
:method => 'PATCH',
:headers => {"Content-Type" => "application/json-patch+json"},
:body => Fog::JSON.encode(service.operations),
:path => "services/#{service.id}"
)
service.operations = []
end
end

View file

@ -7,6 +7,7 @@ module Fog
requires :vsphere_username, :vsphere_password, :vsphere_server
recognizes :vsphere_port, :vsphere_path, :vsphere_ns
recognizes :vsphere_rev, :vsphere_ssl, :vsphere_expected_pubkey_hash
recognizes :vsphere_debug
model_path 'fog/vsphere/models/compute'
model :server
@ -381,6 +382,7 @@ module Fog
@vsphere_ns = options[:vsphere_ns] || 'urn:vim25'
@vsphere_rev = options[:vsphere_rev] || '4.0'
@vsphere_ssl = options[:vsphere_ssl] || true
@vsphere_debug = options[:vsphere_debug] || false
@vsphere_expected_pubkey_hash = options[:vsphere_expected_pubkey_hash]
@vsphere_must_reauthenticate = false
@vsphere_is_vcenter = nil
@ -422,7 +424,8 @@ module Fog
:ns => @vsphere_ns,
:rev => @vsphere_rev,
:ssl => @vsphere_ssl,
:insecure => bad_cert
:insecure => bad_cert,
:debug => @vsphere_debug
break
rescue OpenSSL::SSL::SSLError
raise if bad_cert

View file

@ -126,17 +126,18 @@ module Fog
@timeout = options[:xenserver_timeout] || 30
@redirect_to_master = options[:xenserver_redirect_to_master] || false
@connection = Fog::XenServer::Connection.new(@host, @timeout)
if @redirect_to_master == false
@connection = Fog::XenServer::Connection.new(@host, @timeout)
elsif @redirect_to_master == true
host_master = @connection.find_pool_master(@username, @password)
if host_master && host_master!= @host
@host = host_master
begin
@connection.authenticate(@username, @password)
rescue Fog::XenServer::HostIsSlave => e
if @redirect_to_master
Fog::Logger.debug "Redirecting to master #{e.master_ip}"
@host = e.master_ip
@connection = Fog::XenServer::Connection.new(@host, @timeout)
@connection.authenticate(@username, @password)
else
raise e
end
end
@connection.authenticate(@username, @password)
end
def reload

View file

@ -6,6 +6,14 @@ module Fog
class InvalidLogin < Fog::Errors::Error; end
class NotFound < Fog::Errors::Error; end
class RequestFailed < Fog::Errors::Error; end
class HostIsSlave < Fog::Errors::Error
attr_reader :master_ip
def initialize(master_ip)
@master_ip = master_ip
end
end
extend Fog::Provider
@ -21,24 +29,16 @@ module Fog
@factory.timeout = timeout
end
def find_pool_master( username, password )
@credentials = authenticate( username, password )
response = @factory.call('host.get_all_records', @credentials)
if response['Status'] == "Failure"
if response['ErrorDescription'][0] == "HOST_IS_SLAVE"
ip_address = response['ErrorDescription'][1]
ip_address = ip_address.chomp
valid = !(IPAddr.new(ip_address) rescue nil).nil?
if valid
response['ErrorDescription'][1]
end
end
end
end
def authenticate( username, password )
response = @factory.call('session.login_with_password', username.to_s, password.to_s)
raise Fog::XenServer::InvalidLogin.new unless response["Status"] =~ /Success/
if response['Status'] == 'Failure'
if response['ErrorDescription'][0] == 'HOST_IS_SLAVE'
master_ip = response['ErrorDescription'][1]
raise Fog::XenServer::HostIsSlave.new(master_ip)
else
raise Fog::XenServer::InvalidLogin.new
end
end
@credentials = response["Value"]
end

View file

@ -85,7 +85,7 @@ module Fog
def create_server( name_label, template = nil, networks = [], extra_args = {})
if name_label.is_a?(Hash)
config = name_label.reject! { |_k,v| v.nil? }
config = name_label.reject { |_k,v| v.nil? }
ref = @connection.request({:parser => Fog::Parsers::XenServer::Base.new, :method => 'VM.create' }, config)
else
Fog::Logger.deprecation(

View file

@ -4,7 +4,7 @@ module Fog
class Real
def create_vbd( vm_ref, vdi_ref = '', config = {} )
if vm_ref.is_a?(Hash)
default_config = vm_ref.reject! { |_k,v| v.nil? }
default_config = vm_ref.reject { |_k,v| v.nil? }
else
Fog::Logger.deprecation(
'This api is deprecated. The only expected param is a hash of attributes.'

View file

@ -6,7 +6,7 @@ module Fog
raise ArgumentError.new('Invalid vm_ref') if vm_ref.nil?
raise ArgumentError.new('Invalid network_ref') if network_ref.nil?
if vm_ref.is_a?(Hash)
vif_config = vm_ref.reject! { |_k,v| v.nil? }
vif_config = vm_ref.reject { |_k,v| v.nil? }
else
vm_ref = vm_ref.reference if vm_ref.kind_of? Fog::Model
network_ref = network_ref.reference if network_ref.kind_of? Fog::Model

View file

@ -1,10 +0,0 @@
require "minitest/autorun"
require "fog"
require "fog/bin"
require "helpers/bin"
describe Libvirt do
include Fog::BinSpec
let(:subject) { Libvirt }
end

View file

@ -26,7 +26,6 @@ describe Fog do
assert_equal "IBM", Fog.providers[:ibm]
assert_equal "InternetArchive", Fog.providers[:internetarchive]
assert_equal "Joyent", Fog.providers[:joyent]
assert_equal "Libvirt", Fog.providers[:libvirt]
assert_equal "Linode", Fog.providers[:linode]
assert_equal "Local", Fog.providers[:local]
assert_equal "Ninefold", Fog.providers[:ninefold]
@ -77,7 +76,6 @@ describe Fog do
assert_includes Fog.registered_providers, "IBM"
assert_includes Fog.registered_providers, "InternetArchive"
assert_includes Fog.registered_providers, "Joyent"
assert_includes Fog.registered_providers, "Libvirt"
assert_includes Fog.registered_providers, "Linode"
assert_includes Fog.registered_providers, "Local"
assert_includes Fog.registered_providers, "Ninefold"
@ -128,7 +126,6 @@ describe Fog do
assert_includes Fog.available_providers, "IBM" if IBM.available?
assert_includes Fog.available_providers, "InternetArchive" if InternetArchive.available?
assert_includes Fog.available_providers, "Joyent" if Joyent.available?
assert_includes Fog.available_providers, "Libvirt" if Libvirt.available?
assert_includes Fog.available_providers, "Linode" if Linode.available?
assert_includes Fog.available_providers, "Local" if Local.available?
assert_includes Fog.available_providers, "Ninefold" if Ninefold.available?

View file

@ -34,7 +34,7 @@ end
all_providers = Fog.registered_providers.map {|provider| provider.downcase}
# Manually remove these providers since they are local applications, not lacking credentials
all_providers = all_providers - ["libvirt", "openvz"]
all_providers = all_providers - ["openvz"]
available_providers = Fog.available_providers.map {|provider| provider.downcase}
@ -49,11 +49,3 @@ end
for provider in unavailable_providers
Fog::Formatador.display_line("[yellow]Skipping tests for [bold]#{provider}[/] [yellow]due to lacking credentials (add some to '#{Fog.credentials_path}' to run them)[/]")
end
# mark libvirt tests pending if not setup
begin
require('libvirt')
rescue LoadError
Fog::Formatador.display_line("[yellow]Skipping tests for [bold]libvirt[/] [yellow]due to missing `ruby-libvirt` gem.[/]")
Thread.current[:tags] << '-libvirt'
end

View file

@ -68,7 +68,6 @@ if Fog.mock?
:ovirt_password => '123123',
:profitbricks_username => 'profitbricks_username',
:profitbricks_password => 'profitbricks_password',
:libvirt_uri => 'qemu://libvirt/system',
:rackspace_api_key => 'rackspace_api_key',
:rackspace_region => 'dfw',
:rackspace_username => 'rackspace_username',
@ -89,9 +88,6 @@ if Fog.mock?
:vsphere_username => 'apiuser',
:vsphere_password => 'apipassword',
:vsphere_expected_pubkey_hash => 'abcdef1234567890',
:libvirt_uri => 'qemu:///system',
:libvirt_username => 'root',
:libvirt_password => 'password',
:cloudsigma_username => 'csuname',
:cloudsigma_password => 'cspass',
:docker_username => 'docker-fan',

View file

@ -1,17 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt]', ['libvirt']) do
compute = Fog::Compute[:libvirt]
tests("Compute collections") do
%w{ servers interfaces networks nics nodes pools volumes}.each do |collection|
test("it should respond to #{collection}") { compute.respond_to? collection }
end
end
tests("Compute requests") do
%w{ create_domain create_volume define_domain define_pool destroy_interface destroy_network get_node_info list_domains
list_interfaces list_networks list_pools list_pool_volumes list_volumes pool_action vm_action volume_action }.each do |request|
test("it should respond to #{request}") { compute.respond_to? request }
end
end
end

View file

@ -1,27 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | interface model', ['libvirt']) do
interfaces = Fog::Compute[:libvirt].interfaces
interface = interfaces.last
tests('The interface model should') do
tests('have the action') do
test('reload') { interface.respond_to? 'reload' }
end
tests('have attributes') do
model_attribute_hash = interface.attributes
attributes = [ :name, :mac, :active]
tests("The interface model should respond to") do
attributes.each do |attribute|
test("#{attribute}") { interface.respond_to? attribute }
end
end
tests("The attributes hash should have key") do
attributes.each do |attribute|
test("#{attribute}") { model_attribute_hash.key? attribute }
end
end
end
test('be a kind of Fog::Compute::Libvirt::Interface') { interface.kind_of? Fog::Compute::Libvirt::Interface }
end
end

View file

@ -1,14 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | interfaces collection', ['libvirt']) do
interfaces = Fog::Compute[:libvirt].interfaces
tests('The interfaces collection') do
test('should not be empty') { not interfaces.empty? }
test('should be a kind of Fog::Compute::Libvirt::Interfaces') { interfaces.kind_of? Fog::Compute::Libvirt::Interfaces }
tests('should be able to reload itself').succeeds { interfaces.reload }
tests('should be able to get a model') do
tests('by instance name').succeeds { interfaces.get interfaces.first.name }
end
end
end

View file

@ -1,27 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | network model', ['libvirt']) do
networks = Fog::Compute[:libvirt].networks
network = networks.last
tests('The network model should') do
tests('have the action') do
test('reload') { network.respond_to? 'reload' }
end
tests('have attributes') do
model_attribute_hash = network.attributes
attributes = [ :name, :uuid, :bridge_name]
tests("The network model should respond to") do
attributes.each do |attribute|
test("#{attribute}") { network.respond_to? attribute }
end
end
tests("The attributes hash should have key") do
attributes.each do |attribute|
test("#{attribute}") { model_attribute_hash.key? attribute }
end
end
end
test('be a kind of Fog::Compute::Libvirt::Network') { network.kind_of? Fog::Compute::Libvirt::Network }
end
end

View file

@ -1,13 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | networks collection', ['libvirt']) do
networks = Fog::Compute[:libvirt].networks
tests('The networks collection') do
test('should be a kind of Fog::Compute::Libvirt::Networks') { networks.kind_of? Fog::Compute::Libvirt::Networks }
tests('should be able to reload itself').succeeds { networks.reload }
tests('should be able to get a model') do
tests('by instance id').succeeds { networks.get networks.first.uuid }
end
end
end

View file

@ -1,31 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | nic model', ['libvirt']) do
nic = Fog::Compute[:libvirt].servers.all.select{|v| v.name =~ /^fog/}.first.nics.first
tests('The nic model should') do
tests('have the action') do
test('reload') { nic.respond_to? 'reload' }
end
tests('have attributes') do
model_attribute_hash = nic.attributes
attributes = [ :mac,
:model,
:type,
:network,
:bridge]
tests("The nic model should respond to") do
attributes.each do |attribute|
test("#{attribute}") { nic.respond_to? attribute }
end
end
tests("The attributes hash should have key") do
attributes.delete(:bridge)
attributes.each do |attribute|
test("#{attribute}") { model_attribute_hash.key? attribute }
end
end
end
test('be a kind of Fog::Compute::Libvirt::Nic') { nic.kind_of? Fog::Compute::Libvirt::Nic }
end
end

View file

@ -1,10 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | nics collection', ['libvirt']) do
nics = Fog::Compute[:libvirt].servers.first.nics
tests('The nics collection') do
test('should not be empty') { not nics.empty? }
test('should be a kind of Array') { nics.kind_of? Array }
end
end

View file

@ -1,27 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | interface model', ['libvirt']) do
pools = Fog::Compute[:libvirt].pools
pool = pools.last
tests('The interface model should') do
tests('have the action') do
test('reload') { pool.respond_to? 'reload' }
end
tests('have attributes') do
model_attribute_hash = pool.attributes
attributes = [ :uuid, :name, :persistent, :active, :autostart, :allocation, :capacity, :num_of_volumes, :state]
tests("The interface model should respond to") do
attributes.each do |attribute|
test("#{attribute}") { pool.respond_to? attribute }
end
end
tests("The attributes hash should have key") do
attributes.each do |attribute|
test("#{attribute}") { model_attribute_hash.key? attribute }
end
end
end
test('be a kind of Fog::Compute::Libvirt::Pool') { pool.kind_of? Fog::Compute::Libvirt::Pool }
end
end

View file

@ -1,13 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | pools request', ['libvirt']) do
pools = Fog::Compute[:libvirt].pools
tests('The pools collection') do
test('should not be empty') { not pools.empty? }
test('should be a kind of Fog::Compute::Libvirt::Pools') { pools.kind_of? Fog::Compute::Libvirt::Pools }
tests('should be able to reload itself').succeeds { pools.reload }
tests('should be able to get a model') do
tests('by instance id').succeeds { pools.get pools.first.uuid }
end
end
end

View file

@ -1,58 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | server model', ['libvirt']) do
servers = Fog::Compute[:libvirt].servers
server = servers.all.select{|v| v.name =~ /^fog/}.last
tests('The server model should') do
tests('have the action') do
test('reload') { server.respond_to? 'reload' }
%w{ start stop destroy reboot suspend }.each do |action|
test(action) { server.respond_to? action }
end
%w{ start reboot suspend stop destroy}.each do |action|
test("#{action} returns successfully") {
begin
server.send(action.to_sym)
rescue Libvirt::Error
#libvirt error is acceptable for the above actions.
true
end
}
end
end
tests('have attributes') do
model_attribute_hash = server.attributes
attributes = [ :id,
:cpus,
:cputime,
:os_type,
:memory_size,
:max_memory_size,
:name,
:arch,
:persistent,
:domain_type,
:uuid,
:autostart,
:display,
:nics,
:volumes,
:active,
:boot_order,
:state]
tests("The server model should respond to") do
attributes.each do |attribute|
test("#{attribute}") { server.respond_to? attribute }
end
end
tests("The attributes hash should have key") do
attributes.delete(:volumes)
attributes.each do |attribute|
test("#{attribute}") { model_attribute_hash.key? attribute }
end
end
end
test('be a kind of Fog::Compute::Libvirt::Server') { server.kind_of? Fog::Compute::Libvirt::Server }
end
end

View file

@ -1,14 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | servers collection', ['libvirt']) do
servers = Fog::Compute[:libvirt].servers
tests('The servers collection') do
test('should not be empty') { not servers.empty? }
test('should be a kind of Fog::Compute::Libvirt::Servers') { servers.kind_of? Fog::Compute::Libvirt::Servers }
tests('should be able to reload itself').succeeds { servers.reload }
tests('should be able to get a model') do
tests('by instance uuid').succeeds { servers.get servers.first.id }
end
end
end

View file

@ -1,38 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | volume model', ['libvirt']) do
volume = Fog::Compute[:libvirt].servers.all.select{|v| v.name !~ /^fog/}.first.volumes.first
tests('The volume model should') do
tests('have attributes') do
model_attribute_hash = volume.attributes
attributes = [ :id,
:pool_name,
:key,
:name,
:path,
:capacity,
:allocation,
:format_type]
tests("The volume model should respond to") do
attributes.each do |attribute|
test("#{attribute}") { volume.respond_to? attribute }
end
end
tests("The attributes hash should have key") do
attributes.each do |attribute|
test("#{attribute}") { model_attribute_hash.key? attribute }
end
end
end
test('be a kind of Fog::Compute::Libvirt::Volume') { volume.kind_of? Fog::Compute::Libvirt::Volume }
end
tests('Cloning volumes should') do
test('respond to clone_volume') { volume.respond_to? :clone_volume }
new_vol = volume.clone_volume('new_vol')
# We'd like to test that the :name attr has changed, but it seems that's
# not possible, so we can at least check the new_vol xml exists properly
test('succeed') { volume.xml == new_vol.xml }
end
end

View file

@ -1,14 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | volumes collection', ['libvirt']) do
volumes = Fog::Compute[:libvirt].volumes
tests('The volumes collection') do
test('should not be empty') { not volumes.empty? }
test('should be a kind of Fog::Compute::Libvirt::Volumes') { volumes.kind_of? Fog::Compute::Libvirt::Volumes }
tests('should be able to reload itself').succeeds { volumes.reload }
tests('should be able to get a model') do
tests('by instance uuid').succeeds { volumes.get volumes.first.id }
end
end
end

View file

@ -1,21 +0,0 @@
Shindo.tests("Fog::Compute[:libvirt] | create_domain request", 'libvirt') do
compute = Fog::Compute[:libvirt]
xml = compute.servers.new( :nics => [{:bridge => "br180"}]).to_xml
tests("Create Domain") do
response = compute.create_domain(xml)
test("should be a kind of Libvirt::Domain") { response.kind_of? Libvirt::Domain}
end
tests("Fail Creating Domain") do
begin
response = compute.create_domain(xml)
test("should be a kind of Libvirt::Domain") { response.kind_of? Libvirt::Domain} #mock never raise exceptions
rescue => e
#should raise vm name already exist exception.
test("error should be a kind of Libvirt::Error") { e.kind_of? Libvirt::Error}
end
end
end

View file

@ -1,11 +0,0 @@
Shindo.tests("Fog::Compute[:libvirt] | define_domain request", 'libvirt') do
compute = Fog::Compute[:libvirt]
xml = compute.servers.new().to_xml
tests("Define Domain") do
response = compute.define_domain(xml)
test("should be a kind of Libvirt::Domain") { response.kind_of? Libvirt::Domain}
end
end

View file

@ -1,13 +0,0 @@
Shindo.tests('Fog::Compute[:libvirt] | update_display request', ['libvirt']) do
compute = Fog::Compute[:libvirt]
reconfig_target = 'f74d728a-5b62-7e2f-1f84-239aead298ca'
display_spec = {:password => 'ssaaa'}
tests('The response should') do
response = compute.update_display(:uuid => reconfig_target).merge(display_spec)
test('should be true').succeeds { response }
end
end

View file

@ -0,0 +1,49 @@
Shindo.tests("Fog::Compute[:opennebula] | vm_create and destroy request", 'opennebula') do
compute = Fog::Compute[:opennebula]
name_base = Time.now.to_i
f = compute.flavors.get_by_name("fogtest")
tests("Get 'fogtest' flavor/template") do
test("Got template with name 'fogtest'") {f.kind_of? Array}
raise ArgumentError, "Could not get a template with the name 'fogtest'! This is required for live tests!" unless f
end
f = f.first
newvm = compute.servers.new
newvm.flavor = f
newvm.name = 'fogtest-'+name_base.to_s
vm = newvm.save
tests("Start VM") do
test("response should be a kind of Hash") { vm.kind_of? Fog::Compute::OpenNebula::Server}
test("id should be a one-id (Fixnum)") { vm.id.is_a? Fixnum}
vm.wait_for { (vm.state == 'RUNNING') }
test("VM should be in RUNNING state") { vm.state == 'RUNNING' }
sleep(30) # waiting for 30 seconds to let VM finish booting
end
tests("Create snapshot of the disk and shutdown VM") do
img_id = compute.vm_disk_snapshot(vm.id, 0, 'fogtest-'+name_base.to_s)
test("Image ID of created snapshot should be a kind of Fixnum") { img_id.is_a? Fixnum }
(1..5).each do # wait maximum 5 seconds
sleep(1) # The delay is needed for some reason between issueing disk-snapshot and shutdown
images = compute.image_pool( { :mine => true, :id => img_id } )
test("Got Image with ID=#{img_id}") { images.kind_of? Array }
if images[0].state == 4 # LOCKED, it is normal we must shutdown VM for image to go into READY state
break
end
end
compute.servers.shutdown(vm.id)
image_state = 4
(1..25).each do # Waiting for up to 50 seconds for Image to become READY
sleep(2)
images = compute.image_pool( { :mine => true, :id => img_id } )
image_state = images[0].state
if image_state == 1
break
end
end
test("New image with ID=#{img_id} should be in state READY.") { image_state == 1 }
end
end