mirror of
https://github.com/puppetlabs/vmpooler.git
synced 2026-01-27 10:28:41 -05:00
Merge pull request #162 from puppetlabs/per-pool-stats-in-status
[QENG-4181] Add per-pool stats to `/status` API
This commit is contained in:
commit
8286ec2854
4 changed files with 199 additions and 3 deletions
|
|
@ -9,3 +9,12 @@ rvm:
|
||||||
- 2.2.1
|
- 2.2.1
|
||||||
- 2.2.2
|
- 2.2.2
|
||||||
- jruby-1.7.8
|
- jruby-1.7.8
|
||||||
|
# This below is a temporary shim to bypass these bundler+jruby bugs:
|
||||||
|
#
|
||||||
|
# https://github.com/bundler/bundler/issues/4975
|
||||||
|
# https://github.com/bundler/bundler/issues/4984
|
||||||
|
install:
|
||||||
|
- gem install bundler --version 1.12.5
|
||||||
|
- bundle _1.12.5_ install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
|
||||||
|
script:
|
||||||
|
- bundle _1.12.5_ exec rake
|
||||||
|
|
|
||||||
|
|
@ -119,10 +119,67 @@ module Vmpooler
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Provide run-time statistics
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# {
|
||||||
|
# "boot": {
|
||||||
|
# "duration": {
|
||||||
|
# "average": 163.6,
|
||||||
|
# "min": 65.49,
|
||||||
|
# "max": 830.07,
|
||||||
|
# "total": 247744.71000000002
|
||||||
|
# },
|
||||||
|
# "count": {
|
||||||
|
# "total": 1514
|
||||||
|
# }
|
||||||
|
# },
|
||||||
|
# "capacity": {
|
||||||
|
# "current": 968,
|
||||||
|
# "total": 975,
|
||||||
|
# "percent": 99.3
|
||||||
|
# },
|
||||||
|
# "clone": {
|
||||||
|
# "duration": {
|
||||||
|
# "average": 17.0,
|
||||||
|
# "min": 4.66,
|
||||||
|
# "max": 637.96,
|
||||||
|
# "total": 25634.15
|
||||||
|
# },
|
||||||
|
# "count": {
|
||||||
|
# "total": 1507
|
||||||
|
# }
|
||||||
|
# },
|
||||||
|
# "queue": {
|
||||||
|
# "pending": 12,
|
||||||
|
# "cloning": 0,
|
||||||
|
# "booting": 12,
|
||||||
|
# "ready": 968,
|
||||||
|
# "running": 367,
|
||||||
|
# "completed": 0,
|
||||||
|
# "total": 1347
|
||||||
|
# },
|
||||||
|
# "pools": {
|
||||||
|
# "ready": 100,
|
||||||
|
# "running": 120,
|
||||||
|
# "pending": 5,
|
||||||
|
# "max": 250,
|
||||||
|
# }
|
||||||
|
# "status": {
|
||||||
|
# "ok": true,
|
||||||
|
# "message": "Battle station fully armed and operational.",
|
||||||
|
# "empty": [ # NOTE: would not have 'ok: true' w/ "empty" pools
|
||||||
|
# "redhat-7-x86_64",
|
||||||
|
# "ubuntu-1404-i386"
|
||||||
|
# ],
|
||||||
|
# "uptime": 179585.9
|
||||||
|
# }
|
||||||
get "#{api_prefix}/status/?" do
|
get "#{api_prefix}/status/?" do
|
||||||
content_type :json
|
content_type :json
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
|
pools: {},
|
||||||
status: {
|
status: {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: 'Battle station fully armed and operational.'
|
message: 'Battle station fully armed and operational.'
|
||||||
|
|
@ -136,7 +193,21 @@ module Vmpooler
|
||||||
|
|
||||||
# Check for empty pools
|
# Check for empty pools
|
||||||
pools.each do |pool|
|
pools.each do |pool|
|
||||||
if backend.scard('vmpooler__ready__' + pool['name']).to_i == 0
|
# REMIND: move this out of the API and into the back-end
|
||||||
|
ready = backend.scard('vmpooler__ready__' + pool['name']).to_i
|
||||||
|
running = backend.scard('vmpooler__running__' + pool['name']).to_i
|
||||||
|
pending = backend.scard('vmpooler__pending__' + pool['name']).to_i
|
||||||
|
max = pool['size']
|
||||||
|
|
||||||
|
result[:pools][pool['name']] = {
|
||||||
|
ready: ready,
|
||||||
|
running: running,
|
||||||
|
pending: pending,
|
||||||
|
max: max
|
||||||
|
}
|
||||||
|
|
||||||
|
# for backwards compatibility, include separate "empty" stats in "status" block
|
||||||
|
if ready == 0
|
||||||
result[:status][:empty] ||= []
|
result[:status][:empty] ||= []
|
||||||
result[:status][:empty].push(pool['name'])
|
result[:status][:empty].push(pool['name'])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@ end
|
||||||
def create_ready_vm(template, name, token = nil)
|
def create_ready_vm(template, name, token = nil)
|
||||||
create_vm(name, token)
|
create_vm(name, token)
|
||||||
redis.sadd("vmpooler__ready__#{template}", name)
|
redis.sadd("vmpooler__ready__#{template}", name)
|
||||||
# REMIND: should be __vm__?
|
redis.hset("vmpooler__vm__#{name}", "template", template)
|
||||||
redis.hset("vmpooler_vm_#{name}", "template", template)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_running_vm(template, name, token = nil)
|
def create_running_vm(template, name, token = nil)
|
||||||
|
|
@ -45,6 +44,12 @@ def create_running_vm(template, name, token = nil)
|
||||||
redis.hset("vmpooler__vm__#{name}", "template", template)
|
redis.hset("vmpooler__vm__#{name}", "template", template)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_pending_vm(template, name, token = nil)
|
||||||
|
create_vm(name, token)
|
||||||
|
redis.sadd("vmpooler__pending__#{template}", name)
|
||||||
|
redis.hset("vmpooler__vm__#{name}", "template", template)
|
||||||
|
end
|
||||||
|
|
||||||
def create_vm(name, token = nil)
|
def create_vm(name, token = nil)
|
||||||
redis.hset("vmpooler__vm__#{name}", 'checkout', Time.now)
|
redis.hset("vmpooler__vm__#{name}", 'checkout', Time.now)
|
||||||
if token
|
if token
|
||||||
|
|
|
||||||
111
spec/vmpooler/api/v1/status_spec.rb
Normal file
111
spec/vmpooler/api/v1/status_spec.rb
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'rack/test'
|
||||||
|
|
||||||
|
module Vmpooler
|
||||||
|
class API
|
||||||
|
module Helpers
|
||||||
|
def authenticate(auth, username_str, password_str)
|
||||||
|
username_str == 'admin' and password_str == 's3cr3t'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_set_tag?(vm, tag, value)
|
||||||
|
value == redis.hget("vmpooler__vm__#{vm}", "tag:#{tag}")
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Vmpooler::API::V1 do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
def app()
|
||||||
|
Vmpooler::API
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '/status' do
|
||||||
|
let(:prefix) { '/api/v1' }
|
||||||
|
|
||||||
|
let(:config) {
|
||||||
|
{
|
||||||
|
config: {
|
||||||
|
'site_name' => 'test pooler',
|
||||||
|
'vm_lifetime_auth' => 2,
|
||||||
|
},
|
||||||
|
pools: [
|
||||||
|
{'name' => 'pool1', 'size' => 5},
|
||||||
|
{'name' => 'pool2', 'size' => 10}
|
||||||
|
],
|
||||||
|
alias: { 'poolone' => 'pool1' },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:current_time) { Time.now }
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
redis.flushdb
|
||||||
|
|
||||||
|
app.settings.set :config, config
|
||||||
|
app.settings.set :redis, redis
|
||||||
|
app.settings.set :config, auth: false
|
||||||
|
create_token('abcdefghijklmnopqrstuvwxyz012345', 'jdoe', current_time)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /status' do
|
||||||
|
it 'returns the configured maximum size for each pool' do
|
||||||
|
get "#{prefix}/status/"
|
||||||
|
|
||||||
|
# of course /status doesn't conform to the weird standard everything else uses...
|
||||||
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
|
result = JSON.parse(last_response.body)
|
||||||
|
expect(result["pools"]["pool1"]["max"]).to be(5)
|
||||||
|
expect(result["pools"]["pool2"]["max"]).to be(10)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the number of ready vms for each pool' do
|
||||||
|
3.times {|i| create_ready_vm("pool1", "vm-#{i}") }
|
||||||
|
get "#{prefix}/status/"
|
||||||
|
|
||||||
|
# of course /status doesn't conform to the weird standard everything else uses...
|
||||||
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
|
result = JSON.parse(last_response.body)
|
||||||
|
expect(result["pools"]["pool1"]["ready"]).to be(3)
|
||||||
|
expect(result["pools"]["pool2"]["ready"]).to be(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the number of running vms for each pool' do
|
||||||
|
3.times {|i| create_running_vm("pool1", "vm-#{i}") }
|
||||||
|
4.times {|i| create_running_vm("pool2", "vm-#{i}") }
|
||||||
|
|
||||||
|
get "#{prefix}/status/"
|
||||||
|
|
||||||
|
# of course /status doesn't conform to the weird standard everything else uses...
|
||||||
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
|
result = JSON.parse(last_response.body)
|
||||||
|
expect(result["pools"]["pool1"]["running"]).to be(3)
|
||||||
|
expect(result["pools"]["pool2"]["running"]).to be(4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the number of pending vms for each pool' do
|
||||||
|
3.times {|i| create_pending_vm("pool1", "vm-#{i}") }
|
||||||
|
4.times {|i| create_pending_vm("pool2", "vm-#{i}") }
|
||||||
|
|
||||||
|
get "#{prefix}/status/"
|
||||||
|
|
||||||
|
# of course /status doesn't conform to the weird standard everything else uses...
|
||||||
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
|
result = JSON.parse(last_response.body)
|
||||||
|
expect(result["pools"]["pool1"]["pending"]).to be(3)
|
||||||
|
expect(result["pools"]["pool2"]["pending"]).to be(4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it '(for v1 backwards compatibility) lists any empty pools in the status section' do
|
||||||
|
get "#{prefix}/status/"
|
||||||
|
|
||||||
|
# of course /status doesn't conform to the weird standard everything else uses...
|
||||||
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
|
result = JSON.parse(last_response.body)
|
||||||
|
expect(result["status"]["empty"].sort).to eq(["pool1", "pool2"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue