This commit is contained in:
Scott Schneider 2015-02-26 12:07:13 -08:00
parent b965ce3a55
commit 6d6dbfa2c8
4 changed files with 620 additions and 557 deletions

View file

@ -1,5 +1,5 @@
module Vmpooler module Vmpooler
class API class API < Sinatra::Base
def initialize def initialize
# Load the configuration file # Load the configuration file
config_file = File.expand_path('vmpooler.yaml') config_file = File.expand_path('vmpooler.yaml')
@ -17,571 +17,42 @@ module Vmpooler
# Connect to Redis # Connect to Redis
$redis = Redis.new(host: $config[:redis]['server']) $redis = Redis.new(host: $config[:redis]['server'])
super()
end end
def execute! set :environment, :production
my_app = Sinatra.new do
set :environment, 'production'
helpers do not_found do
def hostname_shorten(hostname) content_type :json
if $config[:config]['domain'] && hostname =~ /^\w+\.#{$config[:config]['domain']}$/
hostname = hostname[/[^\.]+/]
end
hostname result = {
end ok: false
}
def validate_date_str(date_str) JSON.pretty_generate(result)
/^\d{4}-\d{2}-\d{2}$/ === date_str end
end
def mean(list) get '/' do
s = list.map(&:to_f).reduce(:+).to_f erb :dashboard, locals: {
(s > 0 && list.length > 0) ? s / list.length.to_f : 0 site_name: $config[:config]['site_name'] || '<b>vmpooler</b>'
end }
end end
not_found do %w( dashboard reroute v1 ).each do |lib|
content_type :json begin
require "api/#{lib}"
result = { rescue LoadError
ok: false require File.expand_path(File.join(File.dirname(__FILE__), 'api', lib))
}
JSON.pretty_generate(result)
end
get '/' do
erb :dashboard, locals: {
site_name: $config[:config]['site_name'] || '<b>vmpooler</b>'
}
end
get '/dashboard/stats/vmpooler/pool/?' do
content_type :json
result = {}
$config[:pools].each do |pool|
result[pool['name']] ||= Hash.new
result[pool['name']]['size'] = pool['size']
result[pool['name']]['ready'] = $redis.scard('vmpooler__ready__' + pool['name'])
end
if params[:history]
if $config[:graphite]['server']
history ||= Hash.new
begin
buffer = open(
'http://' + $config[:graphite]['server'] + '/render?target=' + $config[:graphite]['prefix'] + '.ready.*&from=-1hour&format=json'
).read
history = JSON.parse(buffer)
history.each do |pool|
if pool['target'] =~ /.*\.(.*)$/
pool['name'] = Regexp.last_match[1]
if result[pool['name']]
pool['last'] = result[pool['name']]['size']
result[pool['name']]['history'] ||= Array.new
pool['datapoints'].each do |metric|
8.times do |_n|
if metric[0]
pool['last'] = metric[0].to_i
result[pool['name']]['history'].push(metric[0].to_i)
else
result[pool['name']]['history'].push(pool['last'])
end
end
end
end
end
end
rescue
end
else
$config[:pools].each do |pool|
result[pool['name']] ||= Hash.new
result[pool['name']]['history'] = [$redis.scard('vmpooler__ready__' + pool['name'])]
end
end
end
JSON.pretty_generate(result)
end
get '/dashboard/stats/vmpooler/running/?' do
content_type :json
result = {}
$config[:pools].each do |pool|
running = $redis.scard('vmpooler__running__' + pool['name'])
pool['major'] = Regexp.last_match[1] if pool['name'] =~ /^(\w+)\-/
result[pool['major']] ||= Hash.new
result[pool['major']]['running'] = result[pool['major']]['running'].to_i + running.to_i
end
if params[:history]
if $config[:graphite]['server']
begin
buffer = open(
'http://' + $config[:graphite]['server'] + '/render?target=' + $config[:graphite]['prefix'] + '.running.*&from=-1hour&format=json'
).read
JSON.parse(buffer).each do |pool|
if pool['target'] =~ /.*\.(.*)$/
pool['name'] = Regexp.last_match[1]
pool['major'] = Regexp.last_match[1] if pool['name'] =~ /^(\w+)\-/
result[pool['major']]['history'] ||= Array.new
for i in 0..pool['datapoints'].length
if
pool['datapoints'][i] &&
pool['datapoints'][i][0]
pool['last'] = pool['datapoints'][i][0]
result[pool['major']]['history'][i] ||= 0
result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['datapoints'][i][0].to_i
else
result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['last'].to_i
end
end
end
end
rescue
end
end
end
JSON.pretty_generate(result)
end
get '/status/?' do
content_type :json
result = {
status: {
ok: true,
message: 'Battle station fully armed and operational.'
},
capacity: {
current: 0,
total: 0,
percent: 0
},
clone: {
duration: {
average: 0,
min: 0,
max: 0
},
count: {
total: 0
}
},
queue: {
pending: 0,
cloning: 0,
booting: 0,
ready: 0,
running: 0,
completed: 0,
total: 0
}
}
$config[:pools].each do |pool|
pool['capacity'] = $redis.scard('vmpooler__ready__' + pool['name']).to_i
result[:capacity][:current] += pool['capacity']
result[:capacity][:total] += pool['size'].to_i
if (pool['capacity'] == 0)
result[:status][:empty] ||= []
result[:status][:empty].push(pool['name'])
end
result[:queue][:pending] += $redis.scard('vmpooler__pending__' + pool['name']).to_i
result[:queue][:ready] += $redis.scard('vmpooler__ready__' + pool['name']).to_i
result[:queue][:running] += $redis.scard('vmpooler__running__' + pool['name']).to_i
result[:queue][:completed] += $redis.scard('vmpooler__completed__' + pool['name']).to_i
end
if result[:status][:empty]
result[:status][:ok] = false
result[:status][:message] = "Found #{result[:status][:empty].length} empty pools."
end
result[:capacity][:percent] = ((result[:capacity][:current].to_f / result[:capacity][:total].to_f) * 100.0).round(1) if result[:capacity][:total] > 0
result[:queue][:cloning] = $redis.get('vmpooler__tasks__clone').to_i
result[:queue][:booting] = result[:queue][:pending].to_i - result[:queue][:cloning].to_i
result[:queue][:booting] = 0 if result[:queue][:booting] < 0
result[:queue][:total] = result[:queue][:pending].to_i + result[:queue][:ready].to_i + result[:queue][:running].to_i + result[:queue][:completed].to_i
result[:clone][:count][:total] = $redis.hlen('vmpooler__clone__' + Date.today.to_s).to_i
if result[:clone][:count][:total] > 0
clone_times = $redis.hvals('vmpooler__clone__' + Date.today.to_s).map(&:to_f)
result[:clone][:duration][:average] = (clone_times.reduce(:+).to_f / result[:clone][:count][:total]).round(1)
result[:clone][:duration][:min], result[:clone][:duration][:max] = clone_times.minmax
end
result[:status][:uptime] = (Time.now - $config[:uptime]).round(1) if $config[:uptime]
JSON.pretty_generate(Hash[result.sort_by { |k, _v| k }])
end
get '/summary/?' do
content_type :json
result = {
clone: {
duration: {
average: 0,
min: 0,
max: 0,
total: 0
},
count: {
average: 0,
min: 0,
max: 0,
total: 0
}
},
daily: [] # used for daily info
}
from_param, to_param = params[:from], params[:to]
# Check date formats.
# It is ok if to_param is nil, we will assume this means 'today'
if to_param.nil?
to_param = Date.today.to_s
elsif !validate_date_str(to_param.to_s)
halt 400, 'Invalid "to" date format, must match YYYY-MM-DD'
end
# It is also ok if from_param is nil, we will assume this also means 'today'
if from_param.nil?
from_param = Date.today.to_s
elsif !validate_date_str(from_param.to_s)
halt 400, 'Invalid "from" date format, must match YYYY-MM-DD'
end
from_date, to_date = Date.parse(from_param), Date.parse(to_param)
if to_date < from_date
halt 400, 'Date range is invalid, "to" cannot come before "from".'
elsif from_date > Date.today
halt 400, 'Date range is invalid, "from" must be in the past.'
end
# total clone time for entire duration requested.
min_max_clone_times = [] # min/max clone times from each day.
total_clones_per_day = [] # total clones from each day
total_clone_dur_day = [] # total clone durations from each day
# generate sequence/range for from_date to to_date (inclusive).
# for each date, calculate the day's clone total & average, as well
# as add to total/overall values.
(from_date..to_date).each do |date|
me = {
date: date.to_s,
clone: {
duration: {
average: 0,
min: 0,
max: 0,
total: 0
},
count: {
total: $redis.hlen('vmpooler__clone__' + date.to_s).to_i
}
}
}
# add to daily clone count array
total_clones_per_day.push(me[:clone][:count][:total])
# fetch clone times from redis for this date. convert the results
# to float (numeric).
clone_times = $redis.hvals('vmpooler__clone__' + date.to_s).map(&:to_f)
unless clone_times.nil? or clone_times.length == 0
clone_time = clone_times.reduce(:+).to_f
# add clone time for this date for later processing
total_clone_dur_day.push(clone_time)
me[:clone][:duration][:total] = clone_time
# min and max clone durations for the day.
mi, ma = clone_times.minmax
me[:clone][:duration][:min], me[:clone][:duration][:max] = mi, ma
min_max_clone_times.push(mi, ma)
# if clone_total > 0, calculate clone_average.
# this prevents divide by 0 problems.
if me[:clone][:count][:total] > 0
me[:clone][:duration][:average] = mean(clone_times)
else
me[:clone][:duration][:average] = 0
end
end
# add to daily array
result[:daily].push(me)
end
# again, calc clone_average if we had clones.
unless total_clones_per_day.nil? or total_clones_per_day.length == 0
# totals
result[:clone][:count][:total] = total_clones_per_day.reduce(:+).to_i
result[:clone][:duration][:total] = total_clone_dur_day.reduce(:+).to_f
# averages and other things.
if result[:clone][:count][:total] != 0
result[:clone][:duration][:average] = result[:clone][:duration][:total] / result[:clone][:count][:total]
end
if min_max_clone_times.length > 0
result[:clone][:duration][:min], result[:clone][:duration][:max] = min_max_clone_times.minmax
end
result[:clone][:count][:min], result[:clone][:count][:max] = total_clones_per_day.minmax
result[:clone][:count][:average] = mean(total_clones_per_day)
end
JSON.pretty_generate(result)
end
get '/vm/?' do
content_type :json
result = []
$config[:pools].each do |pool|
result.push(pool['name'])
end
JSON.pretty_generate(result)
end
post '/vm/?' do
content_type :json
result = {}
available = 1
jdata = JSON.parse(request.body.read)
jdata.each do |key, val|
if $redis.scard('vmpooler__ready__' + key) < val.to_i
available = 0
end
end
if (available == 1)
result['ok'] = true
jdata.each do |key, val|
result[key] ||= {}
result[key]['ok'] = true ##
val.to_i.times do |_i|
vm = $redis.spop('vmpooler__ready__' + key)
unless vm.nil?
$redis.sadd('vmpooler__running__' + key, vm)
$redis.hset('vmpooler__active__' + key, vm, Time.now)
result[key] ||= {}
result[key]['ok'] = true ##
if result[key]['hostname']
result[key]['hostname'] = [result[key]['hostname']] unless result[key]['hostname'].is_a?(Array)
result[key]['hostname'].push(vm)
else
result[key]['hostname'] = vm
end
else
result[key]['ok'] = false ##
status 503
result['ok'] = false
end
end
end
else
status 503
result['ok'] = false
end
if result['ok'] && $config[:config]['domain']
result['domain'] = $config[:config]['domain']
end
JSON.pretty_generate(result)
end
post '/vm/:template/?' do
content_type :json
result = {}
request = {}
params[:template].split('+').each do |template|
request[template] ||= 0
request[template] = request[template] + 1
end
available = 1
request.keys.each do |template|
if $redis.scard('vmpooler__ready__' + template) < request[template]
available = 0
end
end
if (available == 1)
result['ok'] = true
params[:template].split('+').each do |template|
result[template] ||= {}
result[template]['ok'] = true ##
vm = $redis.spop('vmpooler__ready__' + template)
unless vm.nil?
$redis.sadd('vmpooler__running__' + template, vm)
$redis.hset('vmpooler__active__' + template, vm, Time.now)
result[template] ||= {}
if result[template]['hostname']
result[template]['hostname'] = [result[template]['hostname']] unless result[template]['hostname'].is_a?(Array)
result[template]['hostname'].push(vm)
else
result[template]['hostname'] = vm
end
else
result[template]['ok'] = false ##
status 503
result['ok'] = false
end
end
else
status 503
result['ok'] = false
end
if result['ok'] && $config[:config]['domain']
result['domain'] = $config[:config]['domain']
end
JSON.pretty_generate(result)
end
get '/vm/:hostname/?' do
content_type :json
result = {}
status 404
result['ok'] = false
params[:hostname] = hostname_shorten(params[:hostname])
if $redis.exists('vmpooler__vm__' + params[:hostname])
stauts 200
result['ok'] = true
result[params[:hostname]] = {}
result[params[:hostname]]['template'] = $redis.hget('vmpooler__vm__' + params[:hostname], 'template')
result[params[:hostname]]['lifetime'] = $redis.hget('vmpooler__vm__' + params[:hostname], 'lifetime') || $config[:config]['vm_lifetime']
result[params[:hostname]]['running'] = ((Time.now - Time.parse($redis.hget('vmpooler__active__' + result[params[:hostname]]['template'], params[:hostname]))) / 60 / 60).round(2)
if $config[:config]['domain']
result[params[:hostname]]['domain'] = $config[:config]['domain']
end
end
JSON.pretty_generate(result)
end
delete '/vm/:hostname/?' do
content_type :json
result = {}
status 404
result['ok'] = false
params[:hostname] = hostname_shorten(params[:hostname])
$config[:pools].each do |pool|
if $redis.sismember('vmpooler__running__' + pool['name'], params[:hostname])
$redis.srem('vmpooler__running__' + pool['name'], params[:hostname])
$redis.sadd('vmpooler__completed__' + pool['name'], params[:hostname])
status 200
result['ok'] = true
end
end
JSON.pretty_generate(result)
end
put '/vm/:hostname/?' do
content_type :json
result = {}
status 404
result['ok'] = false
params[:hostname] = hostname_shorten(params[:hostname])
if $redis.exists('vmpooler__vm__' + params[:hostname])
jdata = JSON.parse(request.body.read)
jdata.each do |param, arg|
case param
when 'lifetime'
arg = arg.to_i
if arg > 0
$redis.hset('vmpooler__vm__' + params[:hostname], param, arg)
status 200
result['ok'] = true
end
end
end
end
JSON.pretty_generate(result)
end
end end
end
my_app.run! use Vmpooler::API::Dashboard
use Vmpooler::API::Reroute
use Vmpooler::API::V1
Thread.new do
run!
end end
end end
end end

View file

@ -0,0 +1,112 @@
module Vmpooler
class API
class Dashboard < Sinatra::Base
get '/dashboard/stats/vmpooler/pool/?' do
content_type :json
result = {}
$config[:pools].each do |pool|
result[pool['name']] ||= {}
result[pool['name']]['size'] = pool['size']
result[pool['name']]['ready'] = $redis.scard('vmpooler__ready__' + pool['name'])
end
if params[:history]
if $config[:graphite]['server']
history ||= {}
begin
buffer = open(
'http://' + $config[:graphite]['server'] + '/render?target=' + $config[:graphite]['prefix'] + '.ready.*&from=-1hour&format=json'
).read
history = JSON.parse(buffer)
history.each do |pool|
if pool['target'] =~ /.*\.(.*)$/
pool['name'] = Regexp.last_match[1]
if result[pool['name']]
pool['last'] = result[pool['name']]['size']
result[pool['name']]['history'] ||= Array.new
pool['datapoints'].each do |metric|
8.times do |_n|
if metric[0]
pool['last'] = metric[0].to_i
result[pool['name']]['history'].push(metric[0].to_i)
else
result[pool['name']]['history'].push(pool['last'])
end
end
end
end
end
end
rescue
end
else
$config[:pools].each do |pool|
result[pool['name']] ||= {}
result[pool['name']]['history'] = [$redis.scard('vmpooler__ready__' + pool['name'])]
end
end
end
JSON.pretty_generate(result)
end
get '/dashboard/stats/vmpooler/running/?' do
content_type :json
result = {}
$config[:pools].each do |pool|
running = $redis.scard('vmpooler__running__' + pool['name'])
pool['major'] = Regexp.last_match[1] if pool['name'] =~ /^(\w+)\-/
result[pool['major']] ||= {}
result[pool['major']]['running'] = result[pool['major']]['running'].to_i + running.to_i
end
if params[:history]
if $config[:graphite]['server']
begin
buffer = open(
'http://' + $config[:graphite]['server'] + '/render?target=' + $config[:graphite]['prefix'] + '.running.*&from=-1hour&format=json'
).read
JSON.parse(buffer).each do |pool|
if pool['target'] =~ /.*\.(.*)$/
pool['name'] = Regexp.last_match[1]
pool['major'] = Regexp.last_match[1] if pool['name'] =~ /^(\w+)\-/
result[pool['major']]['history'] ||= Array.new
for i in 0..pool['datapoints'].length
if
pool['datapoints'][i] &&
pool['datapoints'][i][0]
pool['last'] = pool['datapoints'][i][0]
result[pool['major']]['history'][i] ||= 0
result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['datapoints'][i][0].to_i
else
result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['last'].to_i
end
end
end
end
rescue
end
end
end
JSON.pretty_generate(result)
end
end
end
end

View file

@ -0,0 +1,39 @@
module Vmpooler
class API
class Reroute < Sinatra::Base
api_version = '1'
get '/status/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/status")
end
get '/summary/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/summary")
end
get '/vm/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm")
end
post '/vm/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm")
end
post '/vm/:template/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm/#{params[:template]}")
end
get '/vm/:hostname/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm/#{params[:hostname]}")
end
delete '/vm/:hostname/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm/#{params[:hostname]}")
end
put '/vm/:hostname/?' do
call env.merge("PATH_INFO" => "/api/v#{api_version}/vm/#{params[:hostname]}")
end
end
end
end

441
lib/vmpooler/api/v1.rb Normal file
View file

@ -0,0 +1,441 @@
module Vmpooler
class API
class V1 < Sinatra::Base
api_version = '1'
api_prefix = "/api/v#{api_version}"
helpers do
def hostname_shorten(hostname)
if $config[:config]['domain'] && hostname =~ /^\w+\.#{$config[:config]['domain']}$/
hostname = hostname[/[^\.]+/]
end
hostname
end
def validate_date_str(date_str)
/^\d{4}-\d{2}-\d{2}$/ === date_str
end
def mean(list)
s = list.map(&:to_f).reduce(:+).to_f
(s > 0 && list.length > 0) ? s / list.length.to_f : 0
end
end
get "#{api_prefix}/status/?" do
content_type :json
result = {
status: {
ok: true,
message: 'Battle station fully armed and operational.'
},
capacity: {
current: 0,
total: 0,
percent: 0
},
clone: {
duration: {
average: 0,
min: 0,
max: 0
},
count: {
total: 0
}
},
queue: {
pending: 0,
cloning: 0,
booting: 0,
ready: 0,
running: 0,
completed: 0,
total: 0
}
}
$config[:pools].each do |pool|
pool['capacity'] = $redis.scard('vmpooler__ready__' + pool['name']).to_i
result[:capacity][:current] += pool['capacity']
result[:capacity][:total] += pool['size'].to_i
if (pool['capacity'] == 0)
result[:status][:empty] ||= []
result[:status][:empty].push(pool['name'])
end
result[:queue][:pending] += $redis.scard('vmpooler__pending__' + pool['name']).to_i
result[:queue][:ready] += $redis.scard('vmpooler__ready__' + pool['name']).to_i
result[:queue][:running] += $redis.scard('vmpooler__running__' + pool['name']).to_i
result[:queue][:completed] += $redis.scard('vmpooler__completed__' + pool['name']).to_i
end
if result[:status][:empty]
result[:status][:ok] = false
result[:status][:message] = "Found #{result[:status][:empty].length} empty pools."
end
result[:capacity][:percent] = ((result[:capacity][:current].to_f / result[:capacity][:total].to_f) * 100.0).round(1) if result[:capacity][:total] > 0
result[:queue][:cloning] = $redis.get('vmpooler__tasks__clone').to_i
result[:queue][:booting] = result[:queue][:pending].to_i - result[:queue][:cloning].to_i
result[:queue][:booting] = 0 if result[:queue][:booting] < 0
result[:queue][:total] = result[:queue][:pending].to_i + result[:queue][:ready].to_i + result[:queue][:running].to_i + result[:queue][:completed].to_i
result[:clone][:count][:total] = $redis.hlen('vmpooler__clone__' + Date.today.to_s).to_i
if result[:clone][:count][:total] > 0
clone_times = $redis.hvals('vmpooler__clone__' + Date.today.to_s).map(&:to_f)
result[:clone][:duration][:average] = (clone_times.reduce(:+).to_f / result[:clone][:count][:total]).round(1)
result[:clone][:duration][:min], result[:clone][:duration][:max] = clone_times.minmax
end
result[:status][:uptime] = (Time.now - $config[:uptime]).round(1) if $config[:uptime]
JSON.pretty_generate(Hash[result.sort_by { |k, _v| k }])
end
get "#{api_prefix}/summary/?" do
content_type :json
result = {
clone: {
duration: {
average: 0,
min: 0,
max: 0,
total: 0
},
count: {
average: 0,
min: 0,
max: 0,
total: 0
}
},
daily: [] # used for daily info
}
from_param, to_param = params[:from], params[:to]
# Check date formats.
# It is ok if to_param is nil, we will assume this means 'today'
if to_param.nil?
to_param = Date.today.to_s
elsif !validate_date_str(to_param.to_s)
halt 400, 'Invalid "to" date format, must match YYYY-MM-DD'
end
# It is also ok if from_param is nil, we will assume this also means 'today'
if from_param.nil?
from_param = Date.today.to_s
elsif !validate_date_str(from_param.to_s)
halt 400, 'Invalid "from" date format, must match YYYY-MM-DD'
end
from_date, to_date = Date.parse(from_param), Date.parse(to_param)
if to_date < from_date
halt 400, 'Date range is invalid, "to" cannot come before "from".'
elsif from_date > Date.today
halt 400, 'Date range is invalid, "from" must be in the past.'
end
# total clone time for entire duration requested.
min_max_clone_times = [] # min/max clone times from each day.
total_clones_per_day = [] # total clones from each day
total_clone_dur_day = [] # total clone durations from each day
# generate sequence/range for from_date to to_date (inclusive).
# for each date, calculate the day's clone total & average, as well
# as add to total/overall values.
(from_date..to_date).each do |date|
me = {
date: date.to_s,
clone: {
duration: {
average: 0,
min: 0,
max: 0,
total: 0
},
count: {
total: $redis.hlen('vmpooler__clone__' + date.to_s).to_i
}
}
}
# add to daily clone count array
total_clones_per_day.push(me[:clone][:count][:total])
# fetch clone times from redis for this date. convert the results
# to float (numeric).
clone_times = $redis.hvals('vmpooler__clone__' + date.to_s).map(&:to_f)
unless clone_times.nil? or clone_times.length == 0
clone_time = clone_times.reduce(:+).to_f
# add clone time for this date for later processing
total_clone_dur_day.push(clone_time)
me[:clone][:duration][:total] = clone_time
# min and max clone durations for the day.
mi, ma = clone_times.minmax
me[:clone][:duration][:min], me[:clone][:duration][:max] = mi, ma
min_max_clone_times.push(mi, ma)
# if clone_total > 0, calculate clone_average.
# this prevents divide by 0 problems.
if me[:clone][:count][:total] > 0
me[:clone][:duration][:average] = mean(clone_times)
else
me[:clone][:duration][:average] = 0
end
end
# add to daily array
result[:daily].push(me)
end
# again, calc clone_average if we had clones.
unless total_clones_per_day.nil? or total_clones_per_day.length == 0
# totals
result[:clone][:count][:total] = total_clones_per_day.reduce(:+).to_i
result[:clone][:duration][:total] = total_clone_dur_day.reduce(:+).to_f
# averages and other things.
if result[:clone][:count][:total] != 0
result[:clone][:duration][:average] = result[:clone][:duration][:total] / result[:clone][:count][:total]
end
if min_max_clone_times.length > 0
result[:clone][:duration][:min], result[:clone][:duration][:max] = min_max_clone_times.minmax
end
result[:clone][:count][:min], result[:clone][:count][:max] = total_clones_per_day.minmax
result[:clone][:count][:average] = mean(total_clones_per_day)
end
JSON.pretty_generate(result)
end
get "#{api_prefix}/vm/?" do
content_type :json
result = []
$config[:pools].each do |pool|
result.push(pool['name'])
end
JSON.pretty_generate(result)
end
post "#{api_prefix}/vm/?" do
content_type :json
result = {}
available = 1
jdata = JSON.parse(request.body.read)
jdata.each do |key, val|
if $redis.scard('vmpooler__ready__' + key) < val.to_i
available = 0
end
end
if (available == 1)
result['ok'] = true
jdata.each do |key, val|
result[key] ||= {}
result[key]['ok'] = true ##
val.to_i.times do |_i|
vm = $redis.spop('vmpooler__ready__' + key)
unless vm.nil?
$redis.sadd('vmpooler__running__' + key, vm)
$redis.hset('vmpooler__active__' + key, vm, Time.now)
result[key] ||= {}
result[key]['ok'] = true ##
if result[key]['hostname']
result[key]['hostname'] = [result[key]['hostname']] unless result[key]['hostname'].is_a?(Array)
result[key]['hostname'].push(vm)
else
result[key]['hostname'] = vm
end
else
result[key]['ok'] = false ##
status 503
result['ok'] = false
end
end
end
else
status 503
result['ok'] = false
end
if result['ok'] && $config[:config]['domain']
result['domain'] = $config[:config]['domain']
end
JSON.pretty_generate(result)
end
post "#{api_prefix}/vm/:template/?" do
content_type :json
result = {}
request = {}
params[:template].split('+').each do |template|
request[template] ||= 0
request[template] = request[template] + 1
end
available = 1
request.keys.each do |template|
if $redis.scard('vmpooler__ready__' + template) < request[template]
available = 0
end
end
if (available == 1)
result['ok'] = true
params[:template].split('+').each do |template|
result[template] ||= {}
result[template]['ok'] = true ##
vm = $redis.spop('vmpooler__ready__' + template)
unless vm.nil?
$redis.sadd('vmpooler__running__' + template, vm)
$redis.hset('vmpooler__active__' + template, vm, Time.now)
result[template] ||= {}
if result[template]['hostname']
result[template]['hostname'] = [result[template]['hostname']] unless result[template]['hostname'].is_a?(Array)
result[template]['hostname'].push(vm)
else
result[template]['hostname'] = vm
end
else
result[template]['ok'] = false ##
status 503
result['ok'] = false
end
end
else
status 503
result['ok'] = false
end
if result['ok'] && $config[:config]['domain']
result['domain'] = $config[:config]['domain']
end
JSON.pretty_generate(result)
end
get "#{api_prefix}/vm/:hostname/?" do
content_type :json
result = {}
status 404
result['ok'] = false
params[:hostname] = hostname_shorten(params[:hostname])
if $redis.exists('vmpooler__vm__' + params[:hostname])
stauts 200
result['ok'] = true
result[params[:hostname]] = {}
result[params[:hostname]]['template'] = $redis.hget('vmpooler__vm__' + params[:hostname], 'template')
result[params[:hostname]]['lifetime'] = $redis.hget('vmpooler__vm__' + params[:hostname], 'lifetime') || $config[:config]['vm_lifetime']
result[params[:hostname]]['running'] = ((Time.now - Time.parse($redis.hget('vmpooler__active__' + result[params[:hostname]]['template'], params[:hostname]))) / 60 / 60).round(2)
if $config[:config]['domain']
result[params[:hostname]]['domain'] = $config[:config]['domain']
end
end
JSON.pretty_generate(result)
end
delete "#{api_prefix}/vm/:hostname/?" do
content_type :json
result = {}
status 404
result['ok'] = false
params[:hostname] = hostname_shorten(params[:hostname])
$config[:pools].each do |pool|
if $redis.sismember('vmpooler__running__' + pool['name'], params[:hostname])
$redis.srem('vmpooler__running__' + pool['name'], params[:hostname])
$redis.sadd('vmpooler__completed__' + pool['name'], params[:hostname])
status 200
result['ok'] = true
end
end
JSON.pretty_generate(result)
end
put "#{api_prefix}/vm/:hostname/?" do
content_type :json
result = {}
status 404
result['ok'] = false
params[:hostname] = hostname_shorten(params[:hostname])
if $redis.exists('vmpooler__vm__' + params[:hostname])
jdata = JSON.parse(request.body.read)
jdata.each do |param, arg|
case param
when 'lifetime'
arg = arg.to_i
if arg > 0
$redis.hset('vmpooler__vm__' + params[:hostname], param, arg)
status 200
result['ok'] = true
end
end
end
end
JSON.pretty_generate(result)
end
end
end
end