module Vmpooler::API::Helpers

Public Instance Methods

authenticate(auth, username_str, password_str) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 77
def authenticate(auth, username_str, password_str)
  case auth['provider']
  when 'dummy'
    return (username_str != password_str)
  when 'ldap'
    ldap_base = auth[:ldap]['base']
    ldap_port = auth[:ldap]['port'] || 389
    ldap_user_obj = auth[:ldap]['user_object']
    ldap_host = auth[:ldap]['host']
    ldap_encryption_hash = auth[:ldap]['encryption'] || {
      :method => :start_tls,
      :tls_options => { :ssl_version => 'TLSv1' }
    }

    unless ldap_base.is_a? Array
      ldap_base = ldap_base.split
    end

    unless ldap_user_obj.is_a? Array
      ldap_user_obj = ldap_user_obj.split
    end

    ldap_base.each do |search_base|
      ldap_user_obj.each do |search_user_obj|
        result = authenticate_ldap(
          ldap_port,
          ldap_host,
          ldap_encryption_hash,
          search_user_obj,
          search_base,
          username_str,
          password_str
        )
        return true if result
      end
    end

    return false
  end
end
authenticate_ldap(port, host, encryption_hash, user_object, base, username_str, password_str) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 59
def authenticate_ldap(port, host, encryption_hash, user_object, base, username_str, password_str)
  ldap = Net::LDAP.new(
    :host => host,
    :port => port,
    :encryption => encryption_hash,
    :base => base,
    :auth => {
      :method => :simple,
      :username => "#{user_object}=#{username_str},#{base}",
      :password => password_str
    }
  )

  return true if ldap.bind

  return false
end
authorized?() click to toggle source
# File lib/vmpooler/api/helpers.rb, line 45
def authorized?
  @auth ||= Rack::Auth::Basic::Request.new(request.env)

  if @auth.provided? and @auth.basic? and @auth.credentials
    username, password = @auth.credentials

    if authenticate(Vmpooler::API.settings.config[:auth], username, password)
      return true
    end
  end

  return false
end
export_tags(backend, hostname, tags) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 118
def export_tags(backend, hostname, tags)
  backend.pipelined do
    tags.each_pair do |tag, value|
      next if value.nil? or value.empty?

      backend.hset("vmpooler__vm__#{hostname}", "tag:#{tag}", value)
      backend.hset("vmpooler__tag__#{Date.today}", "#{hostname}:#{tag}", value)
    end
  end
end
filter_tags(tags) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 129
def filter_tags(tags)
  return unless Vmpooler::API.settings.config[:tagfilter]

  tags.each_pair do |tag, value|
    next unless filter = Vmpooler::API.settings.config[:tagfilter][tag]

    tags[tag] = value.match(filter).captures.join if value.match(filter)
  end

  tags
end
get_capacity_metrics(pools, backend) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 209
def get_capacity_metrics(pools, backend)
  capacity = {
      current: 0,
      total: 0,
      percent: 0
  }

  pools.each do |pool|
    capacity[:total] += pool['size'].to_i
  end

  capacity[:current] = get_total_across_pools_redis_scard(pools, 'vmpooler__ready__', backend)

  if capacity[:total] > 0
    capacity[:percent] = (capacity[:current].fdiv(capacity[:total]) * 100.0).round(1)
  end

  capacity
end
get_list_across_pools_redis_hget(pools, key, backend) click to toggle source

Takes the pools and a key to run hget on returns a hash with each pool name as key and the value as string

# File lib/vmpooler/api/helpers.rb, line 194
def get_list_across_pools_redis_hget(pools, key, backend)
  # using pipelined is much faster than querying each of the pools and adding them
  # as we get the result.
  temp_hash = {}
  res = backend.pipelined do
    pools.each do |pool|
      backend.hget(key, pool['name'])
    end
  end
  pools.each_with_index do |pool, i|
    temp_hash[pool['name']] = res[i].to_s
  end
  temp_hash
end
get_list_across_pools_redis_scard(pools, key, backend) click to toggle source

Takes the pools and a key to run scard on returns a hash with each pool name as key and the value being the count as integer

# File lib/vmpooler/api/helpers.rb, line 177
def get_list_across_pools_redis_scard(pools, key, backend)
  # using pipelined is much faster than querying each of the pools and adding them
  # as we get the result.
  temp_hash = {}
  res = backend.pipelined do
    pools.each do |pool|
      backend.scard(key + pool['name'])
    end
  end
  pools.each_with_index do |pool, i|
    temp_hash[pool['name']] = res[i].to_i
  end
  temp_hash
end
get_queue_metrics(pools, backend) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 229
def get_queue_metrics(pools, backend)
  queue = {
      pending: 0,
      cloning: 0,
      booting: 0,
      ready: 0,
      running: 0,
      completed: 0,
      total: 0
  }

  queue[:pending]   = get_total_across_pools_redis_scard(pools, 'vmpooler__pending__', backend)
  queue[:ready]     = get_total_across_pools_redis_scard(pools, 'vmpooler__ready__', backend)
  queue[:running]   = get_total_across_pools_redis_scard(pools, 'vmpooler__running__', backend)
  queue[:completed] = get_total_across_pools_redis_scard(pools, 'vmpooler__completed__', backend)

  queue[:cloning] = backend.get('vmpooler__tasks__clone').to_i + backend.get('vmpooler__tasks__ondemandclone').to_i
  queue[:booting] = queue[:pending].to_i - queue[:cloning].to_i
  queue[:booting] = 0 if queue[:booting] < 0
  queue[:total]   = queue[:pending].to_i + queue[:ready].to_i + queue[:running].to_i + queue[:completed].to_i

  queue
end
get_tag_metrics(backend, date_str, opts = {}) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 253
def get_tag_metrics(backend, date_str, opts = {})
  opts = {:only => false}.merge(opts)

  tags = {}

  backend.hgetall("vmpooler__tag__#{date_str}").each do |key, value|
    hostname = 'unknown'
    tag = 'unknown'

    if key =~ /:/
      hostname, tag = key.split(':', 2)
    end

    next if opts[:only] && tag != opts[:only]

    tags[tag] ||= {}
    tags[tag][value] ||= 0
    tags[tag][value] += 1

    tags[tag]['total'] ||= 0
    tags[tag]['total'] += 1
  end

  tags
end
get_tag_summary(backend, from_date, to_date, opts = {}) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 279
def get_tag_summary(backend, from_date, to_date, opts = {})
  opts = {:only => false}.merge(opts)

  result = {
    tag: {},
    daily: []
  }

  (from_date..to_date).each do |date|
    daily = {
      date: date.to_s,
      tag: get_tag_metrics(backend, date.to_s, opts)
    }
    result[:daily].push(daily)
  end

  result[:daily].each do |daily|
    daily[:tag].each_key do |tag|
      result[:tag][tag] ||= {}

      daily[:tag][tag].each do |key, value|
        result[:tag][tag][key] ||= 0
        result[:tag][tag][key] += value
      end
    end
  end

  result
end
get_task_metrics(backend, task_str, date_str, opts = {}) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 309
def get_task_metrics(backend, task_str, date_str, opts = {})
  opts = {:bypool => false, :only => false}.merge(opts)

  task = {
      duration: {
          average: 0,
          min: 0,
          max: 0,
          total: 0
      },
      count: {
          total: 0
      }
  }

  task[:count][:total] = backend.hlen("vmpooler__#{task_str}__#{date_str}").to_i

  if task[:count][:total] > 0
    if opts[:bypool] == true
      task_times_bypool = {}

      task[:count][:pool]    = {}
      task[:duration][:pool] = {}

      backend.hgetall("vmpooler__#{task_str}__#{date_str}").each do |key, value|
        pool     = 'unknown'
        hostname = 'unknown'

        if key =~ /:/
          pool, hostname = key.split(':')
        else
          hostname = key
        end

        task[:count][:pool][pool]    ||= {}
        task[:duration][:pool][pool] ||= {}

        task_times_bypool[pool] ||= []
        task_times_bypool[pool].push(value.to_f)
      end

      task_times_bypool.each_key do |pool|
        task[:count][:pool][pool][:total] = task_times_bypool[pool].length

        task[:duration][:pool][pool][:total]                                   = task_times_bypool[pool].reduce(:+).to_f
        task[:duration][:pool][pool][:average]                                 = (task[:duration][:pool][pool][:total] / task[:count][:pool][pool][:total]).round(1)
        task[:duration][:pool][pool][:min], task[:duration][:pool][pool][:max] = task_times_bypool[pool].minmax
      end
    end

    task_times = get_task_times(backend, task_str, date_str)

    task[:duration][:total]                      = task_times.reduce(:+).to_f
    task[:duration][:average]                    = (task[:duration][:total] / task[:count][:total]).round(1)
    task[:duration][:min], task[:duration][:max] = task_times.minmax
  end

  if opts[:only]
    task.each_key do |key|
      task.delete(key) unless key.to_s == opts[:only]
    end
  end

  task
end
get_task_summary(backend, task_str, from_date, to_date, opts = {}) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 375
def get_task_summary(backend, task_str, from_date, to_date, opts = {})
  opts = {:bypool => false, :only => false}.merge(opts)

  task_sym = task_str.to_sym

  result = {
    task_sym => {},
    daily: []
  }

  (from_date..to_date).each do |date|
    daily = {
      date: date.to_s,
      task_sym => get_task_metrics(backend, task_str, date.to_s, opts)
    }
    result[:daily].push(daily)
  end

  daily_task = {}
  daily_task_bypool = {} if opts[:bypool] == true

  result[:daily].each do |daily|
    daily[task_sym].each_key do |type|
      result[task_sym][type] ||= {}
      daily_task[type] ||= {}

      ['min', 'max'].each do |key|
        if daily[task_sym][type][key]
          daily_task[type][:data] ||= []
          daily_task[type][:data].push(daily[task_sym][type][key])
        end
      end

      result[task_sym][type][:total] ||= 0
      result[task_sym][type][:total] += daily[task_sym][type][:total]

      if opts[:bypool] == true
        result[task_sym][type][:pool] ||= {}
        daily_task_bypool[type] ||= {}

        next unless daily[task_sym][type][:pool]

        daily[task_sym][type][:pool].each_key do |pool|
          result[task_sym][type][:pool][pool] ||= {}
          daily_task_bypool[type][pool] ||= {}

          ['min', 'max'].each do |key|
            if daily[task_sym][type][:pool][pool][key.to_sym]
              daily_task_bypool[type][pool][:data] ||= []
              daily_task_bypool[type][pool][:data].push(daily[task_sym][type][:pool][pool][key.to_sym])
            end
          end

          result[task_sym][type][:pool][pool][:total] ||= 0
          result[task_sym][type][:pool][pool][:total] += daily[task_sym][type][:pool][pool][:total]
        end
      end
    end
  end

  result[task_sym].each_key do |type|
    if daily_task[type][:data]
      result[task_sym][type][:min], result[task_sym][type][:max] = daily_task[type][:data].minmax
      result[task_sym][type][:average] = mean(daily_task[type][:data])
    end

    if opts[:bypool] == true
      result[task_sym].each_key do |type|
        result[task_sym][type][:pool].each_key do |pool|
          if daily_task_bypool[type][pool][:data]
            result[task_sym][type][:pool][pool][:min], result[task_sym][type][:pool][pool][:max] = daily_task_bypool[type][pool][:data].minmax
            result[task_sym][type][:pool][pool][:average] = mean(daily_task_bypool[type][pool][:data])
          end
        end
      end
    end
  end

  result
end
get_task_times(backend, task, date_str) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 158
def get_task_times(backend, task, date_str)
  backend.hvals("vmpooler__#{task}__" + date_str).map(&:to_f)
end
get_total_across_pools_redis_scard(pools, key, backend) click to toggle source

Takes the pools and a key to run scard on returns an integer for the total count

# File lib/vmpooler/api/helpers.rb, line 164
def get_total_across_pools_redis_scard(pools, key, backend)
  # using pipelined is much faster than querying each of the pools and adding them
  # as we get the result.
  res = backend.pipelined do
    pools.each do |pool|
      backend.scard(key + pool['name'])
    end
  end
  res.inject(0) { |m, x| m + x }.to_i
end
has_token?() click to toggle source
# File lib/vmpooler/api/helpers.rb, line 9
def has_token?
  request.env['HTTP_X_AUTH_TOKEN'].nil? ? false : true
end
hostname_shorten(hostname, domain=nil) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 150
def hostname_shorten(hostname, domain=nil)
  if domain && hostname =~ /^[\w-]+\.#{domain}$/
    hostname = hostname[/[^.]+/]
  end

  hostname
end
is_integer?(x) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 474
def is_integer?(x)
  Integer(x)
  true
rescue StandardError
  false
end
mean(list) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 141
def mean(list)
  s = list.map(&:to_f).reduce(:+).to_f
  (s > 0 && list.length > 0) ? s / list.length.to_f : 0
end
open_socket(host, domain = nil, timeout = 1, port = 22) { |sock| ... } click to toggle source
# File lib/vmpooler/api/helpers.rb, line 481
def open_socket(host, domain = nil, timeout = 1, port = 22, &_block)
  Timeout.timeout(timeout) do
    target_host = host
    target_host = "#{host}.#{domain}" if domain
    sock = TCPSocket.new target_host, port
    begin
      yield sock if block_given?
    ensure
      sock.close
    end
  end
end
pool_index(pools) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 456
def pool_index(pools)
  pools_hash = {}
  index = 0
  pools.each do |pool|
    pools_hash[pool['name']] = index
    index += 1
  end
  pools_hash
end
template_ready?(pool, backend) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 466
def template_ready?(pool, backend)
  prepared_template = backend.hget('vmpooler__template__prepared', pool['name'])
  return false if prepared_template.nil?
  return true if pool['template'] == prepared_template

  return false
end
valid_token?(backend) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 13
def valid_token?(backend)
  return false unless has_token?

  backend.exists?("vmpooler__token__#{request.env['HTTP_X_AUTH_TOKEN']}") ? true : false
end
validate_auth(backend) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 34
def validate_auth(backend)
  return if authorized?

  content_type :json

  result = { 'ok' => false }

  headers['WWW-Authenticate'] = 'Basic realm="Authentication required"'
  halt 401, JSON.pretty_generate(result)
end
validate_date_str(date_str) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 146
def validate_date_str(date_str)
  /^\d{4}-\d{2}-\d{2}$/ === date_str
end
validate_token(backend) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 19
def validate_token(backend)
  if valid_token?(backend)
    backend.hset("vmpooler__token__#{request.env['HTTP_X_AUTH_TOKEN']}", 'last', Time.now)

    return true
  end

  content_type :json

  result = { 'ok' => false }

  headers['WWW-Authenticate'] = 'Basic realm="Authentication required"'
  halt 401, JSON.pretty_generate(result)
end
vm_ready?(vm_name, domain = nil) click to toggle source
# File lib/vmpooler/api/helpers.rb, line 494
def vm_ready?(vm_name, domain = nil)
  begin
    open_socket(vm_name, domain)
  rescue StandardError => _e
    return false
  end

  true
end