[DRE-commits] [ruby-fog-libvirt] 01/16: Import upstream 0.0.2.
Antonio Terceiro
terceiro at moszumanska.debian.org
Sat Apr 23 18:18:53 UTC 2016
This is an automated email from the git hooks/post-receive script.
terceiro pushed a commit to branch master
in repository ruby-fog-libvirt.
commit 7a1edfbb4850bfc4ce50cedde0180ae266d738e5
Author: intrigeri <intrigeri at boum.org>
Date: Thu Aug 13 12:00:15 2015 +0000
Import upstream 0.0.2.
---
CONTRIBUTORS.md | 23 ++
Gemfile | 9 +
LICENSE.md | 20 +
README.md | 29 ++
Rakefile | 127 ++++++
fog-libvirt.gemspec | 52 +++
lib/fog/bin/libvirt.rb | 58 +++
lib/fog/libvirt.rb | 18 +
lib/fog/libvirt/compute.rb | 137 +++++++
lib/fog/libvirt/models/compute/README.md | 76 ++++
lib/fog/libvirt/models/compute/interface.rb | 25 ++
lib/fog/libvirt/models/compute/interfaces.rb | 20 +
lib/fog/libvirt/models/compute/network.rb | 29 ++
lib/fog/libvirt/models/compute/networks.rb | 20 +
lib/fog/libvirt/models/compute/nic.rb | 50 +++
lib/fog/libvirt/models/compute/nics.rb | 12 +
lib/fog/libvirt/models/compute/node.rb | 29 ++
lib/fog/libvirt/models/compute/nodes.rb | 20 +
lib/fog/libvirt/models/compute/pool.rb | 84 ++++
lib/fog/libvirt/models/compute/pools.rb | 20 +
lib/fog/libvirt/models/compute/server.rb | 434 +++++++++++++++++++++
lib/fog/libvirt/models/compute/servers.rb | 21 +
.../models/compute/templates/network.xml.erb | 6 +
.../libvirt/models/compute/templates/pool.xml.erb | 6 +
.../models/compute/templates/server.xml.erb | 54 +++
.../models/compute/templates/volume.xml.erb | 26 ++
lib/fog/libvirt/models/compute/util/uri.rb | 138 +++++++
lib/fog/libvirt/models/compute/util/util.rb | 32 ++
lib/fog/libvirt/models/compute/volume.rb | 127 ++++++
lib/fog/libvirt/models/compute/volumes.rb | 20 +
lib/fog/libvirt/requests/compute/clone_volume.rb | 18 +
lib/fog/libvirt/requests/compute/create_domain.rb | 17 +
lib/fog/libvirt/requests/compute/create_volume.rb | 16 +
lib/fog/libvirt/requests/compute/define_domain.rb | 17 +
lib/fog/libvirt/requests/compute/define_pool.rb | 16 +
.../libvirt/requests/compute/destroy_interface.rb | 18 +
.../libvirt/requests/compute/destroy_network.rb | 17 +
lib/fog/libvirt/requests/compute/get_node_info.rb | 37 ++
lib/fog/libvirt/requests/compute/list_domains.rb | 105 +++++
.../libvirt/requests/compute/list_interfaces.rb | 57 +++
lib/fog/libvirt/requests/compute/list_networks.rb | 55 +++
.../libvirt/requests/compute/list_pool_volumes.rb | 19 +
lib/fog/libvirt/requests/compute/list_pools.rb | 71 ++++
lib/fog/libvirt/requests/compute/list_volumes.rb | 88 +++++
.../libvirt/requests/compute/mock_files/domain.xml | 40 ++
lib/fog/libvirt/requests/compute/pool_action.rb | 19 +
lib/fog/libvirt/requests/compute/update_display.rb | 31 ++
lib/fog/libvirt/requests/compute/upload_volume.rb | 31 ++
lib/fog/libvirt/requests/compute/vm_action.rb | 19 +
lib/fog/libvirt/requests/compute/volume_action.rb | 18 +
lib/fog/libvirt/version.rb | 5 +
metadata.yml | 344 ++++++++++++++++
minitests/server/user_data_iso_test.rb | 69 ++++
minitests/test_helper.rb | 18 +
tests/helper.rb | 17 +
tests/helpers/formats_helper.rb | 98 +++++
tests/helpers/formats_helper_tests.rb | 110 ++++++
tests/helpers/mock_helper.rb | 14 +
tests/helpers/succeeds_helper.rb | 9 +
tests/libvirt/compute_tests.rb | 17 +
tests/libvirt/models/compute/interface_tests.rb | 27 ++
tests/libvirt/models/compute/interfaces_tests.rb | 14 +
tests/libvirt/models/compute/network_tests.rb | 27 ++
tests/libvirt/models/compute/networks_tests.rb | 13 +
tests/libvirt/models/compute/nic_tests.rb | 31 ++
tests/libvirt/models/compute/nics_tests.rb | 10 +
tests/libvirt/models/compute/pool_tests.rb | 27 ++
tests/libvirt/models/compute/pools_tests.rb | 13 +
tests/libvirt/models/compute/server_tests.rb | 57 +++
tests/libvirt/models/compute/servers_tests.rb | 14 +
tests/libvirt/models/compute/volume_tests.rb | 38 ++
tests/libvirt/models/compute/volumes_tests.rb | 14 +
.../requests/compute/create_domain_tests.rb | 21 +
.../requests/compute/define_domain_tests.rb | 11 +
tests/libvirt/requests/compute/update_display.rb | 13 +
75 files changed, 3462 insertions(+)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
new file mode 100644
index 0000000..396d46c
--- /dev/null
+++ b/CONTRIBUTORS.md
@@ -0,0 +1,23 @@
+* Amos Benari <abenari at redhat.com>
+* brookemckim <brooke.mckim at gmail.com>
+* Carl Caum <carl at carlcaum.com>
+* Carlos Sanchez <csanchez at maestrodev.com>
+* David Wittman <david at wittman.com>
+* Dominic Cleal <dcleal at redhat.com>
+* Greg Sutcliffe <gsutclif at redhat.com>
+* James Herdman <james.herdman at me.com>
+* Josef Strzibny <strzibny at strzibny.name>
+* Kevin Menard <nirvdrum at gmail.com>
+* Konstantin Haase <konstantin.mailinglists at googlemail.com>
+* Kyle Rames <kyle.rames at rackspace.com>
+* Lance Ivy <lance at cainlevy.net>
+* Ohad Levy <ohadlevy at redhat.com>
+* Patrick Debois <Patrick.Debois at jedi.be>
+* Paul Thornthwaite <tokengeek at gmail.com>
+* Romain Vrignaud <romain at yakaz.com>
+* Ryan Davies <ryan at ryandavies.co.nz>
+* Sergio Rubio <rubiojr at frameos.org>
+* Shlomi Zadok <shlomi at ben-hanna.com>
+* Steve Smith <github at scsworld.co.uk>
+* Vincent Demeester <vincent+git at demeester.fr>
+* Wesley Beary <geemus at gmail.com>
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..23db6d7
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,9 @@
+source "https://rubygems.org"
+
+group :development, :test do
+ # This is here because gemspec doesn't support require: false
+ gem "netrc", :require => false
+ gem "octokit", :require => false
+end
+
+gemspec
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..0a31a1a
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2009-2014 [CONTRIBUTORS.md](https://github.com/fog/fog/blob/master/CONTRIBUTORS.md)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..44b78a2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,29 @@
+# Fog::Libvirt
+
+fog-libvirt is a libvirt provider for [fog](https://github.com/fog/fog).
+
+[](http://travis-ci.org/fog/fog-libvirt)
+[](https://gemnasium.com/fog/fog-libvirt)
+[](https://codeclimate.com/github/fog/fog-libvirt)
+[](http://badge.fury.io/rb/fog-libvirt)
+[](https://www.gittip.com/geemus/)
+
+## Installation
+
+fog-libvirt can be used as a module for fog or installed separately as:
+
+```
+$ sudo gem install fog-libvirt
+```
+
+## Usage
+
+See [README.md](https://github.com/fog/fog-libvirt/blob/master/lib/fog/libvirt/models/compute/README.md).
+
+## Contributing
+
+Please refer to [CONTRIBUTING.md](https://github.com/fog/fog/blob/master/CONTRIBUTING.md).
+
+## License
+
+Please refer to [LICENSE.md](https://github.com/fog/fog-libvirt/blob/master/LICENSE.md).
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..5230dfc
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,127 @@
+require 'bundler/setup'
+require 'rake/testtask'
+require 'rubygems'
+require 'rubygems/package_task'
+require 'yard'
+require File.dirname(__FILE__) + '/lib/fog/libvirt'
+
+#############################################################################
+#
+# Helper functions
+#
+#############################################################################
+
+def name
+ @name ||= Dir['*.gemspec'].first.split('.').first
+end
+
+def version
+ Fog::Libvirt::VERSION
+end
+
+def gemspec_file
+ "#{name}.gemspec"
+end
+
+def gem_file
+ "#{name}-#{version}.gem"
+end
+
+#############################################################################
+#
+# Standard tasks
+#
+#############################################################################
+
+GEM_NAME = "#{name}"
+task :default => [:test, :minitest]
+
+Rake::TestTask.new(:minitest) do |t|
+ t.libs << '.'
+ t.libs << 'lib'
+ t.libs << 'minitests'
+ t.test_files = Dir.glob('minitests/**/*_test.rb')
+ t.verbose = true
+end
+
+desc 'Run tests'
+task :test do
+ mock = ENV['FOG_MOCK'] || 'true'
+ sh("export FOG_MOCK=#{mock} && bundle exec shindont tests")
+end
+
+desc 'Run mocked tests'
+task :mock do
+ sh("export FOG_MOCK=true && bundle exec shindont tests")
+end
+
+desc 'Run live tests'
+task :live do
+ sh("export FOG_MOCK=false && bundle exec shindont tests")
+end
+
+desc "Open an irb session preloaded with this library"
+task :console do
+ sh "irb -rubygems -r ./lib/fog/libvirt.rb"
+end
+
+#############################################################################
+#
+# Packaging tasks
+#
+#############################################################################
+
+task :release => ["release:prepare", "release:publish"]
+
+namespace :release do
+ task :preflight do
+ unless `git branch` =~ /^\* master$/
+ puts "You must be on the master branch to release!"
+ exit!
+ end
+ if `git tag` =~ /^\* v#{version}$/
+ puts "Tag v#{version} already exists!"
+ exit!
+ end
+ end
+
+ task :prepare => :preflight do
+ Rake::Task[:build].invoke
+ sh "gem install pkg/#{name}-#{version}.gem"
+ Rake::Task[:git_mark_release].invoke
+ end
+
+ task :publish do
+ Rake::Task[:git_push_release].invoke
+ Rake::Task[:gem_push].invoke
+ end
+end
+
+task :git_mark_release do
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
+ sh "git tag v#{version}"
+end
+
+task :git_push_release do
+ sh "git push origin master"
+ sh "git push origin v#{version}"
+end
+
+task :gem_push do
+ sh "gem push pkg/#{name}-#{version}.gem"
+end
+
+desc "Build #{name}-#{version}.gem"
+task :build do
+ sh "mkdir -p pkg"
+ sh "gem build #{gemspec_file}"
+ sh "mv #{gem_file} pkg"
+end
+task :gem => :build
+
+# Include Yard tasks for rake yard
+YARDOC_LOCATION = "doc"
+YARD::Rake::YardocTask.new do |t|
+ t.files = ['lib/**/*.rb', "README"]
+ t.options = ["--output-dir", YARDOC_LOCATION, "--title", "#{name} #{version}"]
+end
diff --git a/fog-libvirt.gemspec b/fog-libvirt.gemspec
new file mode 100644
index 0000000..f3c6b9c
--- /dev/null
+++ b/fog-libvirt.gemspec
@@ -0,0 +1,52 @@
+# coding: utf-8
+lib = File.expand_path("../lib", __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require "fog/libvirt/version"
+
+Gem::Specification.new do |s|
+ s.specification_version = 2 if s.respond_to? :specification_version=
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+
+ s.name = "fog-libvirt"
+ s.version = Fog::Libvirt::VERSION
+
+ s.summary = "Module for the 'fog' gem to support libvirt"
+ s.description = "This library can be used as a module for 'fog' or as standalone libvirt provider."
+
+ s.authors = ["geemus (Wesley Beary)"]
+ s.email = "geemus at gmail.com"
+ s.homepage = "http://github.com/fog/fog-libvirt"
+ s.license = "MIT"
+
+ s.require_paths = %w[lib]
+
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.extra_rdoc_files = %w[README.md]
+
+ s.add_dependency("fog-core", "~> 1.27", ">= 1.27.4")
+ s.add_dependency("fog-json")
+ s.add_dependency("fog-xml", "~> 0.1.1")
+ s.add_dependency('ruby-libvirt','~> 0.5.0')
+ s.add_dependency('mime-types','< 2.0') if RUBY_VERSION < '1.9'
+ s.add_dependency('nokogiri', '< 1.6') if RUBY_VERSION < '1.9'
+ s.add_dependency('octokit', '< 3.0') if RUBY_VERSION < '1.9'
+ s.add_dependency('rest-client', '<= 1.7.0') if RUBY_VERSION < '1.9'
+
+ # Fedora and derivates need explicit require
+ s.add_dependency("json")
+
+ s.add_development_dependency("minitest")
+ s.add_development_dependency("minitest-stub-const")
+ s.add_development_dependency("pry")
+ s.add_development_dependency("rake")
+ s.add_development_dependency("rubocop") if RUBY_VERSION > "1.9"
+ s.add_development_dependency("shindo", "~> 0.3.4")
+ s.add_development_dependency("simplecov")
+ s.add_development_dependency("yard")
+ s.add_development_dependency("mocha", "~> 1.1.0")
+
+ # Let's not ship dot files and gemfiles
+ git_files = `git ls-files`.split("\n")
+ s.files = git_files.delete_if{ |f| f =~ /^\..*/ || f =~ /^gemfiles\/*/ }
+ s.test_files = `git ls-files -- {spec,tests}/*`.split("\n")
+end
diff --git a/lib/fog/bin/libvirt.rb b/lib/fog/bin/libvirt.rb
new file mode 100644
index 0000000..8cff49d
--- /dev/null
+++ b/lib/fog/bin/libvirt.rb
@@ -0,0 +1,58 @@
+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
diff --git a/lib/fog/libvirt.rb b/lib/fog/libvirt.rb
new file mode 100644
index 0000000..013b845
--- /dev/null
+++ b/lib/fog/libvirt.rb
@@ -0,0 +1,18 @@
+require 'fog/core'
+require 'fog/xml'
+require 'fog/json'
+require 'libvirt'
+
+require File.expand_path('../libvirt/version', __FILE__)
+
+module Fog
+ module Libvirt
+ extend Fog::Provider
+
+ module Compute
+ autoload :Libvirt, File.expand_path('../libvirt/compute', __FILE__)
+ end
+
+ service(:compute, 'Compute')
+ end
+end
diff --git a/lib/fog/libvirt/compute.rb b/lib/fog/libvirt/compute.rb
new file mode 100644
index 0000000..59a916f
--- /dev/null
+++ b/lib/fog/libvirt/compute.rb
@@ -0,0 +1,137 @@
+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 :upload_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
diff --git a/lib/fog/libvirt/models/compute/README.md b/lib/fog/libvirt/models/compute/README.md
new file mode 100644
index 0000000..e681b73
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/README.md
@@ -0,0 +1,76 @@
+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
+
diff --git a/lib/fog/libvirt/models/compute/interface.rb b/lib/fog/libvirt/models/compute/interface.rb
new file mode 100644
index 0000000..a7ebde6
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/interface.rb
@@ -0,0 +1,25 @@
+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
diff --git a/lib/fog/libvirt/models/compute/interfaces.rb b/lib/fog/libvirt/models/compute/interfaces.rb
new file mode 100644
index 0000000..48f696d
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/interfaces.rb
@@ -0,0 +1,20 @@
+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
diff --git a/lib/fog/libvirt/models/compute/network.rb b/lib/fog/libvirt/models/compute/network.rb
new file mode 100644
index 0000000..6a80247
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/network.rb
@@ -0,0 +1,29 @@
+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
diff --git a/lib/fog/libvirt/models/compute/networks.rb b/lib/fog/libvirt/models/compute/networks.rb
new file mode 100644
index 0000000..760ccf2
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/networks.rb
@@ -0,0 +1,20 @@
+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
diff --git a/lib/fog/libvirt/models/compute/nic.rb b/lib/fog/libvirt/models/compute/nic.rb
new file mode 100644
index 0000000..485b417
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/nic.rb
@@ -0,0 +1,50 @@
+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
diff --git a/lib/fog/libvirt/models/compute/nics.rb b/lib/fog/libvirt/models/compute/nics.rb
new file mode 100644
index 0000000..7a326f3
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/nics.rb
@@ -0,0 +1,12 @@
+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
diff --git a/lib/fog/libvirt/models/compute/node.rb b/lib/fog/libvirt/models/compute/node.rb
new file mode 100644
index 0000000..02d3fc7
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/node.rb
@@ -0,0 +1,29 @@
+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
diff --git a/lib/fog/libvirt/models/compute/nodes.rb b/lib/fog/libvirt/models/compute/nodes.rb
new file mode 100644
index 0000000..72d6d7b
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/nodes.rb
@@ -0,0 +1,20 @@
+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
diff --git a/lib/fog/libvirt/models/compute/pool.rb b/lib/fog/libvirt/models/compute/pool.rb
new file mode 100644
index 0000000..d186b86
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/pool.rb
@@ -0,0 +1,84 @@
+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
diff --git a/lib/fog/libvirt/models/compute/pools.rb b/lib/fog/libvirt/models/compute/pools.rb
new file mode 100644
index 0000000..2f3f73f
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/pools.rb
@@ -0,0 +1,20 @@
+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
diff --git a/lib/fog/libvirt/models/compute/server.rb b/lib/fog/libvirt/models/compute/server.rb
new file mode 100644
index 0000000..30d6452
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/server.rb
@@ -0,0 +1,434 @@
+require 'fog/compute/models/server'
+require 'fog/libvirt/models/compute/util/util'
+require 'net/ssh/proxy/command'
+require 'fileutils'
+
+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
+ attr_accessor :user_data
+
+ # 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
+ @user_data = attributes.delete(:user_data)
+ 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
+ create_user_data_iso if user_data
+ @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
+
+ def generate_config_iso(user_data, &blk)
+ Dir.mktmpdir('config') do |wd|
+ generate_config_iso_in_dir(wd, user_data, &blk)
+ end
+ end
+
+ def generate_config_iso_in_dir(dir_path, user_data, &blk)
+ FileUtils.touch(File.join(dir_path, "meta-data"))
+ File.open(File.join(dir_path, 'user-data'), 'w') { |f| f.write user_data }
+
+ isofile = Tempfile.new(['init', '.iso']).path
+ unless system("genisoimage -output #{isofile} -volid cidata -joliet -rock #{File.join(dir_path, 'user-data')} #{File.join(dir_path, 'meta-data')}")
+ raise Fog::Errors::Error("Couldn't generate cloud-init iso disk.")
+ end
+ blk.call(isofile)
+ end
+
+ def create_user_data_iso
+ generate_config_iso(user_data) do |iso|
+ vol = service.volumes.create(:name => cloud_init_volume_name, :capacity => "#{File.size(iso)}b", :allocation => "0G")
+ vol.upload_image(iso)
+ @iso_file = cloud_init_volume_name
+ end
+ end
+
+ def cloud_init_volume_name
+ "#{name}-cloud-init.iso"
+ 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
diff --git a/lib/fog/libvirt/models/compute/servers.rb b/lib/fog/libvirt/models/compute/servers.rb
new file mode 100644
index 0000000..a28db2f
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/servers.rb
@@ -0,0 +1,21 @@
+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
diff --git a/lib/fog/libvirt/models/compute/templates/network.xml.erb b/lib/fog/libvirt/models/compute/templates/network.xml.erb
new file mode 100644
index 0000000..91493dd
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/templates/network.xml.erb
@@ -0,0 +1,6 @@
+<network>
+ <name><%= name %></name>
+ <forward mode='<%= network_mode %>'/>
+ <bridge name='<%= bridge_name %>' stp='on' delay='0' />
+ </ip>
+</network>
diff --git a/lib/fog/libvirt/models/compute/templates/pool.xml.erb b/lib/fog/libvirt/models/compute/templates/pool.xml.erb
new file mode 100644
index 0000000..816916a
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/templates/pool.xml.erb
@@ -0,0 +1,6 @@
+<pool type="dir">
+ <name><%= name %></name>
+ <target>
+ <path><%= path %></path>
+ </target>
+</pool>
diff --git a/lib/fog/libvirt/models/compute/templates/server.xml.erb b/lib/fog/libvirt/models/compute/templates/server.xml.erb
new file mode 100644
index 0000000..a7036f9
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/templates/server.xml.erb
@@ -0,0 +1,54 @@
+<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>
diff --git a/lib/fog/libvirt/models/compute/templates/volume.xml.erb b/lib/fog/libvirt/models/compute/templates/volume.xml.erb
new file mode 100644
index 0000000..5f78e89
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/templates/volume.xml.erb
@@ -0,0 +1,26 @@
+<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>
diff --git a/lib/fog/libvirt/models/compute/util/uri.rb b/lib/fog/libvirt/models/compute/util/uri.rb
new file mode 100644
index 0000000..cbb2e86
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/util/uri.rb
@@ -0,0 +1,138 @@
+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
diff --git a/lib/fog/libvirt/models/compute/util/util.rb b/lib/fog/libvirt/models/compute/util/util.rb
new file mode 100644
index 0000000..28aadf7
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/util/util.rb
@@ -0,0 +1,32 @@
+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
diff --git a/lib/fog/libvirt/models/compute/volume.rb b/lib/fog/libvirt/models/compute/volume.rb
new file mode 100644
index 0000000..04e604f
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/volume.rb
@@ -0,0 +1,127 @@
+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
+
+ def upload_image(file_path)
+ requires :pool_name
+ service.upload_volume(pool_name, name, file_path)
+ 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
diff --git a/lib/fog/libvirt/models/compute/volumes.rb b/lib/fog/libvirt/models/compute/volumes.rb
new file mode 100644
index 0000000..a29a0b4
--- /dev/null
+++ b/lib/fog/libvirt/models/compute/volumes.rb
@@ -0,0 +1,20 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/clone_volume.rb b/lib/fog/libvirt/requests/compute/clone_volume.rb
new file mode 100644
index 0000000..fe0bc71
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/clone_volume.rb
@@ -0,0 +1,18 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/create_domain.rb b/lib/fog/libvirt/requests/compute/create_domain.rb
new file mode 100644
index 0000000..8bcb733
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/create_domain.rb
@@ -0,0 +1,17 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ def create_domain(xml)
+ client.create_domain_xml(xml)
+ end
+ end
+
+ class Mock
+ def create_domain(xml)
+ ::Libvirt::Domain.new()
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/create_volume.rb b/lib/fog/libvirt/requests/compute/create_volume.rb
new file mode 100644
index 0000000..f1f90d8
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/create_volume.rb
@@ -0,0 +1,16 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/define_domain.rb b/lib/fog/libvirt/requests/compute/define_domain.rb
new file mode 100644
index 0000000..53b8fae
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/define_domain.rb
@@ -0,0 +1,17 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ def define_domain(xml)
+ client.define_domain_xml(xml)
+ end
+ end
+
+ class Mock
+ def define_domain(xml)
+ ::Libvirt::Domain.new()
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/define_pool.rb b/lib/fog/libvirt/requests/compute/define_pool.rb
new file mode 100644
index 0000000..8874bf4
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/define_pool.rb
@@ -0,0 +1,16 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/destroy_interface.rb b/lib/fog/libvirt/requests/compute/destroy_interface.rb
new file mode 100644
index 0000000..5e7bfc5
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/destroy_interface.rb
@@ -0,0 +1,18 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ #shutdown the interface
+ def destroy_interface(uuid)
+ client.lookup_interface_by_uuid(uuid).destroy
+ end
+ end
+
+ class Mock
+ def destroy_interface(uuid)
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/destroy_network.rb b/lib/fog/libvirt/requests/compute/destroy_network.rb
new file mode 100644
index 0000000..b2c4e0e
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/destroy_network.rb
@@ -0,0 +1,17 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ def destroy_network(uuid)
+ client.lookup_network_by_uuid(uuid).destroy
+ end
+ end
+
+ class Mock
+ def destroy_network(uuid)
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/get_node_info.rb b/lib/fog/libvirt/requests/compute/get_node_info.rb
new file mode 100644
index 0000000..9d5aa67
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/get_node_info.rb
@@ -0,0 +1,37 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/list_domains.rb b/lib/fog/libvirt/requests/compute/list_domains.rb
new file mode 100644
index 0000000..c756b32
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/list_domains.rb
@@ -0,0 +1,105 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/list_interfaces.rb b/lib/fog/libvirt/requests/compute/list_interfaces.rb
new file mode 100644
index 0000000..d938437
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/list_interfaces.rb
@@ -0,0 +1,57 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/list_networks.rb b/lib/fog/libvirt/requests/compute/list_networks.rb
new file mode 100644
index 0000000..5f55c2a
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/list_networks.rb
@@ -0,0 +1,55 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/list_pool_volumes.rb b/lib/fog/libvirt/requests/compute/list_pool_volumes.rb
new file mode 100644
index 0000000..6faba30
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/list_pool_volumes.rb
@@ -0,0 +1,19 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/list_pools.rb b/lib/fog/libvirt/requests/compute/list_pools.rb
new file mode 100644
index 0000000..8113b6a
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/list_pools.rb
@@ -0,0 +1,71 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/list_volumes.rb b/lib/fog/libvirt/requests/compute/list_volumes.rb
new file mode 100644
index 0000000..8c7ac6a
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/list_volumes.rb
@@ -0,0 +1,88 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/mock_files/domain.xml b/lib/fog/libvirt/requests/compute/mock_files/domain.xml
new file mode 100644
index 0000000..7720f1f
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/mock_files/domain.xml
@@ -0,0 +1,40 @@
+<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>
diff --git a/lib/fog/libvirt/requests/compute/pool_action.rb b/lib/fog/libvirt/requests/compute/pool_action.rb
new file mode 100644
index 0000000..942efd0
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/pool_action.rb
@@ -0,0 +1,19 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ def pool_action(uuid, action)
+ pool = client.lookup_storage_pool_by_uuid uuid
+ pool.send(action)
+ true
+ end
+ end
+
+ class Mock
+ def pool_action(uuid, action)
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/update_display.rb b/lib/fog/libvirt/requests/compute/update_display.rb
new file mode 100644
index 0000000..a2141e1
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/update_display.rb
@@ -0,0 +1,31 @@
+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
diff --git a/lib/fog/libvirt/requests/compute/upload_volume.rb b/lib/fog/libvirt/requests/compute/upload_volume.rb
new file mode 100644
index 0000000..ace05e7
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/upload_volume.rb
@@ -0,0 +1,31 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ def upload_volume(pool_name, volume_name, file_path)
+ volume = client.lookup_storage_pool_by_name(pool_name).lookup_volume_by_name(volume_name)
+ stream = client.stream
+
+ image_file = File.open(file_path, "rb")
+ volume.upload(stream, 0, image_file.size)
+ stream.sendall do |_opaque, n|
+ begin
+ r = image_file.read(n)
+ [r.length < n ? 0 : r.length, r]
+ rescue Exception => e
+ [-1, ""]
+ end
+ end
+ stream.finish
+ ensure
+ image_file.close if image_file
+ end
+ end
+
+ class Mock
+ def upload_volume(pool_name, volume_name, file_path)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/vm_action.rb b/lib/fog/libvirt/requests/compute/vm_action.rb
new file mode 100644
index 0000000..3078028
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/vm_action.rb
@@ -0,0 +1,19 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ def vm_action(uuid, action)
+ domain = client.lookup_domain_by_uuid(uuid)
+ domain.send(action)
+ true
+ end
+ end
+
+ class Mock
+ def vm_action(uuid, action)
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/requests/compute/volume_action.rb b/lib/fog/libvirt/requests/compute/volume_action.rb
new file mode 100644
index 0000000..1a3f849
--- /dev/null
+++ b/lib/fog/libvirt/requests/compute/volume_action.rb
@@ -0,0 +1,18 @@
+module Fog
+ module Compute
+ class Libvirt
+ class Real
+ def volume_action(key, action, options={})
+ get_volume({:key => key}, true).send(action)
+ true
+ end
+ end
+
+ class Mock
+ def volume_action(action, options={})
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/libvirt/version.rb b/lib/fog/libvirt/version.rb
new file mode 100644
index 0000000..9d3fec2
--- /dev/null
+++ b/lib/fog/libvirt/version.rb
@@ -0,0 +1,5 @@
+module Fog
+ module Libvirt
+ VERSION = '0.0.2'
+ end
+end
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..77fdffd
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,344 @@
+--- !ruby/object:Gem::Specification
+name: fog-libvirt
+version: !ruby/object:Gem::Version
+ version: 0.0.2
+platform: ruby
+authors:
+- geemus (Wesley Beary)
+autorequire:
+bindir: bin
+cert_chain: []
+date: 2015-06-16 00:00:00.000000000 Z
+dependencies:
+- !ruby/object:Gem::Dependency
+ name: fog-core
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '1.27'
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 1.27.4
+ type: :runtime
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '1.27'
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 1.27.4
+- !ruby/object:Gem::Dependency
+ name: fog-json
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :runtime
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: fog-xml
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 0.1.1
+ type: :runtime
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 0.1.1
+- !ruby/object:Gem::Dependency
+ name: ruby-libvirt
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 0.5.0
+ type: :runtime
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 0.5.0
+- !ruby/object:Gem::Dependency
+ name: json
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :runtime
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: minitest
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: minitest-stub-const
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: pry
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: rake
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: rubocop
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: shindo
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 0.3.4
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 0.3.4
+- !ruby/object:Gem::Dependency
+ name: simplecov
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: yard
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+- !ruby/object:Gem::Dependency
+ name: mocha
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 1.1.0
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: 1.1.0
+description: This library can be used as a module for 'fog' or as standalone libvirt
+ provider.
+email: geemus at gmail.com
+executables: []
+extensions: []
+extra_rdoc_files:
+- README.md
+files:
+- CONTRIBUTORS.md
+- Gemfile
+- LICENSE.md
+- README.md
+- Rakefile
+- fog-libvirt.gemspec
+- lib/fog/bin/libvirt.rb
+- lib/fog/libvirt.rb
+- lib/fog/libvirt/compute.rb
+- lib/fog/libvirt/models/compute/README.md
+- lib/fog/libvirt/models/compute/interface.rb
+- lib/fog/libvirt/models/compute/interfaces.rb
+- lib/fog/libvirt/models/compute/network.rb
+- lib/fog/libvirt/models/compute/networks.rb
+- lib/fog/libvirt/models/compute/nic.rb
+- lib/fog/libvirt/models/compute/nics.rb
+- lib/fog/libvirt/models/compute/node.rb
+- lib/fog/libvirt/models/compute/nodes.rb
+- lib/fog/libvirt/models/compute/pool.rb
+- lib/fog/libvirt/models/compute/pools.rb
+- lib/fog/libvirt/models/compute/server.rb
+- lib/fog/libvirt/models/compute/servers.rb
+- lib/fog/libvirt/models/compute/templates/network.xml.erb
+- lib/fog/libvirt/models/compute/templates/pool.xml.erb
+- lib/fog/libvirt/models/compute/templates/server.xml.erb
+- lib/fog/libvirt/models/compute/templates/volume.xml.erb
+- lib/fog/libvirt/models/compute/util/uri.rb
+- lib/fog/libvirt/models/compute/util/util.rb
+- lib/fog/libvirt/models/compute/volume.rb
+- lib/fog/libvirt/models/compute/volumes.rb
+- lib/fog/libvirt/requests/compute/clone_volume.rb
+- lib/fog/libvirt/requests/compute/create_domain.rb
+- lib/fog/libvirt/requests/compute/create_volume.rb
+- lib/fog/libvirt/requests/compute/define_domain.rb
+- lib/fog/libvirt/requests/compute/define_pool.rb
+- lib/fog/libvirt/requests/compute/destroy_interface.rb
+- lib/fog/libvirt/requests/compute/destroy_network.rb
+- lib/fog/libvirt/requests/compute/get_node_info.rb
+- lib/fog/libvirt/requests/compute/list_domains.rb
+- lib/fog/libvirt/requests/compute/list_interfaces.rb
+- lib/fog/libvirt/requests/compute/list_networks.rb
+- lib/fog/libvirt/requests/compute/list_pool_volumes.rb
+- lib/fog/libvirt/requests/compute/list_pools.rb
+- lib/fog/libvirt/requests/compute/list_volumes.rb
+- lib/fog/libvirt/requests/compute/mock_files/domain.xml
+- lib/fog/libvirt/requests/compute/pool_action.rb
+- lib/fog/libvirt/requests/compute/update_display.rb
+- lib/fog/libvirt/requests/compute/upload_volume.rb
+- lib/fog/libvirt/requests/compute/vm_action.rb
+- lib/fog/libvirt/requests/compute/volume_action.rb
+- lib/fog/libvirt/version.rb
+- minitests/server/user_data_iso_test.rb
+- minitests/test_helper.rb
+- tests/helper.rb
+- tests/helpers/formats_helper.rb
+- tests/helpers/formats_helper_tests.rb
+- tests/helpers/mock_helper.rb
+- tests/helpers/succeeds_helper.rb
+- tests/libvirt/compute_tests.rb
+- tests/libvirt/models/compute/interface_tests.rb
+- tests/libvirt/models/compute/interfaces_tests.rb
+- tests/libvirt/models/compute/network_tests.rb
+- tests/libvirt/models/compute/networks_tests.rb
+- tests/libvirt/models/compute/nic_tests.rb
+- tests/libvirt/models/compute/nics_tests.rb
+- tests/libvirt/models/compute/pool_tests.rb
+- tests/libvirt/models/compute/pools_tests.rb
+- tests/libvirt/models/compute/server_tests.rb
+- tests/libvirt/models/compute/servers_tests.rb
+- tests/libvirt/models/compute/volume_tests.rb
+- tests/libvirt/models/compute/volumes_tests.rb
+- tests/libvirt/requests/compute/create_domain_tests.rb
+- tests/libvirt/requests/compute/define_domain_tests.rb
+- tests/libvirt/requests/compute/update_display.rb
+homepage: http://github.com/fog/fog-libvirt
+licenses:
+- MIT
+metadata: {}
+post_install_message:
+rdoc_options:
+- "--charset=UTF-8"
+require_paths:
+- lib
+required_ruby_version: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+required_rubygems_version: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+requirements: []
+rubyforge_project:
+rubygems_version: 2.2.2
+signing_key:
+specification_version: 2
+summary: Module for the 'fog' gem to support libvirt
+test_files:
+- tests/helper.rb
+- tests/helpers/formats_helper.rb
+- tests/helpers/formats_helper_tests.rb
+- tests/helpers/mock_helper.rb
+- tests/helpers/succeeds_helper.rb
+- tests/libvirt/compute_tests.rb
+- tests/libvirt/models/compute/interface_tests.rb
+- tests/libvirt/models/compute/interfaces_tests.rb
+- tests/libvirt/models/compute/network_tests.rb
+- tests/libvirt/models/compute/networks_tests.rb
+- tests/libvirt/models/compute/nic_tests.rb
+- tests/libvirt/models/compute/nics_tests.rb
+- tests/libvirt/models/compute/pool_tests.rb
+- tests/libvirt/models/compute/pools_tests.rb
+- tests/libvirt/models/compute/server_tests.rb
+- tests/libvirt/models/compute/servers_tests.rb
+- tests/libvirt/models/compute/volume_tests.rb
+- tests/libvirt/models/compute/volumes_tests.rb
+- tests/libvirt/requests/compute/create_domain_tests.rb
+- tests/libvirt/requests/compute/define_domain_tests.rb
+- tests/libvirt/requests/compute/update_display.rb
+has_rdoc:
diff --git a/minitests/server/user_data_iso_test.rb b/minitests/server/user_data_iso_test.rb
new file mode 100644
index 0000000..d57b99d
--- /dev/null
+++ b/minitests/server/user_data_iso_test.rb
@@ -0,0 +1,69 @@
+require 'test_helper'
+
+class UserDataIsoTest < Minitest::Test
+ def setup
+ @compute = Fog::Compute[:libvirt]
+ @server = @compute.servers.new(:name => "test")
+ @test_data = "test data"
+ end
+
+ def test_contains_meta_data_file
+ @server.stubs(:system).returns(true)
+ in_a_temp_dir do |d|
+ @server.generate_config_iso_in_dir(d, @test_data) {|iso| assert File.exist?(File.join(d, 'meta-data')) }
+ end
+ end
+
+ def test_contains_user_data_file
+ @server.stubs(:system).returns(true)
+ in_a_temp_dir do |d|
+ @server.generate_config_iso_in_dir(d, @test_data) do |iso|
+ assert File.exist?(File.join(d, 'user-data'))
+ assert_equal @test_data, File.read(File.join(d, 'user-data'))
+ end
+ end
+ end
+
+ def test_iso_is_generated
+ in_a_temp_dir do |d|
+ @server.expects(:system).with(regexp_matches(/^genisoimage/)).returns(true)
+ @server.generate_config_iso_in_dir(d, @test_data) {|iso| }
+ end
+ end
+
+ def test_volume_is_created_during_user_data_iso_generation
+ iso_path = "iso_file_path"
+ @server.stubs(:system).returns(true)
+ Fog::Compute::Libvirt::Volumes.any_instance.expects(:create).
+ with(has_entries(:name => @server.cloud_init_volume_name)).
+ returns(@compute.volumes.new)
+ Fog::Compute::Libvirt::Volume.any_instance.stubs(:upload_image)
+
+ @server.create_user_data_iso
+ end
+
+ def test_volume_is_uploaded_during_user_data_iso_generation
+ iso_path = "iso_file_path"
+ @server.stubs(:system).returns(true)
+ Fog::Compute::Libvirt::Volumes.any_instance.stubs(:create).returns(@compute.volumes.new)
+ Fog::Compute::Libvirt::Volume.any_instance.expects(:upload_image).returns(true)
+
+ @server.create_user_data_iso
+ end
+
+ def test_iso_file_is_set_during_user_data_iso_generation
+ iso_path = "iso_file_path"
+ @server.stubs(:system).returns(true)
+ Fog::Compute::Libvirt::Volumes.any_instance.stubs(:create).returns(@compute.volumes.new)
+ Fog::Compute::Libvirt::Volume.any_instance.stubs(:upload_image)
+
+ @server.create_user_data_iso
+ assert_equal @server.cloud_init_volume_name, @server.iso_file
+ end
+
+ def in_a_temp_dir
+ Dir.mktmpdir('test-dir') do |d|
+ yield d
+ end
+ end
+end
diff --git a/minitests/test_helper.rb b/minitests/test_helper.rb
new file mode 100644
index 0000000..220c848
--- /dev/null
+++ b/minitests/test_helper.rb
@@ -0,0 +1,18 @@
+require 'minitest/autorun'
+require 'mocha/mini_test'
+require 'fileutils'
+
+$: << File.join(File.dirname(__FILE__), '..', 'lib')
+
+logdir = File.join(File.dirname(__FILE__), '..', 'logs')
+FileUtils.mkdir_p(logdir) unless File.exist?(logdir)
+
+ENV['TMPDIR'] = 'test/tmp'
+FileUtils.rm_f Dir.glob 'test/tmp/*.tmp'
+
+require 'fog/libvirt'
+
+Fog.mock!
+Fog.credentials = {
+ :libvirt_uri => 'qemu://libvirt/system',
+}.merge(Fog.credentials)
diff --git a/tests/helper.rb b/tests/helper.rb
new file mode 100644
index 0000000..a6cccdb
--- /dev/null
+++ b/tests/helper.rb
@@ -0,0 +1,17 @@
+ENV['FOG_RC'] = ENV['FOG_RC'] || File.expand_path('../.fog', __FILE__)
+ENV['FOG_CREDENTIAL'] = ENV['FOG_CREDENTIAL'] || 'default'
+
+require 'fog/libvirt'
+
+Excon.defaults.merge!(:debug_request => true, :debug_response => true)
+
+require File.expand_path(File.join(File.dirname(__FILE__), 'helpers', 'mock_helper'))
+
+# This overrides the default 600 seconds timeout during live test runs
+if Fog.mocking?
+ FOG_TESTING_TIMEOUT = ENV['FOG_TEST_TIMEOUT'] || 2000
+ Fog.timeout = 2000
+ Fog::Logger.warning "Setting default fog timeout to #{Fog.timeout} seconds"
+else
+ FOG_TESTING_TIMEOUT = Fog.timeout
+end
diff --git a/tests/helpers/formats_helper.rb b/tests/helpers/formats_helper.rb
new file mode 100644
index 0000000..0053bb5
--- /dev/null
+++ b/tests/helpers/formats_helper.rb
@@ -0,0 +1,98 @@
+require "fog/schema/data_validator"
+
+# format related hackery
+# allows both true.is_a?(Fog::Boolean) and false.is_a?(Fog::Boolean)
+# allows both nil.is_a?(Fog::Nullable::String) and ''.is_a?(Fog::Nullable::String)
+module Fog
+ module Boolean; end
+ module Nullable
+ module Boolean; end
+ module Integer; end
+ module String; end
+ module Time; end
+ module Float; end
+ module Hash; end
+ module Array; end
+ end
+end
+[FalseClass, TrueClass].each {|klass| klass.send(:include, Fog::Boolean)}
+[FalseClass, TrueClass, NilClass, Fog::Boolean].each {|klass| klass.send(:include, Fog::Nullable::Boolean)}
+[NilClass, String].each {|klass| klass.send(:include, Fog::Nullable::String)}
+[NilClass, Time].each {|klass| klass.send(:include, Fog::Nullable::Time)}
+[Integer, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Integer)}
+[Float, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Float)}
+[Hash, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Hash)}
+[Array, NilClass].each {|klass| klass.send(:include, Fog::Nullable::Array)}
+
+module Shindo
+ class Tests
+ # Generates a Shindo test that compares a hash schema to the result
+ # of the passed in block returning true if they match.
+ #
+ # The schema that is passed in is a Hash or Array of hashes that
+ # have Classes in place of values. When checking the schema the
+ # value should match the Class.
+ #
+ # Strict mode will fail if the data has additional keys. Setting
+ # +strict+ to +false+ will allow additional keys to appear.
+ #
+ # @param [Hash] schema A Hash schema
+ # @param [Hash] options Options to change validation rules
+ # @option options [Boolean] :allow_extra_keys
+ # If +true+ does not fail when keys are in the data that are
+ # not specified in the schema. This allows new values to
+ # appear in API output without breaking the check.
+ # @option options [Boolean] :allow_optional_rules
+ # If +true+ does not fail if extra keys are in the schema
+ # that do not match the data. Not recommended!
+ # @yield Data to check with schema
+ #
+ # @example Using in a test
+ # Shindo.tests("comparing welcome data against schema") do
+ # data = {:welcome => "Hello" }
+ # data_matches_schema(:welcome => String) { data }
+ # end
+ #
+ # comparing welcome data against schema
+ # + data matches schema
+ #
+ # @example Example schema
+ # {
+ # "id" => String,
+ # "ram" => Integer,
+ # "disks" => [
+ # {
+ # "size" => Float
+ # }
+ # ],
+ # "dns_name" => Fog::Nullable::String,
+ # "active" => Fog::Boolean,
+ # "created" => DateTime
+ # }
+ #
+ # @return [Boolean]
+ def data_matches_schema(schema, options = {})
+ test('data matches schema') do
+ validator = Fog::Schema::DataValidator.new
+ valid = validator.validate(yield, schema, options)
+ @message = validator.message unless valid
+ valid
+ end
+ end
+
+ # @deprecated #formats is deprecated. Use #data_matches_schema instead
+ def formats(format, strict = true)
+ test('has proper format') do
+ if strict
+ options = {:allow_extra_keys => false, :allow_optional_rules => true}
+ else
+ options = {:allow_extra_keys => true, :allow_optional_rules => true}
+ end
+ validator = Fog::Schema::DataValidator.new
+ valid = validator.validate(yield, format, options)
+ @message = validator.message unless valid
+ valid
+ end
+ end
+ end
+end
diff --git a/tests/helpers/formats_helper_tests.rb b/tests/helpers/formats_helper_tests.rb
new file mode 100644
index 0000000..dba2386
--- /dev/null
+++ b/tests/helpers/formats_helper_tests.rb
@@ -0,0 +1,110 @@
+Shindo.tests('test_helper', 'meta') do
+
+ tests('comparing welcome data against schema') do
+ data = {:welcome => "Hello" }
+ data_matches_schema(:welcome => String) { data }
+ end
+
+ tests('#data_matches_schema') do
+ tests('when value matches schema expectation') do
+ data_matches_schema({"key" => String}) { {"key" => "Value"} }
+ end
+
+ tests('when values within an array all match schema expectation') do
+ data_matches_schema({"key" => [Integer]}) { {"key" => [1, 2]} }
+ end
+
+ tests('when nested values match schema expectation') do
+ data_matches_schema({"key" => {:nested_key => String}}) { {"key" => {:nested_key => "Value"}} }
+ end
+
+ tests('when collection of values all match schema expectation') do
+ data_matches_schema([{"key" => String}]) { [{"key" => "Value"}, {"key" => "Value"}] }
+ end
+
+ tests('when collection is empty although schema covers optional members') do
+ data_matches_schema([{"key" => String}], {:allow_optional_rules => true}) { [] }
+ end
+
+ tests('when additional keys are passed and not strict') do
+ data_matches_schema({"key" => String}, {:allow_extra_keys => true}) { {"key" => "Value", :extra => "Bonus"} }
+ end
+
+ tests('when value is nil and schema expects NilClass') do
+ data_matches_schema({"key" => NilClass}) { {"key" => nil} }
+ end
+
+ tests('when value and schema match as hashes') do
+ data_matches_schema({}) { {} }
+ end
+
+ tests('when value and schema match as arrays') do
+ data_matches_schema([]) { [] }
+ end
+
+ tests('when value is a Time') do
+ data_matches_schema({"time" => Time}) { {"time" => Time.now} }
+ end
+
+ tests('when key is missing but value should be NilClass (#1477)') do
+ data_matches_schema({"key" => NilClass}, {:allow_optional_rules => true}) { {} }
+ end
+
+ tests('when key is missing but value is nullable (#1477)') do
+ data_matches_schema({"key" => Fog::Nullable::String}, {:allow_optional_rules => true}) { {} }
+ end
+ end
+
+ tests('#formats backwards compatible changes') do
+
+ tests('when value matches schema expectation') do
+ formats({"key" => String}) { {"key" => "Value"} }
+ end
+
+ tests('when values within an array all match schema expectation') do
+ formats({"key" => [Integer]}) { {"key" => [1, 2]} }
+ end
+
+ tests('when nested values match schema expectation') do
+ formats({"key" => {:nested_key => String}}) { {"key" => {:nested_key => "Value"}} }
+ end
+
+ tests('when collection of values all match schema expectation') do
+ formats([{"key" => String}]) { [{"key" => "Value"}, {"key" => "Value"}] }
+ end
+
+ tests('when collection is empty although schema covers optional members') do
+ formats([{"key" => String}]) { [] }
+ end
+
+ tests('when additional keys are passed and not strict') do
+ formats({"key" => String}, false) { {"key" => "Value", :extra => "Bonus"} }
+ end
+
+ tests('when value is nil and schema expects NilClass') do
+ formats({"key" => NilClass}) { {"key" => nil} }
+ end
+
+ tests('when value and schema match as hashes') do
+ formats({}) { {} }
+ end
+
+ tests('when value and schema match as arrays') do
+ formats([]) { [] }
+ end
+
+ tests('when value is a Time') do
+ formats({"time" => Time}) { {"time" => Time.now} }
+ end
+
+ tests('when key is missing but value should be NilClass (#1477)') do
+ formats({"key" => NilClass}) { {} }
+ end
+
+ tests('when key is missing but value is nullable (#1477)') do
+ formats({"key" => Fog::Nullable::String}) { {} }
+ end
+
+ end
+
+end
diff --git a/tests/helpers/mock_helper.rb b/tests/helpers/mock_helper.rb
new file mode 100644
index 0000000..0fcaca2
--- /dev/null
+++ b/tests/helpers/mock_helper.rb
@@ -0,0 +1,14 @@
+# Use so you can run in mock mode from the command line
+#
+# FOG_MOCK=true fog
+
+if ENV["FOG_MOCK"] == "true"
+ Fog.mock!
+end
+
+# if in mocked mode, fill in some fake credentials for us
+if Fog.mock?
+ Fog.credentials = {
+ :libvirt_uri => 'qemu://libvirt/system',
+ }.merge(Fog.credentials)
+end
diff --git a/tests/helpers/succeeds_helper.rb b/tests/helpers/succeeds_helper.rb
new file mode 100644
index 0000000..b54589e
--- /dev/null
+++ b/tests/helpers/succeeds_helper.rb
@@ -0,0 +1,9 @@
+module Shindo
+ class Tests
+ def succeeds
+ test('succeeds') do
+ !!instance_eval(&Proc.new)
+ end
+ end
+ end
+end
diff --git a/tests/libvirt/compute_tests.rb b/tests/libvirt/compute_tests.rb
new file mode 100644
index 0000000..ae78b9a
--- /dev/null
+++ b/tests/libvirt/compute_tests.rb
@@ -0,0 +1,17 @@
+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
diff --git a/tests/libvirt/models/compute/interface_tests.rb b/tests/libvirt/models/compute/interface_tests.rb
new file mode 100644
index 0000000..7de6917
--- /dev/null
+++ b/tests/libvirt/models/compute/interface_tests.rb
@@ -0,0 +1,27 @@
+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
diff --git a/tests/libvirt/models/compute/interfaces_tests.rb b/tests/libvirt/models/compute/interfaces_tests.rb
new file mode 100644
index 0000000..a5f7f4b
--- /dev/null
+++ b/tests/libvirt/models/compute/interfaces_tests.rb
@@ -0,0 +1,14 @@
+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
diff --git a/tests/libvirt/models/compute/network_tests.rb b/tests/libvirt/models/compute/network_tests.rb
new file mode 100644
index 0000000..155a598
--- /dev/null
+++ b/tests/libvirt/models/compute/network_tests.rb
@@ -0,0 +1,27 @@
+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
diff --git a/tests/libvirt/models/compute/networks_tests.rb b/tests/libvirt/models/compute/networks_tests.rb
new file mode 100644
index 0000000..6edeb81
--- /dev/null
+++ b/tests/libvirt/models/compute/networks_tests.rb
@@ -0,0 +1,13 @@
+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
diff --git a/tests/libvirt/models/compute/nic_tests.rb b/tests/libvirt/models/compute/nic_tests.rb
new file mode 100644
index 0000000..290bec2
--- /dev/null
+++ b/tests/libvirt/models/compute/nic_tests.rb
@@ -0,0 +1,31 @@
+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
diff --git a/tests/libvirt/models/compute/nics_tests.rb b/tests/libvirt/models/compute/nics_tests.rb
new file mode 100644
index 0000000..186dfcd
--- /dev/null
+++ b/tests/libvirt/models/compute/nics_tests.rb
@@ -0,0 +1,10 @@
+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
diff --git a/tests/libvirt/models/compute/pool_tests.rb b/tests/libvirt/models/compute/pool_tests.rb
new file mode 100644
index 0000000..03946ab
--- /dev/null
+++ b/tests/libvirt/models/compute/pool_tests.rb
@@ -0,0 +1,27 @@
+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
diff --git a/tests/libvirt/models/compute/pools_tests.rb b/tests/libvirt/models/compute/pools_tests.rb
new file mode 100644
index 0000000..6fe3fb8
--- /dev/null
+++ b/tests/libvirt/models/compute/pools_tests.rb
@@ -0,0 +1,13 @@
+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
diff --git a/tests/libvirt/models/compute/server_tests.rb b/tests/libvirt/models/compute/server_tests.rb
new file mode 100644
index 0000000..ac5d035
--- /dev/null
+++ b/tests/libvirt/models/compute/server_tests.rb
@@ -0,0 +1,57 @@
+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
diff --git a/tests/libvirt/models/compute/servers_tests.rb b/tests/libvirt/models/compute/servers_tests.rb
new file mode 100644
index 0000000..905aa75
--- /dev/null
+++ b/tests/libvirt/models/compute/servers_tests.rb
@@ -0,0 +1,14 @@
+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
diff --git a/tests/libvirt/models/compute/volume_tests.rb b/tests/libvirt/models/compute/volume_tests.rb
new file mode 100644
index 0000000..735a5f3
--- /dev/null
+++ b/tests/libvirt/models/compute/volume_tests.rb
@@ -0,0 +1,38 @@
+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
diff --git a/tests/libvirt/models/compute/volumes_tests.rb b/tests/libvirt/models/compute/volumes_tests.rb
new file mode 100644
index 0000000..6f29786
--- /dev/null
+++ b/tests/libvirt/models/compute/volumes_tests.rb
@@ -0,0 +1,14 @@
+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
diff --git a/tests/libvirt/requests/compute/create_domain_tests.rb b/tests/libvirt/requests/compute/create_domain_tests.rb
new file mode 100644
index 0000000..0f1cfe9
--- /dev/null
+++ b/tests/libvirt/requests/compute/create_domain_tests.rb
@@ -0,0 +1,21 @@
+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
diff --git a/tests/libvirt/requests/compute/define_domain_tests.rb b/tests/libvirt/requests/compute/define_domain_tests.rb
new file mode 100644
index 0000000..f581642
--- /dev/null
+++ b/tests/libvirt/requests/compute/define_domain_tests.rb
@@ -0,0 +1,11 @@
+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
diff --git a/tests/libvirt/requests/compute/update_display.rb b/tests/libvirt/requests/compute/update_display.rb
new file mode 100644
index 0000000..1ca8e7f
--- /dev/null
+++ b/tests/libvirt/requests/compute/update_display.rb
@@ -0,0 +1,13 @@
+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
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-fog-libvirt.git
More information about the Pkg-ruby-extras-commits
mailing list