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:
commit
b96e9cf7e2
86 changed files with 180 additions and 2524 deletions
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
|
@ -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'],
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
require 'fog/libvirt/compute'
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,6 +0,0 @@
|
|||
<network>
|
||||
<name><%= name %></name>
|
||||
<forward mode='<%= network_mode %>'/>
|
||||
<bridge name='<%= bridge_name %>' stp='on' delay='0' />
|
||||
</ip>
|
||||
</network>
|
|
@ -1,6 +0,0 @@
|
|||
<pool type="dir">
|
||||
<name><%= name %></name>
|
||||
<target>
|
||||
<path><%= path %></path>
|
||||
</target>
|
||||
</pool>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -19,6 +19,10 @@ module Fog
|
|||
new data.first unless data.empty?
|
||||
end
|
||||
|
||||
def shutdown(id)
|
||||
service.vm_shutdown(id)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
27
lib/fog/opennebula/requests/compute/image_pool.rb
Normal file
27
lib/fog/opennebula/requests/compute/image_pool.rb
Normal 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
|
22
lib/fog/opennebula/requests/compute/vm_disk_snapshot.rb
Normal file
22
lib/fog/opennebula/requests/compute/vm_disk_snapshot.rb
Normal 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
|
18
lib/fog/opennebula/requests/compute/vm_shutdown.rb
Normal file
18
lib/fog/opennebula/requests/compute/vm_shutdown.rb
Normal 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
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
49
tests/opennebula/requests/compute/vm_disk_snapshot_test.rb
Normal file
49
tests/opennebula/requests/compute/vm_disk_snapshot_test.rb
Normal 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
|
Loading…
Add table
Reference in a new issue