diff --git a/lib/vmpooler.rb b/lib/vmpooler.rb index 26c3faf..953dac1 100644 --- a/lib/vmpooler.rb +++ b/lib/vmpooler.rb @@ -12,7 +12,7 @@ module Vmpooler require 'yaml' require 'set' - %w(api graphite logger pool_manager vsphere_helper statsd dummy_statsd).each do |lib| + %w(api graphite logger pool_manager vsphere_helper statsd dummy_statsd providers).each do |lib| begin require "vmpooler/#{lib}" rescue LoadError diff --git a/lib/vmpooler/providers.rb b/lib/vmpooler/providers.rb new file mode 100644 index 0000000..eb35436 --- /dev/null +++ b/lib/vmpooler/providers.rb @@ -0,0 +1,7 @@ +%w( base vsphere ).each do |lib| + begin + require "vmpooler/providers/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'providers', lib)) + end +end diff --git a/lib/vmpooler/providers/base.rb b/lib/vmpooler/providers/base.rb new file mode 100644 index 0000000..4e7877b --- /dev/null +++ b/lib/vmpooler/providers/base.rb @@ -0,0 +1,107 @@ +module Vmpooler + class PoolManager + class Provider + class Base + # These defs must be overidden in child classes + + def initialize(options) + @provider_options = options + end + + # returns + # [String] Name of the provider service + def name + 'base' + end + + # inputs + # pool : hashtable from config file + # returns + # hashtable + # name : name of the device <---- TODO is this all? + def vms_in_pool(pool) + fail "#{self.class.name} does not implement vms_in_pool" + end + + # inputs + # vm_name: string + # returns + # [String] hostname = Name of the host computer running the vm. If this is not a Virtual Machine, it returns the vm_name + def get_vm_host(vm_name) + fail "#{self.class.name} does not implement get_vm_host" + end + + # inputs + # vm_name: string + # returns + # [String] hostname = Name of the most appropriate host computer to run this VM. Useful for load balancing VMs in a cluster + # If this is not a Virtual Machine, it returns the vm_name + def find_least_used_compatible_host(vm_name) + fail "#{self.class.name} does not implement find_least_used_compatible_host" + end + + # inputs + # vm_name: string + # dest_host_name: string (Name of the host to migrate `vm_name` to) + # returns + # [Boolean] Returns true on success or false on failure + def migrate_vm_to_host(vm_name, dest_host_name) + fail "#{self.class.name} does not implement migrate_vm_to_host" + end + + # inputs + # vm_name: string + # returns + # nil if it doesn't exist + # Hastable of the VM + # [String] name = Name of the VM + # [String] hostname = Name reported by Vmware tools (host.summary.guest.hostName) + # [String] template = This is the name of template exposed by the API. It must _match_ the poolname + # [String] poolname = Name of the pool the VM is located + # [Time] boottime = Time when the VM was created/booted + # [String] powerstate = Current power state of a VM. Valid values (as per vCenter API) + # - 'PoweredOn','PoweredOff' + def get_vm(vm_name) + fail "#{self.class.name} does not implement get_vm" + end + + # inputs + # pool : hashtable from config file + # new_vmname : string Name the new VM should use + # returns + # Hashtable of the VM as per get_vm + def create_vm(pool,new_vmname) + fail "#{self.class.name} does not implement create_vm" + end + + # inputs + # vm_name: string + # pool: string + # returns + # boolean : true if success, false on error + def destroy_vm(vm_name,pool) + fail "#{self.class.name} does not implement destroy_vm" + end + + # inputs + # vm : string + # pool: string + # timeout: int (Seconds) + # returns + # result: boolean + def is_vm_ready?(vm,pool,timeout) + fail "#{self.class.name} does not implement is_vm_ready?" + end + + # inputs + # vm : string + # returns + # result: boolean + def vm_exists?(vm) + !get_vm(vm).nil? + end + + end + end + end +end diff --git a/spec/unit/providers/base_spec.rb b/spec/unit/providers/base_spec.rb new file mode 100644 index 0000000..24f2b7c --- /dev/null +++ b/spec/unit/providers/base_spec.rb @@ -0,0 +1,92 @@ +require 'spec_helper' + +# This spec does not really exercise code paths but is merely used +# to enforce that certain methods are defined in the base classes + +describe 'Vmpooler::PoolManager::Provider::Base' do + let(:config) { {} } + let(:fake_vm) { + fake_vm = {} + fake_vm['name'] = 'vm1' + fake_vm['hostname'] = 'vm1' + fake_vm['template'] = 'pool1' + fake_vm['boottime'] = Time.now + fake_vm['powerstate'] = 'PoweredOn' + + fake_vm + } + + subject { Vmpooler::PoolManager::Provider::Base.new(config) } + + describe '#name' do + it 'should be base' do + expect(subject.name).to eq('base') + end + end + + describe '#vms_in_pool' do + it 'should raise error' do + expect{subject.vms_in_pool('pool')}.to raise_error(/does not implement vms_in_pool/) + end + end + + describe '#get_vm_host' do + it 'should raise error' do + expect{subject.get_vm_host('vm')}.to raise_error(/does not implement get_vm_host/) + end + end + + describe '#find_least_used_compatible_host' do + it 'should raise error' do + expect{subject.find_least_used_compatible_host('vm')}.to raise_error(/does not implement find_least_used_compatible_host/) + end + end + + describe '#migrate_vm_to_host' do + it 'should raise error' do + expect{subject.migrate_vm_to_host('vm','host')}.to raise_error(/does not implement migrate_vm_to_host/) + end + end + + describe '#get_vm' do + it 'should raise error' do + expect{subject.get_vm('vm')}.to raise_error(/does not implement get_vm/) + end + end + + describe '#create_vm' do + it 'should raise error' do + expect{subject.create_vm('pool','newname')}.to raise_error(/does not implement create_vm/) + end + end + + describe '#destroy_vm' do + it 'should raise error' do + expect{subject.destroy_vm('vm','pool')}.to raise_error(/does not implement destroy_vm/) + end + end + + describe '#is_vm_ready?' do + it 'should raise error' do + expect{subject.is_vm_ready?('vm','pool','timeout')}.to raise_error(/does not implement is_vm_ready?/) + end + end + + describe '#vm_exists?' do + it 'should raise error' do + expect{subject.vm_exists?('vm')}.to raise_error(/does not implement/) + end + + it 'should return true when get_vm returns an object' do + allow(subject).to receive(:get_vm).with('vm').and_return(fake_vm) + + expect(subject.vm_exists?('vm')).to eq(true) + end + + it 'should return false when get_vm returns nil' do + allow(subject).to receive(:get_vm).with('vm').and_return(nil) + + expect(subject.vm_exists?('vm')).to eq(false) + end + end +end