mirror of
https://github.com/puppetlabs/vmpooler.git
synced 2026-01-26 01:58:41 -05:00
Improved tests for vmpooler (#152)
* Add redis to our travis runs * De-mockistify v1/token specs; use real redis. Open questions: - Do we need to do better cleanup here? - Should we be using a separate database to prevent clobbering other local db's? * Remove mockist tests from main suite. * (MAINT) gitignore some common files * (maint) Clean up some of the /vm/ tests * (maint) Convert specs for /vm/template * (maint) Clean up, reorganize specs * (maint) Move extracted spec helper methods to spec_helper * (maint) rename create_vm -> create_ready_vm * (WIP) add partially-converted /vm/hostname specs * (maint) clean up vm_spec * (WIP) notes for next steps * (maint) Define :config in token tests Miscellaneous whitespace cleanup. * (maint) Lift #redis definition into spec helper library * (maint) drop unneeded clear_pool helper Given the way we're flushing redis (which seems super performant), we don't need to clear pools any more at the beginning of tests. * (maint) Drop clear_pool from vm/template specs * (maint) Update vm/hostname tag and lifetime specs * (maint) Convert vm deletion specs * (maint) Convert specs for vm snapshot operations * (maint) Drop now-obsolete v1_spec.rb * (maint) cosmetic cleanup in spec helper * (maint) begin de-mockistifying api_spec.rb * (maint) repair incorrect test The mockist version of the test allows redis' scard to return nil, which it does not actually do in real life. Verified the behavior in the code via a debugger. Fixed the test. * (maint) finish converting dashboard specs * (maint) rename api_spec to dashboard_spec * (maint) Don't clobber default redis database when running specs
This commit is contained in:
parent
b59a1f8886
commit
26ca390b4c
10 changed files with 941 additions and 771 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.ruby-version
|
||||||
|
Gemfile.lock
|
||||||
|
vendor
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
cache: bundler
|
cache: bundler
|
||||||
sudo: false
|
sudo: false
|
||||||
language: ruby
|
language: ruby
|
||||||
|
services:
|
||||||
|
- redis-server
|
||||||
rvm:
|
rvm:
|
||||||
- 1.9.3
|
- 1.9.3
|
||||||
- 2.1.1
|
- 2.1.1
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
def expect_json(
|
def redis
|
||||||
ok = true,
|
unless @redis
|
||||||
http = 200
|
@redis = Redis.new
|
||||||
)
|
@redis.select(15) # let's use the highest numbered database available in a default install
|
||||||
|
end
|
||||||
|
@redis
|
||||||
|
end
|
||||||
|
|
||||||
|
def expect_json(ok = true, http = 200)
|
||||||
expect(last_response.header['Content-Type']).to eq('application/json')
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
|
|
||||||
if (ok == true) then
|
if (ok == true) then
|
||||||
|
|
@ -12,3 +17,59 @@ def expect_json(
|
||||||
|
|
||||||
expect(last_response.status).to eq(http)
|
expect(last_response.status).to eq(http)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_token(token, user, timestamp)
|
||||||
|
redis.hset("vmpooler__token__#{token}", 'user', user)
|
||||||
|
redis.hset("vmpooler__token__#{token}", 'created', timestamp)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_token_data(token)
|
||||||
|
redis.hgetall("vmpooler__token__#{token}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def token_exists?(token)
|
||||||
|
result = get_token_data
|
||||||
|
result && !result.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_ready_vm(template, name, token = nil)
|
||||||
|
create_vm(name, token)
|
||||||
|
redis.sadd("vmpooler__ready__#{template}", name)
|
||||||
|
redis.hset("vmpooler_vm_#{name}", "template", template)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_running_vm(template, name, token = nil)
|
||||||
|
create_vm(name, token)
|
||||||
|
redis.sadd("vmpooler__running__#{template}", name)
|
||||||
|
redis.hset("vmpooler__vm__#{name}", "template", template)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_vm(name, token = nil)
|
||||||
|
redis.hset("vmpooler__vm__#{name}", 'checkout', Time.now)
|
||||||
|
if token
|
||||||
|
redis.hset("vmpooler__vm__#{name}", 'token:token', token)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_vm(vm)
|
||||||
|
redis.hgetall("vmpooler__vm__#{vm}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def snapshot_vm(vm, snapshot = '12345678901234567890123456789012')
|
||||||
|
redis.sadd('vmpooler__tasks__snapshot', "#{vm}:#{snapshot}")
|
||||||
|
redis.hset("vmpooler__vm__#{vm}", "snapshot:#{snapshot}", "1")
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_vm_snapshot?(vm)
|
||||||
|
redis.smembers('vmpooler__tasks__snapshot').any? do |snapshot|
|
||||||
|
instance, sha = snapshot.split(':')
|
||||||
|
vm == instance
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def vm_reverted_to_snapshot?(vm, snapshot = nil)
|
||||||
|
redis.smembers('vmpooler__tasks__snapshot-revert').any? do |action|
|
||||||
|
instance, sha = action.split(':')
|
||||||
|
instance == vm and (snapshot ? (sha == snapshot) : true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ require 'helpers'
|
||||||
require 'rbvmomi'
|
require 'rbvmomi'
|
||||||
require 'rspec'
|
require 'rspec'
|
||||||
require 'vmpooler'
|
require 'vmpooler'
|
||||||
|
require 'redis'
|
||||||
|
|
|
||||||
173
spec/vmpooler/api/v1/token_spec.rb
Normal file
173
spec/vmpooler/api/v1/token_spec.rb
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
describe Vmpooler::API::V1 do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
def app()
|
||||||
|
Vmpooler::API
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '/token' do
|
||||||
|
let(:prefix) { '/api/v1' }
|
||||||
|
let(:current_time) { Time.now }
|
||||||
|
let(:config) { { } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
app.settings.set :config, config
|
||||||
|
app.settings.set :redis, redis
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /token' do
|
||||||
|
context '(auth not configured)' do
|
||||||
|
let(:config) { { auth: false } }
|
||||||
|
|
||||||
|
it 'returns a 404' do
|
||||||
|
get "#{prefix}/token"
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
let(:config) { { auth: true } }
|
||||||
|
|
||||||
|
it 'returns a 401 if not authed' do
|
||||||
|
get "#{prefix}/token"
|
||||||
|
expect_json(ok = false, http = 401)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a list of tokens if authed' do
|
||||||
|
create_token "abc", "admin", current_time
|
||||||
|
|
||||||
|
authorize 'admin', 's3cr3t'
|
||||||
|
get "#{prefix}/token"
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect(JSON.parse(last_response.body)['abc']['created']).to eq(current_time.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /token' do
|
||||||
|
context '(auth not configured)' do
|
||||||
|
let(:config) { { auth: false } }
|
||||||
|
|
||||||
|
it 'returns a 404' do
|
||||||
|
post "#{prefix}/token"
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
let(:config) { { auth: true } }
|
||||||
|
|
||||||
|
it 'returns a 401 if not authed' do
|
||||||
|
post "#{prefix}/token"
|
||||||
|
expect_json(ok = false, http = 401)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a newly created token if authed' do
|
||||||
|
authorize 'admin', 's3cr3t'
|
||||||
|
post "#{prefix}/token"
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
returned_token = JSON.parse(last_response.body)['token']
|
||||||
|
expect(returned_token.length).to be(32)
|
||||||
|
expect(get_token_data(returned_token)['user']).to eq("admin")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '/token/:token' do
|
||||||
|
let(:prefix) { '/api/v1' }
|
||||||
|
let(:current_time) { Time.now }
|
||||||
|
|
||||||
|
before do
|
||||||
|
app.settings.set :config, config
|
||||||
|
app.settings.set :redis, redis
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_vm_for_token(token, pool, vm)
|
||||||
|
redis.sadd("vmpooler__running__#{pool}", vm)
|
||||||
|
redis.hset("vmpooler__vm__#{vm}", "token:token", token)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /token/:token' do
|
||||||
|
context '(auth not configured)' do
|
||||||
|
let(:config) { { auth: false } }
|
||||||
|
|
||||||
|
it 'returns a 404' do
|
||||||
|
get "#{prefix}/token/this"
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
let(:config) { {
|
||||||
|
auth: true,
|
||||||
|
pools: [
|
||||||
|
{'name' => 'pool1', 'size' => 5}
|
||||||
|
]
|
||||||
|
} }
|
||||||
|
|
||||||
|
it 'returns a token' do
|
||||||
|
create_token "mytoken", "admin", current_time
|
||||||
|
create_vm_for_token "mytoken", "pool1", "vmhostname"
|
||||||
|
|
||||||
|
get "#{prefix}/token/mytoken"
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect(JSON.parse(last_response.body)['ok']).to eq(true)
|
||||||
|
expect(JSON.parse(last_response.body)['mytoken']['user']).to eq('admin')
|
||||||
|
expect(JSON.parse(last_response.body)['mytoken']['vms']['running']).to include('vmhostname')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE /token/:token' do
|
||||||
|
context '(auth not configured)' do
|
||||||
|
let(:config) { { auth: false } }
|
||||||
|
|
||||||
|
it 'returns a 404' do
|
||||||
|
delete "#{prefix}/token/this"
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
let(:config) { { auth: true } }
|
||||||
|
|
||||||
|
it 'returns a 401 if not authed' do
|
||||||
|
delete "#{prefix}/token/this"
|
||||||
|
expect_json(ok = false, http = 401)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deletes a token if authed' do
|
||||||
|
create_token("mytoken", "admin", current_time)
|
||||||
|
authorize 'admin', 's3cr3t'
|
||||||
|
|
||||||
|
delete "#{prefix}/token/mytoken"
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails if token does not exist' do
|
||||||
|
authorize 'admin', 's3cr3t'
|
||||||
|
|
||||||
|
delete "#{prefix}/token/missingtoken"
|
||||||
|
expect_json(ok = false, http = 401) # TODO: should this be 404?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
317
spec/vmpooler/api/v1/vm_hostname_spec.rb
Normal file
317
spec/vmpooler/api/v1/vm_hostname_spec.rb
Normal file
|
|
@ -0,0 +1,317 @@
|
||||||
|
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 '/vm/:hostname' 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 'PUT /vm/:hostname' do
|
||||||
|
it 'allows tags to be set' do
|
||||||
|
create_vm('testhost')
|
||||||
|
put "#{prefix}/vm/testhost", '{"tags":{"tested_by":"rspec"}}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect has_set_tag?('testhost', 'tested_by', 'rspec')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'skips empty tags' do
|
||||||
|
create_vm('testhost')
|
||||||
|
put "#{prefix}/vm/testhost", '{"tags":{"tested_by":""}}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect !has_set_tag?('testhost', 'tested_by', '')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not set tags if request body format is invalid' do
|
||||||
|
create_vm('testhost')
|
||||||
|
put "#{prefix}/vm/testhost", '{"tags":{"tested"}}'
|
||||||
|
expect_json(ok = false, http = 400)
|
||||||
|
|
||||||
|
expect !has_set_tag?('testhost', 'tested', '')
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(allowed_tags configured)' do
|
||||||
|
it 'fails if specified tag is not in allowed_tags array' do
|
||||||
|
app.settings.set :config,
|
||||||
|
{ :config => { 'allowed_tags' => ['created_by', 'project', 'url'] } }
|
||||||
|
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
put "#{prefix}/vm/testhost", '{"tags":{"created_by":"rspec","tested_by":"rspec"}}'
|
||||||
|
expect_json(ok = false, http = 400)
|
||||||
|
|
||||||
|
expect !has_set_tag?('testhost', 'tested_by', 'rspec')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(tagfilter configured)' do
|
||||||
|
let(:config) { {
|
||||||
|
tagfilter: { 'url' => '(.*)\/' },
|
||||||
|
} }
|
||||||
|
|
||||||
|
it 'correctly filters tags' do
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
put "#{prefix}/vm/testhost", '{"tags":{"url":"foo.com/something.html"}}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect has_set_tag?('testhost', 'url', 'foo.com')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't eat tags not matching filter" do
|
||||||
|
create_vm('testhost')
|
||||||
|
put "#{prefix}/vm/testhost", '{"tags":{"url":"foo.com"}}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect has_set_tag?('testhost', 'url', 'foo.com')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth not configured)' do
|
||||||
|
let(:config) { { auth: false } }
|
||||||
|
|
||||||
|
it 'allows VM lifetime to be modified without a token' do
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
put "#{prefix}/vm/testhost", '{"lifetime":"1"}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
vm = fetch_vm('testhost')
|
||||||
|
expect(vm['lifetime'].to_i).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not allow a lifetime to be 0' do
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
put "#{prefix}/vm/testhost", '{"lifetime":"0"}'
|
||||||
|
expect_json(ok = false, http = 400)
|
||||||
|
|
||||||
|
vm = fetch_vm('testhost')
|
||||||
|
expect(vm['lifetime']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
before(:each) do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'allows VM lifetime to be modified with a token' do
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
put "#{prefix}/vm/testhost", '{"lifetime":"1"}', {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
vm = fetch_vm('testhost')
|
||||||
|
expect(vm['lifetime'].to_i).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not allows VM lifetime to be modified without a token' do
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
put "#{prefix}/vm/testhost", '{"lifetime":"1"}'
|
||||||
|
expect_json(ok = false, http = 401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE /vm/:hostname' do
|
||||||
|
context '(auth not configured)' do
|
||||||
|
it 'does not delete a non-existant VM' do
|
||||||
|
delete "#{prefix}/vm/testhost"
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deletes an existing VM' do
|
||||||
|
create_running_vm('pool1', 'testhost')
|
||||||
|
expect fetch_vm('testhost')
|
||||||
|
|
||||||
|
delete "#{prefix}/vm/testhost"
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
expect !fetch_vm('testhost')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
before(:each) do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(checked-out without token)' do
|
||||||
|
it 'deletes a VM without supplying a token' do
|
||||||
|
create_running_vm('pool1', 'testhost')
|
||||||
|
expect fetch_vm('testhost')
|
||||||
|
|
||||||
|
delete "#{prefix}/vm/testhost"
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
expect !fetch_vm('testhost')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(checked-out with token)' do
|
||||||
|
it 'fails to delete a VM without supplying a token' do
|
||||||
|
create_running_vm('pool1', 'testhost', 'abcdefghijklmnopqrstuvwxyz012345')
|
||||||
|
expect fetch_vm('testhost')
|
||||||
|
|
||||||
|
delete "#{prefix}/vm/testhost"
|
||||||
|
expect_json(ok = false, http = 401)
|
||||||
|
expect fetch_vm('testhost')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deletes a VM when token is supplied' do
|
||||||
|
create_running_vm('pool1', 'testhost', 'abcdefghijklmnopqrstuvwxyz012345')
|
||||||
|
expect fetch_vm('testhost')
|
||||||
|
|
||||||
|
delete "#{prefix}/vm/testhost", "", {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect !fetch_vm('testhost')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /vm/:hostname/snapshot' do
|
||||||
|
context '(auth not configured)' do
|
||||||
|
it 'creates a snapshot' do
|
||||||
|
create_vm('testhost')
|
||||||
|
post "#{prefix}/vm/testhost/snapshot"
|
||||||
|
expect_json(ok = true, http = 202)
|
||||||
|
expect(JSON.parse(last_response.body)['testhost']['snapshot'].length).to be(32)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
before(:each) do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 401 if not authed' do
|
||||||
|
post "#{prefix}/vm/testhost/snapshot"
|
||||||
|
expect_json(ok = false, http = 401)
|
||||||
|
expect !has_vm_snapshot?('testhost')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a snapshot if authed' do
|
||||||
|
create_vm('testhost')
|
||||||
|
snapshot_vm('testhost', 'testsnapshot')
|
||||||
|
|
||||||
|
post "#{prefix}/vm/testhost/snapshot", "", {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 202)
|
||||||
|
expect(JSON.parse(last_response.body)['testhost']['snapshot'].length).to be(32)
|
||||||
|
expect has_vm_snapshot?('testhost')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /vm/:hostname/snapshot/:snapshot' do
|
||||||
|
context '(auth not configured)' do
|
||||||
|
it 'reverts to a snapshot' do
|
||||||
|
create_vm('testhost')
|
||||||
|
snapshot_vm('testhost', 'testsnapshot')
|
||||||
|
|
||||||
|
post "#{prefix}/vm/testhost/snapshot/testsnapshot"
|
||||||
|
expect_json(ok = true, http = 202)
|
||||||
|
expect vm_reverted_to_snapshot?('testhost', 'testsnapshot')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails if the specified snapshot does not exist' do
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
post "#{prefix}/vm/testhost/snapshot/testsnapshot", "", {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
expect !vm_reverted_to_snapshot?('testhost', 'testsnapshot')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
before(:each) do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 401 if not authed' do
|
||||||
|
create_vm('testhost')
|
||||||
|
snapshot_vm('testhost', 'testsnapshot')
|
||||||
|
|
||||||
|
post "#{prefix}/vm/testhost/snapshot/testsnapshot"
|
||||||
|
expect_json(ok = false, http = 401)
|
||||||
|
expect !vm_reverted_to_snapshot?('testhost', 'testsnapshot')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails if authed and the specified snapshot does not exist' do
|
||||||
|
create_vm('testhost')
|
||||||
|
|
||||||
|
post "#{prefix}/vm/testhost/snapshot/testsnapshot", "", {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
expect !vm_reverted_to_snapshot?('testhost', 'testsnapshot')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'reverts to a snapshot if authed' do
|
||||||
|
create_vm('testhost')
|
||||||
|
snapshot_vm('testhost', 'testsnapshot')
|
||||||
|
|
||||||
|
post "#{prefix}/vm/testhost/snapshot/testsnapshot", "", {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 202)
|
||||||
|
expect vm_reverted_to_snapshot?('testhost', 'testsnapshot')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
175
spec/vmpooler/api/v1/vm_spec.rb
Normal file
175
spec/vmpooler/api/v1/vm_spec.rb
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
describe Vmpooler::API::V1 do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
def app()
|
||||||
|
Vmpooler::API
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '/vm' 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 'POST /vm' do
|
||||||
|
it 'returns a single VM' do
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm", '{"pool1":"1"}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a single VM for an alias' do
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm", '{"poolone":"1"}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails on nonexistant pools' do
|
||||||
|
post "#{prefix}/vm", '{"poolpoolpool":"1"}'
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns multiple VMs' do
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
create_ready_vm 'pool2', 'qrstuvwxyz012345'
|
||||||
|
|
||||||
|
post "#{prefix}/vm", '{"pool1":"1","pool2":"1"}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
},
|
||||||
|
pool2: {
|
||||||
|
hostname: 'qrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth not configured)' do
|
||||||
|
it 'does not extend VM lifetime if auth token is provided' do
|
||||||
|
app.settings.set :config, auth: false
|
||||||
|
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm", '{"pool1":"1"}', {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
|
||||||
|
vm = fetch_vm('abcdefghijklmnop')
|
||||||
|
expect(vm['lifetime']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
it 'extends VM lifetime if auth token is provided' do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm", '{"pool1":"1"}', {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
|
||||||
|
vm = fetch_vm('abcdefghijklmnop')
|
||||||
|
expect(vm['lifetime'].to_i).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not extend VM lifetime if auth token is not provided' do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm", '{"pool1":"1"}'
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
|
||||||
|
vm = fetch_vm('abcdefghijklmnop')
|
||||||
|
expect(vm['lifetime']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
176
spec/vmpooler/api/v1/vm_template_spec.rb
Normal file
176
spec/vmpooler/api/v1/vm_template_spec.rb
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
describe Vmpooler::API::V1 do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
def app()
|
||||||
|
Vmpooler::API
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '/vm/:template' 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 'POST /vm/:template' do
|
||||||
|
it 'returns a single VM' do
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm/pool1", ''
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a single VM for an alias' do
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm/poolone", ''
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails on nonexistant pools' do
|
||||||
|
post "#{prefix}/vm/poolpoolpool", ''
|
||||||
|
expect_json(ok = false, http = 404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns multiple VMs' do
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
create_ready_vm 'pool2', 'qrstuvwxyz012345'
|
||||||
|
|
||||||
|
post "#{prefix}/vm/pool1+pool2", ''
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
},
|
||||||
|
pool2: {
|
||||||
|
hostname: 'qrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth not configured)' do
|
||||||
|
it 'does not extend VM lifetime if auth token is provided' do
|
||||||
|
app.settings.set :config, auth: false
|
||||||
|
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm/pool1", '', {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
vm = fetch_vm('abcdefghijklmnop')
|
||||||
|
expect(vm['lifetime']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '(auth configured)' do
|
||||||
|
it 'extends VM lifetime if auth token is provided' do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm/pool1", '', {
|
||||||
|
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
|
||||||
|
vm = fetch_vm('abcdefghijklmnop')
|
||||||
|
expect(vm['lifetime'].to_i).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not extend VM lifetime if auth token is not provided' do
|
||||||
|
app.settings.set :config, auth: true
|
||||||
|
create_ready_vm 'pool1', 'abcdefghijklmnop'
|
||||||
|
|
||||||
|
post "#{prefix}/vm/pool1", ''
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
ok: true,
|
||||||
|
pool1: {
|
||||||
|
hostname: 'abcdefghijklmnop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_json(ok = true, http = 200)
|
||||||
|
|
||||||
|
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
||||||
|
|
||||||
|
vm = fetch_vm('abcdefghijklmnop')
|
||||||
|
expect(vm['lifetime']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,735 +0,0 @@
|
||||||
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
|
|
||||||
|
|
||||||
describe Vmpooler::API::V1 do
|
|
||||||
include Rack::Test::Methods
|
|
||||||
|
|
||||||
def app()
|
|
||||||
Vmpooler::API
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '/token' do
|
|
||||||
let(:redis) { double('redis') }
|
|
||||||
let(:prefix) { '/api/v1' }
|
|
||||||
|
|
||||||
before do
|
|
||||||
app.settings.set :config, config
|
|
||||||
app.settings.set :redis, redis
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'GET /token' do
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'returns a 404' do
|
|
||||||
get "#{prefix}/token"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 404)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'returns a 401 if not authed' do
|
|
||||||
get "#{prefix}/token"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 401)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns a list of tokens if authed' do
|
|
||||||
expect(redis).to receive(:keys).with('vmpooler__token__*').and_return(["vmpooler__token__abc"])
|
|
||||||
expect(redis).to receive(:hgetall).with('vmpooler__token__abc').and_return({"user" => "admin", "created" => "now"})
|
|
||||||
|
|
||||||
authorize 'admin', 's3cr3t'
|
|
||||||
|
|
||||||
get "#{prefix}/token"
|
|
||||||
|
|
||||||
expect(JSON.parse(last_response.body)['abc']['created']).to eq('now')
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST /token' do
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'returns a 404' do
|
|
||||||
post "#{prefix}/token"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 404)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
before do
|
|
||||||
allow(redis).to receive(:hset).and_return '1'
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'returns a 401 if not authed' do
|
|
||||||
post "#{prefix}/token"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 401)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns a token if authed' do
|
|
||||||
authorize 'admin', 's3cr3t'
|
|
||||||
|
|
||||||
post "#{prefix}/token"
|
|
||||||
|
|
||||||
expect(JSON.parse(last_response.body)['token'].length).to be(32)
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '/token/:token' do
|
|
||||||
let(:redis) { double('redis') }
|
|
||||||
let(:prefix) { '/api/v1' }
|
|
||||||
|
|
||||||
before do
|
|
||||||
app.settings.set :config, config
|
|
||||||
app.settings.set :redis, redis
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'GET /token/:token' do
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'returns a 404' do
|
|
||||||
get "#{prefix}/token/this"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 404)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { {
|
|
||||||
auth: true,
|
|
||||||
pools: [
|
|
||||||
{'name' => 'pool1', 'size' => 5}
|
|
||||||
]
|
|
||||||
} }
|
|
||||||
|
|
||||||
it 'returns a token' do
|
|
||||||
expect(redis).to receive(:hgetall).with('vmpooler__token__this').and_return({'user' => 'admin'})
|
|
||||||
expect(redis).to receive(:smembers).with('vmpooler__running__pool1').and_return(['vmhostname'])
|
|
||||||
expect(redis).to receive(:hget).with('vmpooler__vm__vmhostname', 'token:token').and_return('this')
|
|
||||||
|
|
||||||
get "#{prefix}/token/this"
|
|
||||||
|
|
||||||
expect(JSON.parse(last_response.body)['ok']).to eq(true)
|
|
||||||
expect(JSON.parse(last_response.body)['this']['user']).to eq('admin')
|
|
||||||
expect(JSON.parse(last_response.body)['this']['vms']['running']).to include('vmhostname')
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'DELETE /token/:token' do
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'returns a 404' do
|
|
||||||
delete "#{prefix}/token/this"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 404)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
before do
|
|
||||||
allow(redis).to receive(:del).and_return '1'
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'returns a 401 if not authed' do
|
|
||||||
delete "#{prefix}/token/this"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 401)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'deletes a token if authed' do
|
|
||||||
authorize 'admin', 's3cr3t'
|
|
||||||
|
|
||||||
delete "#{prefix}/token/this"
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '/vm' do
|
|
||||||
let(:redis) { double('redis') }
|
|
||||||
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' }
|
|
||||||
} }
|
|
||||||
|
|
||||||
before do
|
|
||||||
app.settings.set :config, config
|
|
||||||
app.settings.set :redis, redis
|
|
||||||
|
|
||||||
allow(redis).to receive(:exists).and_return '1'
|
|
||||||
allow(redis).to receive(:hget).with('vmpooler__token__abcdefghijklmnopqrstuvwxyz012345', 'user').and_return 'jdoe'
|
|
||||||
allow(redis).to receive(:hset).and_return '1'
|
|
||||||
allow(redis).to receive(:sadd).and_return '1'
|
|
||||||
allow(redis).to receive(:scard).and_return '5'
|
|
||||||
allow(redis).to receive(:spop).with('vmpooler__ready__pool1').and_return 'abcdefghijklmnop'
|
|
||||||
allow(redis).to receive(:spop).with('vmpooler__ready__pool2').and_return 'qrstuvwxyz012345'
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST /vm' do
|
|
||||||
it 'returns a single VM' do
|
|
||||||
post "#{prefix}/vm", '{"pool1":"1"}'
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns a single VM for an alias' do
|
|
||||||
expect(redis).to receive(:exists).with("vmpooler__ready__poolone").and_return(false)
|
|
||||||
|
|
||||||
post "#{prefix}/vm", '{"poolone":"1"}'
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'fails on nonexistant pools' do
|
|
||||||
expect(redis).to receive(:exists).with("vmpooler__ready__poolpoolpool").and_return(false)
|
|
||||||
|
|
||||||
post "#{prefix}/vm", '{"poolpoolpool":"1"}'
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 404)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns multiple VMs' do
|
|
||||||
post "#{prefix}/vm", '{"pool1":"1","pool2":"1"}'
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
},
|
|
||||||
pool2: {
|
|
||||||
hostname: 'qrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'does not extend VM lifetime if auth token is provided' do
|
|
||||||
expect(redis).not_to receive(:hset).with("vmpooler__vm__abcdefghijklmnop", "lifetime", 2)
|
|
||||||
|
|
||||||
post "#{prefix}/vm", '{"pool1":"1"}', {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'extends VM lifetime if auth token is provided' do
|
|
||||||
expect(redis).to receive(:hset).with("vmpooler__vm__abcdefghijklmnop", "lifetime", 2).once
|
|
||||||
|
|
||||||
post "#{prefix}/vm", '{"pool1":"1"}', {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not extend VM lifetime if auth token is not provided' do
|
|
||||||
expect(redis).not_to receive(:hset).with("vmpooler__vm__abcdefghijklmnop", "lifetime", 2)
|
|
||||||
|
|
||||||
post "#{prefix}/vm", '{"pool1":"1"}'
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '/vm/:template' do
|
|
||||||
let(:redis) { double('redis') }
|
|
||||||
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' }
|
|
||||||
} }
|
|
||||||
|
|
||||||
before do
|
|
||||||
app.settings.set :config, config
|
|
||||||
app.settings.set :redis, redis
|
|
||||||
|
|
||||||
allow(redis).to receive(:exists).and_return '1'
|
|
||||||
allow(redis).to receive(:hget).with('vmpooler__token__abcdefghijklmnopqrstuvwxyz012345', 'user').and_return 'jdoe'
|
|
||||||
allow(redis).to receive(:hset).and_return '1'
|
|
||||||
allow(redis).to receive(:sadd).and_return '1'
|
|
||||||
allow(redis).to receive(:scard).and_return '5'
|
|
||||||
allow(redis).to receive(:spop).with('vmpooler__ready__pool1').and_return 'abcdefghijklmnop'
|
|
||||||
allow(redis).to receive(:spop).with('vmpooler__ready__pool2').and_return 'qrstuvwxyz012345'
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST /vm/:template' do
|
|
||||||
it 'returns a single VM' do
|
|
||||||
post "#{prefix}/vm/pool1", ''
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns a single VM for an alias' do
|
|
||||||
expect(redis).to receive(:exists).with("vmpooler__ready__poolone").and_return(false)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/poolone", ''
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'fails on nonexistant pools' do
|
|
||||||
expect(redis).to receive(:exists).with("vmpooler__ready__poolpoolpool").and_return(false)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/poolpoolpool", ''
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 404)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns multiple VMs' do
|
|
||||||
post "#{prefix}/vm/pool1+pool2", ''
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
},
|
|
||||||
pool2: {
|
|
||||||
hostname: 'qrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'does not extend VM lifetime if auth token is provided' do
|
|
||||||
expect(redis).not_to receive(:hset).with("vmpooler__vm__abcdefghijklmnop", "lifetime", 2)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/pool1", '', {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'extends VM lifetime if auth token is provided' do
|
|
||||||
expect(redis).to receive(:hset).with("vmpooler__vm__abcdefghijklmnop", "lifetime", 2).once
|
|
||||||
|
|
||||||
post "#{prefix}/vm/pool1", '', {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not extend VM lifetime if auth token is not provided' do
|
|
||||||
expect(redis).not_to receive(:hset).with("vmpooler__vm__abcdefghijklmnop", "lifetime", 2)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/pool1", ''
|
|
||||||
|
|
||||||
expected = {
|
|
||||||
ok: true,
|
|
||||||
pool1: {
|
|
||||||
hostname: 'abcdefghijklmnop'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(expected))
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '/vm/:hostname' do
|
|
||||||
let(:redis) { double('redis') }
|
|
||||||
let(:prefix) { '/api/v1' }
|
|
||||||
let(:config) { {
|
|
||||||
pools: [
|
|
||||||
{'name' => 'pool1', 'size' => 5},
|
|
||||||
{'name' => 'pool2', 'size' => 10}
|
|
||||||
]
|
|
||||||
} }
|
|
||||||
|
|
||||||
before do
|
|
||||||
app.settings.set :config, config
|
|
||||||
app.settings.set :redis, redis
|
|
||||||
|
|
||||||
allow(redis).to receive(:exists).and_return '1'
|
|
||||||
allow(redis).to receive(:hset).and_return '1'
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'PUT /vm/:hostname' do
|
|
||||||
it 'allows tags to be set' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"tags":{"tested_by":"rspec"}}'
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'skips empty tags' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"tags":{"tested_by":""}}'
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not set tags if request body format is invalid' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"tags":{"tested"}}'
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 400)
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(allowed_tags configured)' do
|
|
||||||
let(:config) { {
|
|
||||||
config: {
|
|
||||||
'allowed_tags' => ['created_by', 'project', 'url']
|
|
||||||
}
|
|
||||||
} }
|
|
||||||
|
|
||||||
it 'fails if specified tag is not in allowed_tags array' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"tags":{"created_by":"rspec","tested_by":"rspec"}}'
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 400)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(tagfilter configured)' do
|
|
||||||
let(:config) { {
|
|
||||||
tagfilter: { 'url' => '(.*)\/' },
|
|
||||||
} }
|
|
||||||
|
|
||||||
it 'correctly filters tags' do
|
|
||||||
expect(redis).to receive(:hset).with("vmpooler__vm__testhost", "tag:url", "foo.com")
|
|
||||||
|
|
||||||
put "#{prefix}/vm/testhost", '{"tags":{"url":"foo.com/something.html"}}'
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'doesn\'t eat tags not matching filter' do
|
|
||||||
expect(redis).to receive(:hset).with("vmpooler__vm__testhost", "tag:url", "foo.com")
|
|
||||||
|
|
||||||
put "#{prefix}/vm/testhost", '{"tags":{"url":"foo.com"}}'
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'allows VM lifetime to be modified without a token' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"lifetime":"1"}'
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not allow a lifetime to be 0' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"lifetime":"0"}'
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 400)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'allows VM lifetime to be modified with a token' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"lifetime":"1"}', {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not allows VM lifetime to be modified without a token' do
|
|
||||||
put "#{prefix}/vm/testhost", '{"lifetime":"1"}'
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 401)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'DELETE /vm/:hostname' do
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'does not delete a non-existant VM' do
|
|
||||||
expect(redis).to receive(:hgetall).and_return({})
|
|
||||||
expect(redis).not_to receive(:sadd)
|
|
||||||
expect(redis).not_to receive(:srem)
|
|
||||||
|
|
||||||
delete "#{prefix}/vm/testhost"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 404)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'deletes an existing VM' do
|
|
||||||
expect(redis).to receive(:hgetall).with('vmpooler__vm__testhost').and_return({"template" => "pool1"})
|
|
||||||
expect(redis).to receive(:srem).and_return(true)
|
|
||||||
expect(redis).to receive(:sadd)
|
|
||||||
|
|
||||||
delete "#{prefix}/vm/testhost"
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
context '(checked-out without token)' do
|
|
||||||
it 'deletes a VM without supplying a token' do
|
|
||||||
expect(redis).to receive(:hgetall).with('vmpooler__vm__testhost').and_return({"template" => "pool1"})
|
|
||||||
expect(redis).to receive(:srem).and_return(true)
|
|
||||||
expect(redis).to receive(:sadd)
|
|
||||||
|
|
||||||
delete "#{prefix}/vm/testhost"
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(checked-out with token)' do
|
|
||||||
it 'fails to delete a VM without supplying a token' do
|
|
||||||
expect(redis).to receive(:hgetall).with('vmpooler__vm__testhost').and_return({"template" => "pool1", "token:token" => "abcdefghijklmnopqrstuvwxyz012345"})
|
|
||||||
expect(redis).not_to receive(:sadd)
|
|
||||||
expect(redis).not_to receive(:srem)
|
|
||||||
|
|
||||||
delete "#{prefix}/vm/testhost"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 401)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'deletes a VM when token is supplied' do
|
|
||||||
expect(redis).to receive(:hgetall).with('vmpooler__vm__testhost').and_return({"template" => "pool1", "token:token" => "abcdefghijklmnopqrstuvwxyz012345"})
|
|
||||||
expect(redis).to receive(:srem).and_return(true)
|
|
||||||
expect(redis).to receive(:sadd)
|
|
||||||
|
|
||||||
delete "#{prefix}/vm/testhost", "", {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST /vm/:hostname/snapshot' do
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'creates a snapshot' do
|
|
||||||
expect(redis).to receive(:sadd)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/testhost/snapshot"
|
|
||||||
|
|
||||||
expect(JSON.parse(last_response.body)['testhost']['snapshot'].length).to be(32)
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 202)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'returns a 401 if not authed' do
|
|
||||||
post "#{prefix}/vm/testhost/snapshot"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 401)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates a snapshot if authed' do
|
|
||||||
expect(redis).to receive(:sadd)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/testhost/snapshot", "", {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(JSON.parse(last_response.body)['testhost']['snapshot'].length).to be(32)
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 202)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST /vm/:hostname/snapshot/:snapshot' do
|
|
||||||
context '(auth not configured)' do
|
|
||||||
let(:config) { { auth: false } }
|
|
||||||
|
|
||||||
it 'reverts to a snapshot' do
|
|
||||||
expect(redis).to receive(:hget).with('vmpooler__vm__testhost', 'snapshot:testsnapshot').and_return(1)
|
|
||||||
expect(redis).to receive(:sadd)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/testhost/snapshot/testsnapshot"
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 202)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '(auth configured)' do
|
|
||||||
let(:config) { { auth: true } }
|
|
||||||
|
|
||||||
it 'returns a 401 if not authed' do
|
|
||||||
post "#{prefix}/vm/testhost/snapshot"
|
|
||||||
|
|
||||||
expect_json(ok = false, http = 401)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'reverts to a snapshot if authed' do
|
|
||||||
expect(redis).to receive(:hget).with('vmpooler__vm__testhost', 'snapshot:testsnapshot').and_return(1)
|
|
||||||
expect(redis).to receive(:sadd)
|
|
||||||
|
|
||||||
post "#{prefix}/vm/testhost/snapshot/testsnapshot", "", {
|
|
||||||
'HTTP_X_AUTH_TOKEN' => 'abcdefghijklmnopqrstuvwxyz012345'
|
|
||||||
}
|
|
||||||
|
|
||||||
expect_json(ok = true, http = 202)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
@ -10,6 +10,10 @@ describe Vmpooler::API do
|
||||||
|
|
||||||
describe 'Dashboard' do
|
describe 'Dashboard' do
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
redis.flushdb
|
||||||
|
end
|
||||||
|
|
||||||
context '/' do
|
context '/' do
|
||||||
before { get '/' }
|
before { get '/' }
|
||||||
|
|
||||||
|
|
@ -38,7 +42,6 @@ describe Vmpooler::API do
|
||||||
it { expect(last_response.status).to eq(404) }
|
it { expect(last_response.status).to eq(404) }
|
||||||
it { expect(last_response.header['Content-Type']).to eq('application/json') }
|
it { expect(last_response.header['Content-Type']).to eq('application/json') }
|
||||||
it { expect(last_response.body).to eq(JSON.pretty_generate({ok: false})) }
|
it { expect(last_response.body).to eq(JSON.pretty_generate({ok: false})) }
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '/dashboard/stats/vmpooler/pool' do
|
describe '/dashboard/stats/vmpooler/pool' do
|
||||||
|
|
@ -49,7 +52,6 @@ describe Vmpooler::API do
|
||||||
],
|
],
|
||||||
graphite: {}
|
graphite: {}
|
||||||
} }
|
} }
|
||||||
let(:redis) { double('redis') }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
$config = config
|
$config = config
|
||||||
|
|
@ -59,13 +61,12 @@ describe Vmpooler::API do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without history param' do
|
context 'without history param' do
|
||||||
|
|
||||||
it 'returns basic JSON' do
|
it 'returns basic JSON' do
|
||||||
allow(redis).to receive(:scard)
|
create_ready_vm('pool1', 'vm1')
|
||||||
allow(redis).to receive(:scard).with('vmpooler__ready__pool1').and_return(3)
|
create_ready_vm('pool1', 'vm2')
|
||||||
allow(redis).to receive(:scard).with('vmpooler__ready__pool2').and_return(2)
|
create_ready_vm('pool1', 'vm3')
|
||||||
|
create_ready_vm('pool2', 'vm4')
|
||||||
expect(redis).to receive(:scard).twice
|
create_ready_vm('pool2', 'vm5')
|
||||||
|
|
||||||
get '/dashboard/stats/vmpooler/pool'
|
get '/dashboard/stats/vmpooler/pool'
|
||||||
|
|
||||||
|
|
@ -78,19 +79,15 @@ describe Vmpooler::API do
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(json_hash))
|
expect(last_response.body).to eq(JSON.pretty_generate(json_hash))
|
||||||
expect(last_response.header['Content-Type']).to eq('application/json')
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with history param' do
|
context 'with history param' do
|
||||||
it 'returns JSON with null history when redis does not has values' do
|
it 'returns JSON with zeroed history when redis does not have values' do
|
||||||
allow(redis).to receive(:scard)
|
|
||||||
expect(redis).to receive(:scard).exactly(4).times
|
|
||||||
|
|
||||||
get '/dashboard/stats/vmpooler/pool', :history => true
|
get '/dashboard/stats/vmpooler/pool', :history => true
|
||||||
|
|
||||||
json_hash = {
|
json_hash = {
|
||||||
pool1: {size: 5, ready: nil, history: [nil]},
|
pool1: {size: 5, ready: 0, history: [0]},
|
||||||
pool2: {size: 1, ready: nil, history: [nil]}
|
pool2: {size: 1, ready: 0, history: [0]}
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(last_response).to be_ok
|
expect(last_response).to be_ok
|
||||||
|
|
@ -99,10 +96,11 @@ describe Vmpooler::API do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns JSON with history when redis has values' do
|
it 'returns JSON with history when redis has values' do
|
||||||
allow(redis).to receive(:scard).with('vmpooler__ready__pool1').and_return(3)
|
create_ready_vm('pool1', 'vm1')
|
||||||
allow(redis).to receive(:scard).with('vmpooler__ready__pool2').and_return(2)
|
create_ready_vm('pool1', 'vm2')
|
||||||
|
create_ready_vm('pool1', 'vm3')
|
||||||
expect(redis).to receive(:scard).exactly(4).times
|
create_ready_vm('pool2', 'vm4')
|
||||||
|
create_ready_vm('pool2', 'vm5')
|
||||||
|
|
||||||
get '/dashboard/stats/vmpooler/pool', :history => true
|
get '/dashboard/stats/vmpooler/pool', :history => true
|
||||||
|
|
||||||
|
|
@ -115,9 +113,7 @@ describe Vmpooler::API do
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(json_hash))
|
expect(last_response.body).to eq(JSON.pretty_generate(json_hash))
|
||||||
expect(last_response.header['Content-Type']).to eq('application/json')
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '/dashboard/stats/vmpooler/running' do
|
describe '/dashboard/stats/vmpooler/running' do
|
||||||
|
|
@ -129,7 +125,6 @@ describe Vmpooler::API do
|
||||||
],
|
],
|
||||||
graphite: {}
|
graphite: {}
|
||||||
} }
|
} }
|
||||||
let(:redis) { double('redis') }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
$config = config
|
$config = config
|
||||||
|
|
@ -141,10 +136,6 @@ describe Vmpooler::API do
|
||||||
context 'without history param' do
|
context 'without history param' do
|
||||||
|
|
||||||
it 'returns basic JSON' do
|
it 'returns basic JSON' do
|
||||||
allow(redis).to receive(:scard)
|
|
||||||
|
|
||||||
expect(redis).to receive(:scard).exactly(3).times
|
|
||||||
|
|
||||||
get '/dashboard/stats/vmpooler/running'
|
get '/dashboard/stats/vmpooler/running'
|
||||||
|
|
||||||
json_hash = {pool: {running: 0}, diffpool: {running: 0}}
|
json_hash = {pool: {running: 0}, diffpool: {running: 0}}
|
||||||
|
|
@ -155,9 +146,18 @@ describe Vmpooler::API do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds major correctly' do
|
it 'adds major correctly' do
|
||||||
allow(redis).to receive(:scard).with('vmpooler__running__pool-1').and_return(3)
|
create_running_vm('pool-1', 'vm1')
|
||||||
allow(redis).to receive(:scard).with('vmpooler__running__pool-2').and_return(5)
|
create_running_vm('pool-1', 'vm2')
|
||||||
allow(redis).to receive(:scard).with('vmpooler__running__diffpool-1').and_return(2)
|
create_running_vm('pool-1', 'vm3')
|
||||||
|
|
||||||
|
create_running_vm('pool-2', 'vm4')
|
||||||
|
create_running_vm('pool-2', 'vm5')
|
||||||
|
create_running_vm('pool-2', 'vm6')
|
||||||
|
create_running_vm('pool-2', 'vm7')
|
||||||
|
create_running_vm('pool-2', 'vm8')
|
||||||
|
|
||||||
|
create_running_vm('diffpool-1', 'vm9')
|
||||||
|
create_running_vm('diffpool-1', 'vm10')
|
||||||
|
|
||||||
get '/dashboard/stats/vmpooler/running'
|
get '/dashboard/stats/vmpooler/running'
|
||||||
|
|
||||||
|
|
@ -167,10 +167,7 @@ describe Vmpooler::API do
|
||||||
expect(last_response.body).to eq(JSON.pretty_generate(json_hash))
|
expect(last_response.body).to eq(JSON.pretty_generate(json_hash))
|
||||||
expect(last_response.header['Content-Type']).to eq('application/json')
|
expect(last_response.header['Content-Type']).to eq('application/json')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue