(POOLER-72) Add Dummy Provider

Previously the only VM Provider was vSphere however this made testing and making
changes difficult as it required a functioning vSphere instance.  This commit
adds a Dummy Provider which presents a VM provider to Pool Manager but manages
provisioned "VM"s in a hashtable.  The Dummy Provider can also be configured to
randomly fail operations and take random amounts of time to perform operations,
 such as cloning a VM, which is useful to see how the Pool Manager copes with
these events.

This commit also updates the configuration YAML documentation and adds
appropriate unit tests.
This commit is contained in:
Glenn Sarti 2017-03-31 16:28:34 -07:00
parent d9d45109f2
commit 77afc86aeb
4 changed files with 962 additions and 1 deletions

View file

@ -1,4 +1,4 @@
%w(base vsphere).each do |lib|
%w(base dummy vsphere).each do |lib|
begin
require "vmpooler/providers/#{lib}"
rescue LoadError

View file

@ -0,0 +1,360 @@
require 'yaml'
module Vmpooler
class PoolManager
class Provider
class Dummy < Vmpooler::PoolManager::Provider::Base
# Fake VM Provider for testing
def initialize(config, logger, metrics, name, options)
super(config, logger, metrics, name, options)
dummyfilename = provider_config['filename']
# This initial_state option is only intended to be used by spec tests
@dummylist = provider_options['initial_state'].nil? ? {} : provider_options['initial_state']
@dummylist = YAML.load_file(dummyfilename) if !dummyfilename.nil? && File.exist?(dummyfilename)
# Even though this code is using Mutexes, it's still no 100% atomic i.e. it's still possible for
# duplicate actions to put the @dummylist hashtable into a bad state, for example;
# Deleting a VM while it's in the middle of adding a disk.
@write_lock = Mutex.new
end
def name
'dummy'
end
def vms_in_pool(pool_name)
vmlist = []
get_dummy_pool_object(pool_name).each do |vm|
vmlist << { 'name' => vm['name'] }
end
vmlist
end
def get_vm_host(pool_name, vm_name)
current_vm = get_dummy_vm(pool_name, vm_name)
current_vm.nil? ? raise("VM #{vm_name} does not exist") : current_vm['vm_host']
end
def find_least_used_compatible_host(pool_name, vm_name)
current_vm = get_dummy_vm(pool_name, vm_name)
# Unless migratevm_couldmove_percent is specified, don't migrate
return current_vm['vm_host'] if provider_config['migratevm_couldmove_percent'].nil?
# Only migrate if migratevm_couldmove_percent is met
return current_vm['vm_host'] if 1 + rand(100) > provider_config['migratevm_couldmove_percent']
# Simulate a 10 node cluster and randomly pick a different one
new_host = 'HOST' + (1 + rand(10)).to_s while new_host == current_vm['vm_host']
new_host
end
def migrate_vm_to_host(pool_name, vm_name, dest_host_name)
current_vm = get_dummy_vm(pool_name, vm_name)
# Inject migration delay
unless provider_config['migratevm_max_time'].nil?
migrate_time = 1 + rand(provider_config['migratevm_max_time'])
sleep(migrate_time)
end
# Inject clone failure
unless provider_config['migratevm_fail_percent'].nil?
raise('Dummy Failure for migratevm_fail_percent') if 1 + rand(100) <= provider_config['migratevm_fail_percent']
end
@write_lock.synchronize do
current_vm = get_dummy_vm(pool_name, vm_name)
current_vm['vm_host'] = dest_host_name
write_backing_file
end
true
end
def get_vm(pool_name, vm_name)
dummy = get_dummy_vm(pool_name, vm_name)
return nil if dummy.nil?
# Randomly power off the VM
unless dummy['powerstate'] != 'PoweredOn' || provider_config['getvm_poweroff_percent'].nil?
if 1 + rand(100) <= provider_config['getvm_poweroff_percent']
@write_lock.synchronize do
dummy = get_dummy_vm(pool_name, vm_name)
dummy['powerstate'] = 'PoweredOff'
write_backing_file
end
logger.log('d', "[ ] [#{dummy['poolname']}] '#{dummy['name']}' is being Dummy Powered Off")
end
end
# Randomly rename the host
unless dummy['hostname'] != dummy['name'] || provider_config['getvm_rename_percent'].nil?
if 1 + rand(100) <= provider_config['getvm_rename_percent']
@write_lock.synchronize do
dummy = get_dummy_vm(pool_name, vm_name)
dummy['hostname'] = 'DUMMY' + dummy['name']
write_backing_file
end
logger.log('d', "[ ] [#{dummy['poolname']}] '#{dummy['name']}' is being Dummy renamed")
end
end
obj = {}
obj['name'] = dummy['name']
obj['hostname'] = dummy['hostname']
obj['boottime'] = dummy['boottime']
obj['template'] = dummy['template']
obj['poolname'] = dummy['poolname']
obj['powerstate'] = dummy['powerstate']
obj['snapshots'] = dummy['snapshots']
obj
end
def create_vm(pool_name, dummy_hostname)
pool = pool_config(pool_name)
raise("Pool #{pool_name} does not exist for the provider #{name}") if pool.nil?
template_name = pool['template']
vm = {}
vm['name'] = dummy_hostname
vm['hostname'] = dummy_hostname
vm['domain'] = 'dummy.local'
# 'vm_template' is the name of the template to use to clone the VM from <----- Do we need this?!?!?
vm['vm_template'] = template_name
# 'template' is the Template name in VM Pooler API, in our case that's the poolname.
vm['template'] = pool_name
vm['poolname'] = pool_name
vm['ready'] = false
vm['boottime'] = Time.now
vm['powerstate'] = 'PoweredOn'
vm['vm_host'] = 'HOST1'
vm['dummy_state'] = 'UNKNOWN'
vm['snapshots'] = []
vm['disks'] = []
# Make sure the pool exists in the dummy list
@write_lock.synchronize do
get_dummy_pool_object(pool_name)
@dummylist['pool'][pool_name] << vm
write_backing_file
end
logger.log('d', "[ ] [#{pool_name}] '#{dummy_hostname}' is being cloned from '#{template_name}'")
# Inject clone time delay
unless provider_config['createvm_max_time'].nil?
@write_lock.synchronize do
vm['dummy_state'] = 'CLONING'
write_backing_file
end
clone_time = 1 + rand(provider_config['createvm_max_time'])
sleep(clone_time)
end
begin
# Inject clone failure
unless provider_config['createvm_fail_percent'].nil?
raise('Dummy Failure for createvm_fail_percent') if 1 + rand(100) <= provider_config['createvm_fail_percent']
end
# Assert the VM is ready for use
@write_lock.synchronize do
vm['dummy_state'] = 'RUNNING'
write_backing_file
end
rescue => _err
@write_lock.synchronize do
remove_dummy_vm(pool_name, dummy_hostname)
write_backing_file
end
raise
end
get_vm(pool_name, dummy_hostname)
end
def create_disk(pool_name, vm_name, disk_size)
vm_object = get_dummy_vm(pool_name, vm_name)
raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
# Inject create time delay
unless provider_config['createdisk_max_time'].nil?
delay = 1 + rand(provider_config['createdisk_max_time'])
sleep(delay)
end
# Inject create failure
unless provider_config['createdisk_fail_percent'].nil?
raise('Dummy Failure for createdisk_fail_percent') if 1 + rand(100) <= provider_config['createdisk_fail_percent']
end
@write_lock.synchronize do
vm_object = get_dummy_vm(pool_name, vm_name)
vm_object['disks'] << disk_size
write_backing_file
end
true
end
def create_snapshot(pool_name, vm_name, snapshot_name)
vm_object = get_dummy_vm(pool_name, vm_name)
raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
# Inject create time delay
unless provider_config['createsnapshot_max_time'].nil?
delay = 1 + rand(provider_config['createsnapshot_max_time'])
sleep(delay)
end
# Inject create failure
unless provider_config['createsnapshot_fail_percent'].nil?
raise('Dummy Failure for createsnapshot_fail_percent') if 1 + rand(100) <= provider_config['createsnapshot_fail_percent']
end
@write_lock.synchronize do
vm_object = get_dummy_vm(pool_name, vm_name)
vm_object['snapshots'] << snapshot_name
write_backing_file
end
true
end
def revert_snapshot(pool_name, vm_name, snapshot_name)
vm_object = get_dummy_vm(pool_name, vm_name)
raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
# Inject create time delay
unless provider_config['revertsnapshot_max_time'].nil?
delay = 1 + rand(provider_config['revertsnapshot_max_time'])
sleep(delay)
end
# Inject create failure
unless provider_config['revertsnapshot_fail_percent'].nil?
raise('Dummy Failure for revertsnapshot_fail_percent') if 1 + rand(100) <= provider_config['revertsnapshot_fail_percent']
end
vm_object['snapshots'].include?(snapshot_name)
end
def destroy_vm(pool_name, vm_name)
vm = get_dummy_vm(pool_name, vm_name)
return false if vm.nil?
return false if vm['poolname'] != pool_name
# Shutdown down the VM if it's poweredOn
if vm['powerstate'] == 'PoweredOn'
logger.log('d', "[ ] [#{pool_name}] '#{vm_name}' is being shut down")
# Inject shutdown delay time
unless provider_config['destroyvm_max_shutdown_time'].nil?
shutdown_time = 1 + rand(provider_config['destroyvm_max_shutdown_time'])
sleep(shutdown_time)
end
@write_lock.synchronize do
vm = get_dummy_vm(pool_name, vm_name)
vm['powerstate'] = 'PoweredOff'
write_backing_file
end
end
# Inject destroy VM delay
unless provider_config['destroyvm_max_time'].nil?
destroy_time = 1 + rand(provider_config['destroyvm_max_time'])
sleep(destroy_time)
end
# Inject destroy VM failure
unless provider_config['destroyvm_fail_percent'].nil?
raise('Dummy Failure for migratevm_fail_percent') if 1 + rand(100) <= provider_config['destroyvm_fail_percent']
end
# 'Destroy' the VM
@write_lock.synchronize do
remove_dummy_vm(pool_name, vm_name)
write_backing_file
end
true
end
def vm_ready?(pool_name, vm_name)
vm_object = get_dummy_vm(pool_name, vm_name)
return false if vm_object.nil?
return false if vm_object['poolname'] != pool_name
return true if vm_object['ready']
timeout = provider_config['is_ready_timeout'] || 5
Timeout.timeout(timeout) do
while vm_object['dummy_state'] != 'RUNNING'
sleep(2)
vm_object = get_dummy_vm(pool_name, vm_name)
end
end
# Simulate how long it takes from a VM being powered on until
# it's ready to receive a connection
sleep(2)
unless provider_config['vmready_fail_percent'].nil?
raise('Dummy Failure for vmready_fail_percent') if 1 + rand(100) <= provider_config['vmready_fail_percent']
end
@write_lock.synchronize do
vm_object['ready'] = true
write_backing_file
end
true
end
private
# Note - NEVER EVER use the @write_lock object in the private methods!!!! Deadlocks will ensue
def remove_dummy_vm(pool_name, vm_name)
return if @dummylist['pool'][pool_name].nil?
new_poollist = @dummylist['pool'][pool_name].delete_if { |vm| vm['name'] == vm_name }
@dummylist['pool'][pool_name] = new_poollist
end
# Get's the pool config safely from the in-memory hashtable
def get_dummy_pool_object(pool_name)
@dummylist['pool'] = {} if @dummylist['pool'].nil?
@dummylist['pool'][pool_name] = [] if @dummylist['pool'][pool_name].nil?
@dummylist['pool'][pool_name]
end
def get_dummy_vm(pool_name, vm_name)
return nil if @dummylist['pool'][pool_name].nil?
@dummylist['pool'][pool_name].each do |poolvm|
return poolvm if poolvm['name'] == vm_name
end
nil
end
def write_backing_file
dummyfilename = provider_config['filename']
return if dummyfilename.nil?
File.open(dummyfilename, 'w') { |file| file.write(YAML.dump(@dummylist)) }
end
end
end
end
end

View file

@ -0,0 +1,509 @@
require 'spec_helper'
describe 'Vmpooler::PoolManager::Provider::Dummy' do
let(:logger) { MockLogger.new }
let(:metrics) { Vmpooler::DummyStatsd.new }
let(:pool_name) { 'pool1' }
let(:other_pool_name) { 'pool2' }
let(:vm_name) { 'vm1' }
let(:running_vm_name) { 'vm2' }
let(:notready_vm_name) { 'vm3' }
let (:provider_options) {
# Construct an initial state for testing
dummylist = {}
dummylist['pool'] = {}
# pool1 is a pool of "normal" VMs
dummylist['pool'][pool_name] = []
# A normal running VM
vm = {}
vm['name'] = vm_name
vm['hostname'] = vm_name
vm['domain'] = 'dummy.local'
vm['vm_template'] = 'template1'
vm['template'] = pool_name
vm['poolname'] = pool_name
vm['ready'] = true
vm['boottime'] = Time.now
vm['powerstate'] = 'PoweredOn'
vm['vm_host'] = 'HOST1'
vm['snapshots'] = []
vm['disks'] = []
vm['dummy_state'] = 'RUNNING'
dummylist['pool'][pool_name] << vm
# pool2 is a pool of "abnormal" VMs e.g. PoweredOff etc.
dummylist['pool'][other_pool_name] = []
# A freshly provisioned VM that is not ready
vm = {}
vm['name'] = running_vm_name
vm['hostname'] = running_vm_name
vm['domain'] = 'dummy.local'
vm['vm_template'] = 'template1'
vm['template'] = other_pool_name
vm['poolname'] = other_pool_name
vm['ready'] = false
vm['boottime'] = Time.now
vm['powerstate'] = 'PoweredOn'
vm['vm_host'] = 'HOST1'
vm['snapshots'] = []
vm['disks'] = []
vm['dummy_state'] = 'UNKNOWN'
dummylist['pool'][other_pool_name] << vm
# A freshly provisioned VM that is running but not ready
vm = {}
vm['name'] = notready_vm_name
vm['hostname'] = notready_vm_name
vm['domain'] = 'dummy.local'
vm['vm_template'] = 'template1'
vm['template'] = other_pool_name
vm['poolname'] = other_pool_name
vm['ready'] = false
vm['boottime'] = Time.now
vm['powerstate'] = 'PoweredOn'
vm['vm_host'] = 'HOST1'
vm['snapshots'] = []
vm['disks'] = []
vm['dummy_state'] = 'RUNNING'
dummylist['pool'][other_pool_name] << vm
{
'initial_state' => dummylist
}
}
let(:config) { YAML.load(<<-EOT
---
:config:
max_tries: 3
retry_factor: 10
:providers:
:dummy:
key1: 'value1'
:pools:
- name: '#{pool_name}'
size: 5
- name: 'pool2'
size: 5
EOT
)
}
subject { Vmpooler::PoolManager::Provider::Dummy.new(config, logger, metrics, 'dummy', provider_options) }
describe '#name' do
it 'should be dummy' do
expect(subject.name).to eq('dummy')
end
end
describe '#vms_in_pool' do
it 'should return [] when pool does not exist' do
vm_list = subject.vms_in_pool('missing_pool')
expect(vm_list).to eq([])
end
it 'should return an array of VMs when pool exists' do
vm_list = subject.vms_in_pool(pool_name)
expect(vm_list.count).to eq(1)
end
end
describe '#get_vm_host' do
it 'should return the hostname when VM exists' do
expect(subject.get_vm_host(pool_name, vm_name)).to eq('HOST1')
end
it 'should error when VM does not exist' do
expect{subject.get_vm_host(pool_name, 'doesnotexist')}.to raise_error(RuntimeError)
end
end
describe '#find_least_used_compatible_host' do
it 'should return the current host' do
new_host = subject.find_least_used_compatible_host(pool_name, vm_name)
expect(new_host).to eq('HOST1')
end
context 'using migratevm_couldmove_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['migratevm_couldmove_percent'] = 0
end
it 'should return the current host' do
new_host = subject.find_least_used_compatible_host(pool_name, vm_name)
expect(new_host).to eq('HOST1')
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['migratevm_couldmove_percent'] = 100
end
it 'should return a different host' do
new_host = subject.find_least_used_compatible_host(pool_name, vm_name)
expect(new_host).to_not eq('HOST1')
end
end
end
end
describe '#migrate_vm_to_host' do
it 'should move to the new host' do
expect(subject.migrate_vm_to_host(pool_name, 'vm1','NEWHOST')).to eq(true)
expect(subject.get_vm_host(pool_name, 'vm1')).to eq('NEWHOST')
end
context 'using migratevm_fail_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['migratevm_fail_percent'] = 0
end
it 'should move to the new host' do
expect(subject.migrate_vm_to_host(pool_name, 'vm1','NEWHOST')).to eq(true)
expect(subject.get_vm_host(pool_name, 'vm1')).to eq('NEWHOST')
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['migratevm_fail_percent'] = 100
end
it 'should raise an error' do
expect{subject.migrate_vm_to_host(pool_name, 'vm1','NEWHOST')}.to raise_error(/migratevm_fail_percent/)
end
end
end
end
describe '#get_vm' do
it 'should return the VM when VM exists' do
vm = subject.get_vm(pool_name, vm_name)
expect(vm['name']).to eq(vm_name)
expect(vm['powerstate']).to eq('PoweredOn')
expect(vm['hostname']).to eq(vm['name'])
end
it 'should return nil when VM does not exist' do
expect(subject.get_vm(pool_name, 'doesnotexist')).to eq(nil)
end
context 'using getvm_poweroff_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['getvm_poweroff_percent'] = 0
end
it 'will not power off a VM' do
vm = subject.get_vm(pool_name, vm_name)
expect(vm['name']).to eq(vm_name)
expect(vm['powerstate']).to eq('PoweredOn')
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['getvm_poweroff_percent'] = 100
end
it 'will power off a VM' do
vm = subject.get_vm(pool_name, vm_name)
expect(vm['name']).to eq(vm_name)
expect(vm['powerstate']).to eq('PoweredOff')
end
end
end
context 'using getvm_rename_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['getvm_rename_percent'] = 0
end
it 'will not rename a VM' do
vm = subject.get_vm(pool_name, vm_name)
expect(vm['name']).to eq(vm_name)
expect(vm['hostname']).to eq(vm['name'])
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['getvm_rename_percent'] = 100
end
it 'will rename a VM' do
vm = subject.get_vm(pool_name, vm_name)
expect(vm['name']).to eq(vm_name)
expect(vm['hostname']).to_not eq(vm['name'])
end
end
end
end
describe '#create_vm' do
let(:new_vm_name) { 'newvm' }
it 'should return a new VM' do
expect(subject.create_vm(pool_name, new_vm_name)['name']).to eq(new_vm_name)
end
it 'should increase the number of VMs in the pool' do
old_pool_count = subject.vms_in_pool(pool_name).count
new_vm = subject.create_vm(pool_name, new_vm_name)
expect(subject.vms_in_pool(pool_name).count).to eq(old_pool_count + 1)
end
context 'using createvm_fail_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['createvm_fail_percent'] = 0
end
it 'should return a new VM' do
expect(subject.create_vm(pool_name, new_vm_name)['name']).to eq(new_vm_name)
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['createvm_fail_percent'] = 100
end
it 'should raise an error' do
expect{subject.create_vm(pool_name, new_vm_name)}.to raise_error(/createvm_fail_percent/)
end
it 'new VM should not exist' do
begin
subject.create_vm(pool_name, new_vm_name)
rescue
end
expect(subject.get_vm(pool_name, new_vm_name)).to eq(nil)
end
end
end
end
describe '#create_disk' do
let(:disk_size) { 10 }
it 'should return true when the disk is created' do
expect(subject.create_disk(pool_name, vm_name,disk_size)).to be true
end
it 'should raise an error when VM does not exist' do
expect{ subject.create_disk(pool_name, 'doesnotexist',disk_size) }.to raise_error(/VM doesnotexist does not exist/)
end
context 'using createdisk_fail_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['createdisk_fail_percent'] = 0
end
it 'should return true when the disk is created' do
expect(subject.create_disk(pool_name, vm_name,disk_size)).to be true
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['createdisk_fail_percent'] = 100
end
it 'should raise an error' do
expect{subject.create_disk(pool_name, vm_name,disk_size)}.to raise_error(/createdisk_fail_percent/)
end
end
end
end
describe '#create_snapshot' do
let(:snapshot_name) { 'newsnapshot' }
it 'should return true when the snapshot is created' do
expect(subject.create_snapshot(pool_name, vm_name, snapshot_name)).to be true
end
it 'should raise an error when VM does not exist' do
expect{ subject.create_snapshot(pool_name, 'doesnotexist', snapshot_name) }.to raise_error(/VM doesnotexist does not exist/)
end
context 'using createsnapshot_fail_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['createsnapshot_fail_percent'] = 0
end
it 'should return true when the disk is created' do
expect(subject.create_snapshot(pool_name, vm_name, snapshot_name)).to be true
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['createsnapshot_fail_percent'] = 100
end
it 'should raise an error' do
expect{ subject.create_snapshot(pool_name, vm_name, snapshot_name) }.to raise_error(/createsnapshot_fail_percent/)
end
end
end
end
describe '#revert_snapshot' do
let(:snapshot_name) { 'newsnapshot' }
before(:each) do
# Create a snapshot
subject.create_snapshot(pool_name, vm_name, snapshot_name)
end
it 'should return true when the snapshot is reverted' do
expect(subject.revert_snapshot(pool_name, vm_name, snapshot_name)).to be true
end
it 'should raise an error when VM does not exist' do
expect{ subject.revert_snapshot(pool_name, 'doesnotexist', snapshot_name) }.to raise_error(/VM doesnotexist does not exist/)
end
it 'should return false when the snapshot does not exist' do
expect(subject.revert_snapshot(pool_name, vm_name, 'doesnotexist')).to be false
end
context 'using revertsnapshot_fail_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['revertsnapshot_fail_percent'] = 0
end
it 'should return true when the snapshot is reverted' do
expect(subject.revert_snapshot(pool_name, vm_name, snapshot_name)).to be true
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['revertsnapshot_fail_percent'] = 100
end
it 'should raise an error when VM does not exist' do
expect{ subject.revert_snapshot(pool_name, vm_name, snapshot_name) }.to raise_error(/revertsnapshot_fail_percent/)
end
end
end
end
describe '#destroy_vm' do
it 'should return true when destroyed' do
expect(subject.destroy_vm(pool_name, vm_name)).to eq(true)
end
it 'should log if the VM is powered off' do
allow(logger).to receive(:log)
expect(logger).to receive(:log).with('d', "[ ] [pool1] 'vm1' is being shut down")
expect(subject.destroy_vm(pool_name, vm_name)).to eq(true)
end
it 'should return false if VM does not exist' do
expect(subject.destroy_vm('doesnotexist',vm_name)).to eq(false)
end
it 'should return false if VM is not in the correct pool' do
expect(subject.destroy_vm(other_pool_name, vm_name)).to eq(false)
end
context 'using destroyvm_fail_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['destroyvm_fail_percent'] = 0
end
it 'should return true when destroyed' do
expect(subject.destroy_vm(pool_name, vm_name)).to eq(true)
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['destroyvm_fail_percent'] = 100
end
it 'should raise an error' do
expect{subject.destroy_vm(pool_name, vm_name)}.to raise_error(/migratevm_fail_percent/)
end
end
end
end
describe '#vm_ready?' do
before(:each) do
# Speed up tests and ignore sleeping
allow(subject).to receive(:sleep)
end
it 'should return true if ready' do
expect(subject.vm_ready?(pool_name, vm_name)).to eq(true)
end
it 'should return false if VM does not exist' do
expect(subject.vm_ready?(pool_name, 'doesnotexist')).to eq(false)
end
it 'should return false if VM is not in the correct pool' do
expect(subject.vm_ready?(other_pool_name, vm_name)).to eq(false)
end
it 'should raise an error if timeout expires' do
expect{subject.vm_ready?(other_pool_name, running_vm_name)}.to raise_error(Timeout::Error)
end
it 'should return true if VM becomes ready' do
expect(subject.vm_ready?(other_pool_name, notready_vm_name)).to eq(true)
end
context 'using vmready_fail_percent' do
describe 'of zero' do
before(:each) do
config[:providers][:dummy]['vmready_fail_percent'] = 0
end
it 'should return true if VM becomes ready' do
expect(subject.vm_ready?(other_pool_name, notready_vm_name)).to eq(true)
end
end
describe 'of 100' do
before(:each) do
config[:providers][:dummy]['vmready_fail_percent'] = 100
end
it 'should raise an error' do
expect{subject.vm_ready?(other_pool_name, notready_vm_name)}.to raise_error(/vmready_fail_percent/)
end
end
end
end
describe '#vm_exists?' do
it 'should return true when VM exists' do
expect(subject.vm_exists?(pool_name, vm_name)).to eq(true)
end
it 'should return true when VM does not exist' do
expect(subject.vm_exists?(pool_name, 'doesnotexist')).to eq(false)
end
end
end

View file

@ -25,6 +25,98 @@
username: 'vmpooler'
password: 'swimsw1msw!m'
:providers:
# :providers:
#
# This section contains the VM providers for VMs and Pools
# The currently supported backing services are:
# - dummy
# :dummy:
#
# The dummy backing service is a simple text file service that can be used
# to test vmpooler operations in a development or test environment
#
# Available configuration parameters:
#
# - filename (Optional)
# The filename used to store the backing text file. If this is not specified the VM state is only
# kept in memory, and is lost when the Provider is shutdown
#
# - migratevm_couldmove_percent
# Percent chance that a VM could be moved to another host
# (optional; default 0%)
#
# - migratevm_max_time
# Maximum amount of random time a VM migration action will take in seconds
# (optional; default 0 seconds)
#
# - migratevm_fail_percent
# Percent chance that a VM migration action will fail
# (optional; default 0%)
#
# - getvm_poweroff_percent
# Percent chance that when the VM information is gathered that the VM will be powered off
# (optional; default 0%)
#
# - getvm_rename_percent
# Percent chance that when the VM information is gathered that the VM will be renamed
# (optional; default 0%)
#
# - createvm_max_time
# Maximum amount of random time a VM creation action will take, in seconds
# (optional; default 0 seconds)
#
# - createvm_fail_percent
# Percent chance that a VM creation action will fail
# (optional; default 0%)
#
# - createdisk_max_time
# Maximum amount of random time a VM create disk action will take, in seconds
# (optional; default 0 seconds)
#
# - createdisk_fail_percent
# Percent chance that a VM create disk action will fail
# (optional; default 0%)
#
# - createsnapshot_max_time
# Maximum amount of random time a VM create snapshot action will take, in seconds
# (optional; default 0 seconds)
#
# - createsnapshot_fail_percent
# Percent chance that a VM create snapshot action will fail
# (optional; default 0%)
#
# - revertsnapshot_max_time
# Maximum amount of random time a VM revert snapshot action will take, in seconds
# (optional; default 0 seconds)
#
# - revertsnapshot_fail_percent
# Percent chance that a VM revert snapshot action will fail
# (optional; default 0%)
#
# - destroyvm_max_shutdown_time
# Maximum amount of random time a VM shutdown action will take during destroy, in seconds
# (optional; default 0 seconds)
#
# - destroyvm_max_time
# Maximum amount of random time a VM destroy action will take, in seconds
# (optional; default 0 seconds)
#
# - destroyvm_fail_percent
# Percent chance that a VM destroy action will fail
# (optional; default 0%)
#
# - vmready_fail_percent
# Percent chance that an error is raised when vm_ready? is called
# (optional; default 0%)
# Example:
:dummy:
filename: '/tmp/dummy-backing.yaml'
# :redis:
#
# This section contains the server hostname and authentication credentials