class Kitchen::Driver::Opennebula

Opennebula driver for Kitchen.

@author Andrew J. Brown <anbrown@blackberry.com>

Public Class Methods

new(config) click to toggle source
Calls superclass method
# File lib/kitchen/driver/opennebula.rb, line 62
def initialize(config)
  super
  Fog.timeout = config[:wait_for].to_i
end

Public Instance Methods

converge(state) click to toggle source
Calls superclass method
# File lib/kitchen/driver/opennebula.rb, line 164
def converge(state)
  super
end
create(state) click to toggle source
# File lib/kitchen/driver/opennebula.rb, line 67
def create(state)
  conn = opennebula_connect

  # Ensure we can authenticate with OpenNebula
  rc = conn.client.get_version
  raise(rc.message) if OpenNebula.is_error?(rc)

  # Check if VM is already created.
  if state[:vm_id] && !conn.list_vms({:id => state[:vm_id]}).empty?
    info("OpenNebula instance #{instance.to_str} already created.")
    return
  end

  if config[:template_id].nil? and config[:template_name].nil?
    raise "template_name or template_id not specified in .kitchen.yml"
  elsif !config[:template_id].nil? and !config[:template_name].nil?
    raise "Only one of template_name or template_id should be specified in .kitchen.yml"
  end

  newvm = conn.servers.new
  if config[:template_id]
    newvm.flavor = conn.flavors.get config[:template_id]
  elsif config[:template_name]
    filter = {
      :name  => config[:template_name],
      :uname => config[:template_uname],
      :uid   => config[:template_uid]
    }
    newvm.flavor = conn.flavors.get_by_filter filter
    if !newvm.flavor.nil? and newvm.flavor.length > 1
      raise 'More than one template found.  Please restrict using template_uname'
    end
    newvm.flavor = newvm.flavor.first unless newvm.flavor.nil?
  end
  if newvm.flavor.nil?
    raise "Could not find template to create VM. -- Verify your template filters and one_auth credentials"
  end
  newvm.name = config[:vm_hostname]

  newvm.flavor.user_variables = {} if newvm.flavor.user_variables.nil? || newvm.flavor.user_variables.empty?
  config[:user_variables].each do |key, val|
    newvm.flavor.user_variables[key.to_s] = val
  end

  newvm.flavor.context = {} if newvm.flavor.context.nil? || newvm.flavor.context.empty?
  newvm.flavor.context['SSH_PUBLIC_KEY'] = File.read(config[:public_key_path]).chomp
  newvm.flavor.context['TEST_KITCHEN'] = "YES"
  # Support for overriding context variables in the VM template
  config[:context_variables].each do |key, val|
    newvm.flavor.context[key.to_s] = val
  end
  newvm.flavor.memory = config[:memory]
  newvm.flavor.vcpu = config[:vcpu]
  newvm.flavor.cpu = config[:cpu]

  # TODO: Set up NIC and disk if not specified in template
  vm = newvm.save
  vm.wait_for { ready? }
  state[:vm_id] = vm.id
  state[:hostname] = vm.ip
  state[:username] = config[:username]
  tcp_check(state)
  passwordless_sudo_check(state)
  info("OpenNebula instance #{instance.to_str} created.")
end
destroy(state) click to toggle source
# File lib/kitchen/driver/opennebula.rb, line 172
def destroy(state)
  conn = opennebula_connect
  conn.servers.destroy(state[:vm_id])
end
passwordless_sudo_check(state) click to toggle source
# File lib/kitchen/driver/opennebula.rb, line 139
def passwordless_sudo_check(state)
  if config[:no_passwordless_sudo_check]
    sleep(config[:no_passwordless_sudo_sleep])
  else
    wait_for_passwordless_sudo(state)
  end
  debug("Passwordless sudo ready on #{instance.to_str}")
end
tcp_check(state) click to toggle source
# File lib/kitchen/driver/opennebula.rb, line 133
def tcp_check(state)
  instance.transport.connection(state).wait_until_ready unless config[:no_ssh_tcp_check]
  sleep(config[:no_ssh_tcp_check_sleep]) if config[:no_ssh_tcp_check]
  debug("SSH ready on #{instance.to_str}")
end
verify(state) click to toggle source
Calls superclass method
# File lib/kitchen/driver/opennebula.rb, line 168
def verify(state)
  super
end
wait_for_passwordless_sudo(state) click to toggle source
# File lib/kitchen/driver/opennebula.rb, line 148
def wait_for_passwordless_sudo(state)
  retries = config[:passwordless_sudo_timeout] || 300
  retry_interval = config[:passwordless_sudo_retry_interval] || 10
  begin
    instance.transport.connection(state) do |conn|
      conn.execute('sudo -n true')
    end
  rescue Kitchen::Transport::SshFailed => e
    if (e.message.eql? "SSH exited (1) for command: [sudo -n true]") && (retries >= 0)
      sleep retry_interval
      retry
    end
    raise ActionFailed, e.message
  end
end

Protected Instance Methods

opennebula_connect() click to toggle source
# File lib/kitchen/driver/opennebula.rb, line 179
def opennebula_connect()
  opennebula_creds = nil
  if ENV.has_key?('ONE_AUTH')
    if File.exist?(ENV['ONE_AUTH'])
      opennebula_creds = File.read(ENV['ONE_AUTH'])
    else
      opennebula_creds = ENV['ONE_AUTH']
    end
  elsif File.exist?(config[:oneauth_file])
    opennebula_creds = File.read(config[:oneauth_file])
  else
    raise ActionFailed, "Could not find one_auth file #{config[:oneauth_file]}"
  end
  opennebula_username = opennebula_creds.split(':')[0]
  opennebula_password = opennebula_creds.split(':')[1]
  conn = Fog::Compute.new( {
    :provider => 'OpenNebula',
    :opennebula_username => opennebula_username,
    :opennebula_password => opennebula_password,
    :opennebula_endpoint => config[:opennebula_endpoint]
  } )
  conn
end