fog-libvirt-0.3.0/0000755000004100000410000000000013000261316013756 5ustar www-datawww-datafog-libvirt-0.3.0/Rakefile0000644000004100000410000000542013000261316015424 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/Gemfile0000644000004100000410000000031513000261316015250 0ustar www-datawww-datasource "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 fog-libvirt-0.3.0/tests/0000755000004100000410000000000013000261316015120 5ustar www-datawww-datafog-libvirt-0.3.0/tests/helper.rb0000644000004100000410000000114013000261316016720 0ustar www-datawww-dataENV['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 fog-libvirt-0.3.0/tests/helpers/0000755000004100000410000000000013000261316016562 5ustar www-datawww-datafog-libvirt-0.3.0/tests/helpers/formats_helper.rb0000644000004100000410000000705613000261316022131 0ustar www-datawww-datarequire "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 fog-libvirt-0.3.0/tests/helpers/succeeds_helper.rb0000644000004100000410000000020613000261316022242 0ustar www-datawww-datamodule Shindo class Tests def succeeds test('succeeds') do !!instance_eval(&Proc.new) end end end end fog-libvirt-0.3.0/tests/helpers/formats_helper_tests.rb0000644000004100000410000000702013000261316023342 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/helpers/mock_helper.rb0000644000004100000410000000047313000261316021403 0ustar www-datawww-data# 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 fog-libvirt-0.3.0/tests/libvirt/0000755000004100000410000000000013000261316016573 5ustar www-datawww-datafog-libvirt-0.3.0/tests/libvirt/requests/0000755000004100000410000000000013000261316020446 5ustar www-datawww-datafog-libvirt-0.3.0/tests/libvirt/requests/compute/0000755000004100000410000000000013000261316022122 5ustar www-datawww-datafog-libvirt-0.3.0/tests/libvirt/requests/compute/dhcp_leases_tests.rb0000644000004100000410000000112513000261316026142 0ustar www-datawww-dataShindo.tests("Fog::Compute[:libvirt] | dhcp_leases request", 'libvirt') do compute = Fog::Compute[:libvirt] tests("DHCP leases response") do response = compute.dhcp_leases("fbd4ac68-cbea-4f95-86ed-22953fd92384", "99:88:77:66:55:44", 0) test("should be an array") { response.kind_of? Array } test("should have one element") { response.length == 1 } test("should have dict elements") { response[0].kind_of? Hash } ["ipaddr", "prefix", "expirytime", "type"].each { |k| test("should have dict elements with required key #{k}") { !response[0][k].nil? } } end end fog-libvirt-0.3.0/tests/libvirt/requests/compute/create_domain_tests.rb0000644000004100000410000000132513000261316026464 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/requests/compute/update_display.rb0000644000004100000410000000061313000261316025456 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/requests/compute/define_domain_tests.rb0000644000004100000410000000047613000261316026461 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/compute_tests.rb0000644000004100000410000000131213000261316022013 0ustar www-datawww-dataShindo.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 dhcp_leases }.each do |request| test("it should respond to #{request}") { compute.respond_to? request } end end end fog-libvirt-0.3.0/tests/libvirt/models/0000755000004100000410000000000013000261316020056 5ustar www-datawww-datafog-libvirt-0.3.0/tests/libvirt/models/compute/0000755000004100000410000000000013000261316021532 5ustar www-datawww-datafog-libvirt-0.3.0/tests/libvirt/models/compute/networks_tests.rb0000644000004100000410000000075713000261316025166 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/server_tests.rb0000644000004100000410000000344513000261316024615 0ustar www-datawww-dataShindo.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 an ip_address action that') do test('returns the latest IP address lease') { server.public_ip_address() == '1.2.5.6' } 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 fog-libvirt-0.3.0/tests/libvirt/models/compute/pool_tests.rb0000644000004100000410000000166013000261316024255 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/volumes_tests.rb0000644000004100000410000000103413000261316024771 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/interface_tests.rb0000644000004100000410000000162713000261316025247 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/nic_tests.rb0000644000004100000410000000170013000261316024050 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/servers_tests.rb0000644000004100000410000000103413000261316024770 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/nics_tests.rb0000644000004100000410000000043513000261316024237 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/pools_tests.rb0000644000004100000410000000102013000261316024426 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/network_tests.rb0000644000004100000410000000213013000261316024766 0ustar www-datawww-dataShindo.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' } test('dhcp_leases') { network.respond_to? 'dhcp_leases' } end tests('have a dhcp_leases action that') do test('returns an array') { network.dhcp_leases('99:88:77:66:55:44', 0).kind_of? Array } 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 fog-libvirt-0.3.0/tests/libvirt/models/compute/volume_tests.rb0000644000004100000410000000241213000261316024607 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/tests/libvirt/models/compute/interfaces_tests.rb0000644000004100000410000000107713000261316025431 0ustar www-datawww-dataShindo.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 fog-libvirt-0.3.0/minitests/0000755000004100000410000000000013000261316015775 5ustar www-datawww-datafog-libvirt-0.3.0/minitests/server/0000755000004100000410000000000013000261316017303 5ustar www-datawww-datafog-libvirt-0.3.0/minitests/server/user_data_iso_test.rb0000644000004100000410000000514713000261316023517 0ustar www-datawww-datarequire '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 test_iso_dir_is_set_during_user_data_iso_generation @server.stubs(:system).returns(true) volume = @compute.volumes.new volume.stubs(:path).returns("/srv/libvirt/#{@server.cloud_init_volume_name}") Fog::Compute::Libvirt::Volumes.any_instance.stubs(:create).returns(volume) Fog::Compute::Libvirt::Volume.any_instance.stubs(:upload_image) @server.create_user_data_iso assert_equal '/srv/libvirt', @server.iso_dir end def in_a_temp_dir Dir.mktmpdir('test-dir') do |d| yield d end end end fog-libvirt-0.3.0/minitests/test_helper.rb0000644000004100000410000000065713000261316020650 0ustar www-datawww-datarequire '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) fog-libvirt-0.3.0/CONTRIBUTORS.md0000644000004100000410000000160113000261316016233 0ustar www-datawww-data* Amos Benari * brookemckim * Carl Caum * Carlos Sanchez * David Wittman * Dominic Cleal * Greg Sutcliffe * James Herdman * Josef Strzibny * Kevin Menard * Konstantin Haase * Kyle Rames * Lance Ivy * Ohad Levy * Patrick Debois * Paul Thornthwaite * Romain Vrignaud * Ryan Davies * Sergio Rubio * Shlomi Zadok * Steve Smith * Vincent Demeester * Wesley Beary fog-libvirt-0.3.0/LICENSE.md0000644000004100000410000000217113000261316015363 0ustar www-datawww-dataThe 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. fog-libvirt-0.3.0/lib/0000755000004100000410000000000013000261316014524 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/0000755000004100000410000000000013000261316015277 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/bin/0000755000004100000410000000000013000261316016047 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/bin/libvirt.rb0000644000004100000410000000302213000261316020044 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt.rb0000644000004100000410000000051413000261316017277 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/0000755000004100000410000000000013000261316016752 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/requests/0000755000004100000410000000000013000261316020625 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/0000755000004100000410000000000013000261316022301 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/mock_files/0000755000004100000410000000000013000261316024414 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/mock_files/domain.xml0000644000004100000410000000155613000261316026414 0ustar www-datawww-data fog-449765558356062 262144 1 hvm fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/get_node_info.rb0000644000004100000410000000200613000261316025423 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/dhcp_leases.rb0000644000004100000410000000213613000261316025102 0ustar www-datawww-datarequire 'socket' module Fog module Compute class Libvirt class Real def dhcp_leases(uuid, mac, flags = 0) client.lookup_network_by_uuid(uuid).dhcp_leases(mac, flags) end end class Mock def dhcp_leases(uuid, mac, flags = 0) leases1 = { 'aa:bb:cc:dd:ee:ff' => [ { 'type' => Socket::AF_INET, 'ipaddr' => '1.2.3.4', 'prefix' => 24, 'expirytime' => 5000 }, { 'type' => Socket::AF_INET, 'ipaddr' => '1.2.5.6', 'prefix' => 24, 'expirytime' => 5005 } ] } leases2 = { '99:88:77:66:55:44' => [ { 'type' => Socket::AF_INET, 'ipaddr' => '10.1.1.5', 'prefix' => 24, 'expirytime' => 50 } ] } networks = { # should match mock net uuid from list_networks.rb 'a29146ea-39b2-412d-8f53-239eef117a32' => leases1, 'fbd4ac68-cbea-4f95-86ed-22953fd92384' => leases2 } if !networks[uuid].nil? return networks[uuid][mac] end end end end end end fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/destroy_interface.rb0000644000004100000410000000047613000261316026346 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/create_volume.rb0000644000004100000410000000045713000261316025466 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/pool_action.rb0000644000004100000410000000051613000261316025136 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/create_domain.rb0000644000004100000410000000042713000261316025423 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/destroy_network.rb0000644000004100000410000000043013000261316026065 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/list_pools.rb0000644000004100000410000000405313000261316025017 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/upload_volume.rb0000644000004100000410000000144613000261316025506 0ustar www-datawww-datamodule 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 ? [r.length, r] : [0, ""] 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/vm_action.rb0000644000004100000410000000051113000261316024602 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/list_pool_volumes.rb0000644000004100000410000000063113000261316026404 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/define_domain.rb0000644000004100000410000000042713000261316025412 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/list_volumes.rb0000644000004100000410000000570013000261316025355 0ustar www-datawww-datamodule 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| begin data << volume_to_attributes(pool.lookup_volume_by_name(volume_name)) rescue ::Libvirt::RetrieveError # Catch libvirt exceptions to avoid race conditions involving # concurrent libvirt operations (like from another process) next end 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" begin { :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), } rescue ::Libvirt::RetrieveError, ::Libvirt::Error return nil # If there are issues during stat of volume file end 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/list_domains.rb0000644000004100000410000001043013000261316025311 0ustar www-datawww-datamodule 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 << catchLibvirtExceptions { client.lookup_domain_by_name(name) } } unless filter[:defined] == false client.list_domains.each { |id| data << catchLibvirtExceptions { client.lookup_domain_by_id(id) } } unless filter[:active] == false end data.compact.map { |d| domain_to_attributes d }.compact end # Catch Libvirt exceptions to avoid race conditions involving # concurrent libvirt operations from other processes. For example, # domains being undefined while fog-libvirt is trying to work with # domain lists. def catchLibvirtExceptions yield rescue ::Libvirt::RetrieveError, ::Libvirt::Error nil 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) begin { :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] } rescue ::Libvirt::RetrieveError, ::Libvirt::Error # Catch libvirt exceptions to avoid race conditions involving # concurrent libvirt operations (like from another process) return nil end 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/update_display.rb0000644000004100000410000000203313000261316025633 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/list_interfaces.rb0000644000004100000410000000301013000261316025776 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/list_networks.rb0000644000004100000410000000273513000261316025544 0ustar www-datawww-datamodule 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={ }) [ { :uuid => 'a29146ea-39b2-412d-8f53-239eef117a32', :name => 'net1', :bridge_name => 'virbr0' }, { :uuid => 'fbd4ac68-cbea-4f95-86ed-22953fd92384', :name => 'net2', :bridge_name => 'virbr1' } ] end end end end end fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/define_pool.rb0000644000004100000410000000036713000261316025117 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/clone_volume.rb0000644000004100000410000000076213000261316025322 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/requests/compute/volume_action.rb0000644000004100000410000000050513000261316025472 0ustar www-datawww-datamodule 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 fog-libvirt-0.3.0/lib/fog/libvirt/version.rb0000644000004100000410000000007413000261316020765 0ustar www-datawww-datamodule Fog module Libvirt VERSION = '0.3.0' end end fog-libvirt-0.3.0/lib/fog/libvirt/models/0000755000004100000410000000000013000261316020235 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/models/compute/0000755000004100000410000000000013000261316021711 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/models/compute/interface.rb0000644000004100000410000000073413000261316024202 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/volume.rb0000644000004100000410000000651313000261316023552 0ustar www-datawww-datarequire '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 => "" # A volume always belongs to a pool, :pool_name => "" # 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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/pools.rb0000644000004100000410000000060113000261316023367 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/servers.rb0000644000004100000410000000066513000261316023736 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/templates/0000755000004100000410000000000013000261316023707 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/models/compute/templates/server.xml.erb0000644000004100000410000000340513000261316026510 0ustar www-datawww-data <%= name %> <%= memory_size %> <%= cpus %> <%= os_type %> <% boot_order.each do |dev| -%> <% end -%> <% volumes.each do |vol| -%> <%# we need to ensure a unique target dev -%> ' bus='virtio'/> <% end -%> <% if iso_file -%>
<% end -%> <% nics.each do |nic| -%> /> <% end -%> listen='<%= display[:listen] %>'<% end %> <% if display[:password] and !(display[:password].empty?) %>passwd='<%=display[:password] %>'<% end %> /> fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/templates/pool.xml.erb0000644000004100000410000000016113000261316026147 0ustar www-datawww-data <%= name %> <%= path %> fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/templates/volume.xml.erb0000644000004100000410000000163113000261316026510 0ustar www-datawww-data <%= name %> <%= split_size_unit(allocation)[0] %> <%= split_size_unit(capacity)[0] %> 0 0 0744 <% if backing_volume -%> <%= backing_volume.path %> 0 0 0744 <% end -%> fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/templates/network.xml.erb0000644000004100000410000000023213000261316026666 0ustar www-datawww-data <%= name %> fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/network.rb0000644000004100000410000000130613000261316023727 0ustar www-datawww-datarequire '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 dhcp_leases(mac, flags = 0) service.dhcp_leases(uuid, mac, flags) 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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/interfaces.rb0000644000004100000410000000062313000261316024362 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/nics.rb0000644000004100000410000000033613000261316023174 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/nic.rb0000644000004100000410000000225313000261316023011 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/util/0000755000004100000410000000000013000261316022666 5ustar www-datawww-datafog-libvirt-0.3.0/lib/fog/libvirt/models/compute/util/uri.rb0000644000004100000410000000474313000261316024022 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/util/util.rb0000644000004100000410000000167113000261316024175 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/volumes.rb0000644000004100000410000000060613000261316023732 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/node.rb0000644000004100000410000000114013000261316023157 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/pool.rb0000644000004100000410000000373613000261316023220 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/server.rb0000644000004100000410000003027713000261316023555 0ustar www-datawww-datarequire 'fog/compute/models/server' require 'fog/libvirt/models/compute/util/util' 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 => "" # 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 begin require 'net/ssh/proxy/command' rescue LoadError Fog::Logger.warning("'net/ssh' missing, please install and try again.") exit(1) end # if this is a direct connection, we don't need a proxy to be set. return nil unless connection.uri.ssh_enabled? user_string= 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 @iso_dir = File.dirname(vol.path) if vol.path 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 ip_address = nil nic = self.nics.find {|nic| nic.mac==mac} if !nic.nil? service.networks.all.each do |net| if net.name == nic.network leases = net.dhcp_leases(mac, 0) # Assume the lease expiring last is the current IP address ip_address = leases.sort_by { |lse| lse["expirytime"] }.last["ipaddr"] if !leases.empty? break end 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 => %w[hd cdrom network], :display => default_display } end def verify_boot_order order = [] valid_boot_media = %w[cdrom fd hd network] if order order.each do |b| raise "invalid boot order, possible values are any combination of: #{valid_boot_media.join(', ')}" unless valid_boot_media.include?(b) end end end def default_display {:port => '-1', :listen => '127.0.0.1', :type => 'vnc', :password => '' } end end end end end fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/README.md0000644000004100000410000000631513000261316023175 0ustar www-datawww-dataThis 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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/nodes.rb0000644000004100000410000000054113000261316023346 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/models/compute/networks.rb0000644000004100000410000000061313000261316024112 0ustar www-datawww-datarequire '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 fog-libvirt-0.3.0/lib/fog/libvirt/compute.rb0000644000004100000410000000764713000261316020771 0ustar www-datawww-datarequire '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 :dhcp_leases 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 fog-libvirt-0.3.0/fog-libvirt.gemspec0000644000004100000410000000425513000261316017555 0ustar www-datawww-data# 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@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.7.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' s.add_dependency("tins", "<= 1.6.0") if RUBY_VERSION < "1.9" # Fedora and derivates need explicit require. # Also we cannot use newer JSON on Ruby 1.8 & 1.9. if RUBY_VERSION < '2.0' s.add_dependency("json", '< 2.0') else s.add_dependency("json") end 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 > "2.0" 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 fog-libvirt-0.3.0/README.md0000644000004100000410000000203313000261316015233 0ustar www-datawww-data# Fog::Libvirt fog-libvirt is a libvirt provider for [fog](https://github.com/fog/fog). [![Build Status](https://secure.travis-ci.org/fog/fog.png?branch=master)](http://travis-ci.org/fog/fog-libvirt) [![Dependency Status](https://gemnasium.com/fog/fog.png)](https://gemnasium.com/fog/fog-libvirt) [![Code Climate](https://codeclimate.com/github/fog/fog.png)](https://codeclimate.com/github/fog/fog-libvirt) [![Gem Version](https://fury-badge.herokuapp.com/rb/fog.png)](http://badge.fury.io/rb/fog-libvirt) [![Gittip](http://img.shields.io/gittip/geemus.png)](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).