module Fog::Libvirt::Compute::Shared

Attributes

client[R]
uri[R]

Public Class Methods

new(options={}) click to toggle source
Calls superclass method
# File lib/fog/libvirt/compute.rb, line 56
def initialize(options={})
  super()
  @uri = ::Fog::Libvirt::Util::URI.new(enhance_uri(options[:libvirt_uri]))

  # 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

Public Instance Methods

catchLibvirtExceptions() { || ... } click to toggle source

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.

# File lib/fog/libvirt/requests/compute/list_domains.rb, line 23
def catchLibvirtExceptions
  yield
rescue ::Libvirt::RetrieveError, ::Libvirt::Error
  nil
end
clone_volume(pool_name, xml, name) click to toggle source
# File lib/fog/libvirt/requests/compute/clone_volume.rb, line 5
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
create_domain(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/create_domain.rb, line 5
def create_domain(xml)
  client.create_domain_xml(xml)
end
create_volume(pool_name, xml) click to toggle source
# File lib/fog/libvirt/requests/compute/create_volume.rb, line 5
def create_volume(pool_name, xml)
  client.lookup_storage_pool_by_name(pool_name).create_vol_xml(xml)
end
define_domain(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/define_domain.rb, line 5
def define_domain(xml)
  client.define_domain_xml(xml)
end
define_pool(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/define_pool.rb, line 5
def define_pool(xml)
  client.define_storage_pool_xml(xml)
end
destroy_interface(uuid) click to toggle source

shutdown the interface

# File lib/fog/libvirt/requests/compute/destroy_interface.rb, line 6
def destroy_interface(uuid)
  client.lookup_interface_by_uuid(uuid).destroy
end
destroy_network(uuid) click to toggle source
# File lib/fog/libvirt/requests/compute/destroy_network.rb, line 5
def destroy_network(uuid)
  client.lookup_network_by_uuid(uuid).destroy
end
enhance_uri(uri) click to toggle source
# File lib/fog/libvirt/compute.rb, line 91
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 and
  # if the socket exists

  socketpath="/var/run/libvirt/libvirt-sock"
  if RUBY_PLATFORM =~ /darwin/ && File.exist?(socketpath)
    querystring=::URI.parse(uri).query
    if querystring.nil?
      append="?socket=#{socketpath}"
    elsif !::CGI.parse(querystring).key?("socket")
      append="&socket=#{socketpath}"
    end
  end
  uri+append
end
get_node_info() click to toggle source
# File lib/fog/libvirt/requests/compute/get_node_info.rb, line 5
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
libversion() click to toggle source
# File lib/fog/libvirt/requests/compute/libversion.rb, line 6
def libversion()
  client.libversion
end
list_domains(filter = { }) click to toggle source
# File lib/fog/libvirt/requests/compute/list_domains.rb, line 5
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
list_interfaces(filter = { }) click to toggle source
# File lib/fog/libvirt/requests/compute/list_interfaces.rb, line 5
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
list_networks(filter = { }) click to toggle source
# File lib/fog/libvirt/requests/compute/list_networks.rb, line 5
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
list_pool_volumes(uuid) click to toggle source
# File lib/fog/libvirt/requests/compute/list_pool_volumes.rb, line 5
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
list_pools(filter = { }) click to toggle source
# File lib/fog/libvirt/requests/compute/list_pools.rb, line 5
def list_pools(filter = { })
  data=[]
  if filter.key?(:name)
    data << find_pool_by_name(filter[:name], filter[:include_inactive])
  elsif filter.key?(:uuid)
    data << find_pool_by_uuid(filter[:uuid], filter[:include_inactive])
  else
    (client.list_storage_pools + client.list_defined_storage_pools).each do |name|
      data << find_pool_by_name(name, filter[:include_inactive])
    end
  end
  data.compact
end
list_volumes(filter = { }) click to toggle source
# File lib/fog/libvirt/requests/compute/list_volumes.rb, line 5
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
    data << get_volume(filter)
  end
  data.compact
end
pool_action(uuid, action) click to toggle source
# File lib/fog/libvirt/requests/compute/pool_action.rb, line 5
def pool_action(uuid, action)
  pool = client.lookup_storage_pool_by_uuid uuid
  pool.send(action)
  true
end
terminate() click to toggle source
# File lib/fog/libvirt/compute.rb, line 87
def terminate
  @client.close if @client and !@client.closed?
end
update_autostart(uuid, value) click to toggle source
# File lib/fog/libvirt/requests/compute/update_autostart.rb, line 5
def update_autostart(uuid, value)
  domain = client.lookup_domain_by_uuid(uuid)
  domain.autostart = value
end
update_display(options = { }) click to toggle source
# File lib/fog/libvirt/requests/compute/update_display.rb, line 5
def update_display(options = { })
  raise ArgumentError, "uuid is a required parameter" unless options.key? :uuid

  domain = client.lookup_domain_by_uuid(options[: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'
  new_keymap       = options[:keymap] || xml_elements(domain.xml_desc, "graphics", "keymap")[0]
  display[:keymap] = new_keymap unless new_keymap.nil?

  builder = Nokogiri::XML::Builder.new { graphics_ (display) }
  xml     = Nokogiri::XML(builder.to_xml).root.to_s

  domain.update_device(xml, 0)
  # if we got no exceptions, then we're good'
  true
end
upload_volume(pool_name, volume_name, file_path) click to toggle source
# File lib/fog/libvirt/requests/compute/upload_volume.rb, line 5
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
vm_action(uuid, action, *params) click to toggle source
# File lib/fog/libvirt/requests/compute/vm_action.rb, line 5
def vm_action(uuid, action, *params)
  domain = client.lookup_domain_by_uuid(uuid)
  domain.send(action, *params)
  true
end
volume_action(key, action, options={}) click to toggle source
# File lib/fog/libvirt/requests/compute/volume_action.rb, line 5
def volume_action(key, action, options={})
  get_volume({:key => key}, true).send(action)
  true
end

Private Instance Methods

boot_order(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/list_domains.rb, line 45
def boot_order xml
  xml_elements(xml, "domain/os/boot", "dev")
end
bytes_to_gb(bytes) click to toggle source
# File lib/fog/libvirt/requests/compute/list_volumes.rb, line 47
def bytes_to_gb bytes
  bytes / 1024**3
end
domain_display(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/list_domains.rb, line 31
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
domain_interfaces(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/list_domains.rb, line 67
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
domain_to_attributes(dom) click to toggle source
# File lib/fog/libvirt/requests/compute/list_domains.rb, line 80
def domain_to_attributes(dom)
  states= %w(nostate running blocked paused shutting-down shutoff crashed pmsuspended)

  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],
      :firmware        => firmware(dom.xml_desc),
      :secure_boot     => secure_boot_enabled?(dom.xml_desc),
    }
  rescue ::Libvirt::RetrieveError, ::Libvirt::Error
    # Catch libvirt exceptions to avoid race conditions involving
    # concurrent libvirt operations (like from another process)
    return nil
  end
end
domain_volumes(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/list_domains.rb, line 39
def domain_volumes xml
  xml_elements(xml, "domain/devices/disk/source").map do |element|
    element[:file] || element[:dev] || element[:name]
  end
end
find_pool_by_name(name, include_inactive) click to toggle source
# File lib/fog/libvirt/requests/compute/list_pools.rb, line 21
def find_pool_by_name name, include_inactive
  pool_to_attributes(client.lookup_storage_pool_by_name(name), include_inactive)
rescue ::Libvirt::RetrieveError
  nil
end
find_pool_by_uuid(uuid, include_inactive) click to toggle source
# File lib/fog/libvirt/requests/compute/list_pools.rb, line 27
def find_pool_by_uuid uuid, include_inactive
  pool_to_attributes(client.lookup_storage_pool_by_uuid(uuid), include_inactive)
rescue ::Libvirt::RetrieveError
  nil
end
firmware(xml) click to toggle source
# File lib/fog/libvirt/requests/compute/list_domains.rb, line 49
def firmware(xml)
  firmware_from_loader = xml_elements(xml, "domain/os/loader", "type").first

  case firmware_from_loader
  when 'pflash'
    'efi'
  when 'rom'
    'bios'
  else
    xml_elements(xml, "domain/os", "firmware").first || 'bios'
  end
end
get_interface_by_filter(filter) click to toggle source

Retrieve the interface by mac or by name

# File lib/fog/libvirt/requests/compute/list_interfaces.rb, line 21
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
get_network_by_filter(filter) click to toggle source

Retrieve the network by uuid or name

# File lib/fog/libvirt/requests/compute/list_networks.rb, line 19
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
get_volume(filter = { }) click to toggle source
# File lib/fog/libvirt/requests/compute/list_volumes.rb, line 58
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

  nil
end
interface_to_attributes(net) click to toggle source
# File lib/fog/libvirt/requests/compute/list_interfaces.rb, line 30
def interface_to_attributes(net)
  return if net.nil? || net.name == 'lo'
  {
    :mac    => net.mac,
    :name   => net.name,
    :active => net.active?
  }
end
network_to_attributes(net) click to toggle source

bridge name may not be defined in some networks, we should skip that in such case

# File lib/fog/libvirt/requests/compute/list_networks.rb, line 29
def network_to_attributes(net)
  return if net.nil?

  begin
    bridge_name = net.bridge_name
  rescue ::Libvirt::Error
    bridge_name = ''
  end

  {
    :uuid        => net.uuid,
    :name        => net.name,
    :bridge_name => bridge_name
  }
end
node_attr(attr, xml) click to toggle source
# File lib/fog/libvirt/requests/compute/get_node_info.rb, line 26
def node_attr attr, xml
  xml_element(xml, "sysinfo/system/entry[@name='#{attr}']").strip
end
pool_to_attributes(pool, include_inactive = nil) click to toggle source
# File lib/fog/libvirt/requests/compute/list_pools.rb, line 33
def pool_to_attributes(pool, include_inactive = nil)
  return nil unless pool.active? || include_inactive

  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.active? ? pool.num_of_volumes : nil,
    :state          => states[pool.info.state]
  }
end
raw_volumes() { |pool| ... } click to toggle source
# File lib/fog/libvirt/requests/compute/list_volumes.rb, line 51
def raw_volumes
  client.list_storage_pools.each do |pool_name|
    pool = client.lookup_storage_pool_by_name(pool_name)
    yield(pool)
  end
end
secure_boot_enabled?(xml) click to toggle source

we rely on the fact that the secure attribute is only present when secure boot is enabled

# File lib/fog/libvirt/requests/compute/list_domains.rb, line 63
def secure_boot_enabled?(xml)
  xml_elements(xml, "domain/os/loader", "secure").first == 'yes'
end
volume_to_attributes(vol) click to toggle source
# File lib/fog/libvirt/requests/compute/list_volumes.rb, line 27
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