Compare commits

..

No commits in common. "main" and "0.2.0" have entirely different histories.
main ... 0.2.0

15 changed files with 456 additions and 191 deletions

View file

@ -1,7 +0,0 @@
version: 2
updates:
- package-ecosystem: bundler
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10

View file

@ -1,39 +0,0 @@
name: Release
on: workflow_dispatch
jobs:
release:
runs-on: ubuntu-latest
if: github.repository == 'puppetlabs/beaker-vmpooler'
steps:
- uses: actions/checkout@v3
- name: Get Version
id: gv
run: |
version=$(grep VERSION lib/beaker-vmpooler/version.rb |rev |cut -d "'" -f2 |rev)
echo "version=$version" >> $GITHUB_OUTPUT
echo "Found version $version from lib/beaker-vmpooler/version.rb"
- name: Tag Release
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.gv.outputs.version }}
token: ${{ secrets.GITHUB_TOKEN }}
draft: false
prerelease: false
generateReleaseNotes: true
- name: Install Ruby 2.7
uses: ruby/setup-ruby@v1
with:
ruby-version: '2.7'
- name: Build gem
run: gem build *.gemspec
- name: Publish gem
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem push *.gem
env:
GEM_HOST_API_KEY: '${{ secrets.RUBYGEMS_AUTH_TOKEN }}'

View file

@ -1,39 +0,0 @@
name: Security
on:
workflow_dispatch:
push:
branches:
- main
jobs:
scan:
name: Mend Scanning
runs-on: ubuntu-latest
steps:
- name: checkout repo content
uses: actions/checkout@v3
with:
fetch-depth: 1
- name: setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
# setup a package lock if one doesn't exist, otherwise do nothing
- name: check lock
run: '[ -f "Gemfile.lock" ] && echo "package lock file exists, skipping" || bundle lock'
# install java
- uses: actions/setup-java@v3
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
# download mend
- name: download_mend
run: curl -o wss-unified-agent.jar https://unified-agent.s3.amazonaws.com/wss-unified-agent.jar
- name: run mend
run: java -jar wss-unified-agent.jar
env:
WS_APIKEY: ${{ secrets.MEND_API_KEY }}
WS_WSS_URL: https://saas-eu.whitesourcesoftware.com/agent
WS_USERKEY: ${{ secrets.MEND_TOKEN }}
WS_PRODUCTNAME: RE
WS_PROJECTNAME: ${{ github.event.repository.name }}

View file

@ -1,26 +0,0 @@
name: Testing
on:
pull_request:
branches:
- main
jobs:
spec_tests:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version:
- '2.7'
- '3.0'
- '3.1'
- '3.2'
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Run spec tests
run: bundle exec rake test

View file

@ -1,2 +0,0 @@
* @puppetlabs/release-engineering

11
Gemfile
View file

@ -1,6 +1,8 @@
source ENV['GEM_SOURCE'] || "https://rubygems.org" source ENV['GEM_SOURCE'] || "https://rubygems.org"
gemspec :development_group => :acceptance_testing gemspec
def location_for(place, fake_version = nil) def location_for(place, fake_version = nil)
if place =~ /^(git:[^#]*)#(.*)/ if place =~ /^(git:[^#]*)#(.*)/
@ -12,13 +14,14 @@ def location_for(place, fake_version = nil)
end end
end end
# We don't put beaker in as a test dependency because we # We don't put beaker in as a test dependency because we
# don't want to create a transitive dependency # don't want to create a transitive dependency
group :acceptance_testing do group :acceptance_testing do
gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '>= 5.0', '< 7') gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '~> 3.0')
gem "beaker-abs"
end end
if File.exist? "#{__FILE__}.local"
if File.exists? "#{__FILE__}.local"
eval(File.read("#{__FILE__}.local"), binding) eval(File.read("#{__FILE__}.local"), binding)
end end

View file

@ -4,26 +4,7 @@ Beaker library to use vmpooler hypervisor
# How to use this wizardry # How to use this wizardry
This is a gem that allows you to use hosts with [vmpooler](vmpooler.md) hypervisor with [beaker](https://github.com/puppetlabs/beaker). This is a gem that allows you to use hosts with [vmpooler](vmpooler.md) hypervisor with [beaker](https://github.com/puppetlabs/beaker). This gem is already included as [beaker dependency](https://github.com/puppetlabs/beaker/blob/master/beaker.gemspec#L59) for you, so you don't need to do anything special to use this gem's functionality with beaker.
Beaker will automatically load the appropriate hypervisors for any given hosts file, so as long as your project dependencies are satisfied there's nothing else to do. No need to `require` this library in your tests.
## With Beaker 3.x
This library is included as a dependency of Beaker 3.x versions, so there's nothing to do.
## With Beaker 4.x
As of Beaker 4.0, all hypervisor and DSL extension libraries have been removed and are no longer dependencies. In order to use a specific hypervisor or DSL extension library in your project, you will need to include them alongside Beaker in your Gemfile or project.gemspec. E.g.
~~~ruby
# Gemfile
gem 'beaker', '~>4.0'
gem 'beaker-vmpooler'
# project.gemspec
s.add_runtime_dependency 'beaker', '~>4.0'
s.add_runtime_dependency 'beaker-vmpooler'
~~~
# Spec tests # Spec tests

View file

@ -20,12 +20,11 @@ Runs the base beaker acceptance test using the hypervisor library
beaker_gem_spec = Gem::Specification.find_by_name('beaker') beaker_gem_spec = Gem::Specification.find_by_name('beaker')
beaker_gem_dir = beaker_gem_spec.gem_dir beaker_gem_dir = beaker_gem_spec.gem_dir
beaker_test_base_dir = File.join(beaker_gem_dir, 'acceptance/tests/base') beaker_test_base_dir = File.join(beaker_gem_dir, 'acceptance/tests/base')
beaker_hosts = ENV['BEAKER_HOSTS'] || 'redhat7-64af-64default.mdcal'
load_path_option = File.join(beaker_gem_dir, 'acceptance/lib') load_path_option = File.join(beaker_gem_dir, 'acceptance/lib')
sh("beaker", sh("beaker",
"--tests", beaker_test_base_dir, "--tests", beaker_test_base_dir,
"--log-level", "verbose", "--log-level", "verbose",
"--hosts", beaker_hosts, "--hosts", "redhat7-64af-redhat7-64default.mdcal",
"--load-path", load_path_option, "--load-path", load_path_option,
"--keyfile", ENV['KEY'] || "#{ENV['HOME']}/.ssh/id_rsa-acceptance") "--keyfile", ENV['KEY'] || "#{ENV['HOME']}/.ssh/id_rsa-acceptance")
end end

View file

@ -20,8 +20,8 @@ Gem::Specification.new do |s|
# Testing dependencies # Testing dependencies
s.add_development_dependency 'rspec', '~> 3.0' s.add_development_dependency 'rspec', '~> 3.0'
s.add_development_dependency 'rspec-its' s.add_development_dependency 'rspec-its'
s.add_development_dependency 'fakefs', '~> 2.4' s.add_development_dependency 'fakefs', '~> 0.6'
s.add_development_dependency 'rake', '~> 13.0' s.add_development_dependency 'rake', '~> 10.1'
s.add_development_dependency 'simplecov' s.add_development_dependency 'simplecov'
s.add_development_dependency 'pry', '~> 0.10' s.add_development_dependency 'pry', '~> 0.10'
@ -32,6 +32,7 @@ Gem::Specification.new do |s|
# Run time dependencies # Run time dependencies
s.add_runtime_dependency 'stringify-hash', '~> 0.0.0' s.add_runtime_dependency 'stringify-hash', '~> 0.0.0'
s.add_runtime_dependency 'rbvmomi', '~> 1.9'
end end

View file

@ -1,3 +1,3 @@
module BeakerVmpooler module BeakerVmpooler
VERSION = '1.4.0' VERSION = '0.2.0'
end end

View file

@ -0,0 +1,238 @@
require 'yaml' unless defined?(YAML)
require 'beaker/hypervisor/vmpooler'
module Beaker
class Vcloud < Beaker::Hypervisor
def self.new(vcloud_hosts, options)
if options['pooling_api']
Beaker::Vmpooler.new(vcloud_hosts, options)
else
super
end
end
def initialize(vcloud_hosts, options)
@options = options
@logger = options[:logger]
@hosts = vcloud_hosts
raise 'You must specify a datastore for vCloud instances!' unless @options['datastore']
raise 'You must specify a folder for vCloud instances!' unless @options['folder']
raise 'You must specify a datacenter for vCloud instances!' unless @options['datacenter']
@vsphere_credentials = VsphereHelper.load_config(@options[:dot_fog])
end
def connect_to_vsphere
@logger.notify "Connecting to vSphere at #{@vsphere_credentials[:server]}" +
" with credentials for #{@vsphere_credentials[:user]}"
@vsphere_helper = VsphereHelper.new( @vsphere_credentials )
end
def wait_for_dns_resolution host, try, attempts
@logger.notify "Waiting for #{host['vmhostname']} DNS resolution"
begin
Socket.getaddrinfo(host['vmhostname'], nil)
rescue
if try <= attempts
sleep 5
try += 1
retry
else
raise "DNS resolution failed after #{@options[:timeout].to_i} seconds"
end
end
end
def booting_host host, try, attempts
@logger.notify "Booting #{host['vmhostname']} (#{host.name}) and waiting for it to register with vSphere"
until
@vsphere_helper.find_vms(host['vmhostname'])[host['vmhostname']].summary.guest.toolsRunningStatus == 'guestToolsRunning' and
@vsphere_helper.find_vms(host['vmhostname'])[host['vmhostname']].summary.guest.ipAddress != nil
if try <= attempts
sleep 5
try += 1
else
raise "vSphere registration failed after #{@options[:timeout].to_i} seconds"
end
end
end
# Directly borrowed from openstack hypervisor
def enable_root(host)
if host['user'] != 'root'
copy_ssh_to_root(host, @options)
enable_root_login(host, @options)
host['user'] = 'root'
host.close
end
end
def create_clone_spec host
# Add VM annotation
configSpec = RbVmomi::VIM.VirtualMachineConfigSpec(
:annotation =>
'Base template: ' + host['template'] + "\n" +
'Creation time: ' + Time.now.strftime("%Y-%m-%d %H:%M") + "\n\n" +
'CI build link: ' + ( ENV['BUILD_URL'] || 'Deployed independently of CI' ) +
'department: ' + @options[:department] +
'project: ' + @options[:project],
:extraConfig => [
{ :key => 'guestinfo.hostname',
:value => host['vmhostname']
}
]
)
# Are we using a customization spec?
customizationSpec = @vsphere_helper.find_customization( host['template'] )
if customizationSpec
# Print a logger message if using a customization spec
@logger.notify "Found customization spec for '#{host['template']}', will apply after boot"
end
# Put the VM in the specified folder and resource pool
relocateSpec = RbVmomi::VIM.VirtualMachineRelocateSpec(
:datastore => @vsphere_helper.find_datastore(@options['datacenter'],@options['datastore']),
:pool => @options['resourcepool'] ? @vsphere_helper.find_pool(@options['datacenter'],@options['resourcepool']) : nil,
:diskMoveType => :moveChildMostDiskBacking
)
# Create a clone spec
spec = RbVmomi::VIM.VirtualMachineCloneSpec(
:config => configSpec,
:location => relocateSpec,
:customization => customizationSpec,
:powerOn => true,
:template => false
)
spec
end
def provision
connect_to_vsphere
begin
try = 1
attempts = @options[:timeout].to_i / 5
start = Time.now
tasks = []
@hosts.each_with_index do |h, i|
if h['name']
h['vmhostname'] = h['name']
else
h['vmhostname'] = generate_host_name
end
if h['template'].nil? and defined?(ENV['BEAKER_vcloud_template'])
h['template'] = ENV['BEAKER_vcloud_template']
end
raise "Missing template configuration for #{h}. Set template in nodeset or set ENV[BEAKER_vcloud_template]" unless h['template']
if h['template'] =~ /\//
templatefolders = h['template'].split('/')
h['template'] = templatefolders.pop
end
@logger.notify "Deploying #{h['vmhostname']} (#{h.name}) to #{@options['folder']} from template '#{h['template']}'"
vm = {}
if templatefolders
vm[h['template']] = @vsphere_helper.find_folder(@options['datacenter'],templatefolders.join('/')).find(h['template'])
else
vm = @vsphere_helper.find_vms(h['template'])
end
if vm.length == 0
raise "Unable to find template '#{h['template']}'!"
end
spec = create_clone_spec(h)
# Deploy from specified template
tasks << vm[h['template']].CloneVM_Task( :folder => @vsphere_helper.find_folder(@options['datacenter'],@options['folder']), :name => h['vmhostname'], :spec => spec )
end
try = (Time.now - start) / 5
@vsphere_helper.wait_for_tasks(tasks, try, attempts)
@logger.notify 'Spent %.2f seconds deploying VMs' % (Time.now - start)
try = (Time.now - start) / 5
duration = run_and_report_duration do
@hosts.each_with_index do |h, i|
booting_host(h, try, attempts)
end
end
@logger.notify "Spent %.2f seconds booting and waiting for vSphere registration" % duration
try = (Time.now - start) / 5
duration = run_and_report_duration do
@hosts.each do |host|
repeat_fibonacci_style_for 8 do
@vsphere_helper.find_vms(host['vmhostname'])[host['vmhostname']].summary.guest.ipAddress != nil
end
host[:ip] = @vsphere_helper.find_vms(host['vmhostname'])[host['vmhostname']].summary.guest.ipAddress
enable_root(host)
end
end
@logger.notify "Spent %.2f seconds waiting for DNS resolution" % duration
rescue => e
@vsphere_helper.close
report_and_raise(@logger, e, "Vcloud.provision")
end
end
def cleanup
@logger.notify "Destroying vCloud boxes"
connect_to_vsphere
vm_names = @hosts.map {|h| h['vmhostname'] }.compact
if @hosts.length != vm_names.length
@logger.warn "Some hosts did not have vmhostname set correctly! This likely means VM provisioning was not successful"
end
vms = @vsphere_helper.find_vms vm_names
begin
vm_names.each do |name|
unless vm = vms[name]
@logger.warn "Unable to cleanup #{name}, couldn't find VM #{name} in vSphere!"
next
end
if vm.runtime.powerState == 'poweredOn'
@logger.notify "Shutting down #{vm.name}"
duration = run_and_report_duration do
vm.PowerOffVM_Task.wait_for_completion
end
@logger.notify "Spent %.2f seconds halting #{vm.name}" % duration
end
duration = run_and_report_duration do
vm.Destroy_Task
end
@logger.notify "Spent %.2f seconds destroying #{vm.name}" % duration
end
rescue RbVmomi::Fault => ex
if ex.fault.is_a?(RbVmomi::VIM::ManagedObjectNotFound)
#it's already gone, don't bother trying to delete it
name = vms.key(ex.fault.obj)
vms.delete(name)
vm_names.delete(name)
@logger.warn "Unable to destroy #{name}, it was not found in vSphere"
retry
end
end
@vsphere_helper.close
end
end
end

View file

@ -27,21 +27,33 @@ module Beaker
def load_credentials(dot_fog = '.fog') def load_credentials(dot_fog = '.fog')
creds = {} creds = {}
begin
fog = get_fog_credentials(dot_fog) if fog = read_fog_file(dot_fog)
if fog[:vmpooler_token] if fog[:default] && fog[:default][:vmpooler_token]
creds[:vmpooler_token] = fog[:vmpooler_token] creds[:vmpooler_token] = fog[:default][:vmpooler_token]
else else
@logger.warn "vmpooler_token not found in credentials file (#{dot_fog})\nProceeding without authentication" @logger.warn "Credentials file (#{dot_fog}) is missing a :default section with a :vmpooler_token value; proceeding without authentication"
end end
rescue ArgumentError => e else
@logger.warn "Invalid credentials file:\n(#{e.class}) #{e.message}\nProceeding without authentication" @logger.warn "Credentials file (#{dot_fog}) is empty; proceeding without authentication"
end end
creds
rescue TypeError, Psych::SyntaxError => e
@logger.warn "#{e.class}: Credentials file (#{dot_fog}) has invalid syntax; proceeding without authentication"
creds
rescue Errno::ENOENT
@logger.warn "Credentials file (#{dot_fog}) not found; proceeding without authentication"
creds creds
end end
def connection_preference(host) def read_fog_file(dot_fog = '.fog')
[:vmhostname, :ip, :hostname] YAML.load_file(dot_fog)
end
def connection_preference
['vmhostname', 'ip', 'hostname']
end end
def check_url url def check_url url
@ -114,7 +126,6 @@ module Beaker
uri = URI.parse(@options['pooling_api'] + '/vm/') uri = URI.parse(@options['pooling_api'] + '/vm/')
http = Net::HTTP.new(uri.host, uri.port) http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.instance_of?(URI::HTTPS)
request = Net::HTTP::Post.new(uri.request_uri) request = Net::HTTP::Post.new(uri.request_uri)
if @credentials[:vmpooler_token] if @credentials[:vmpooler_token]
@ -170,7 +181,7 @@ module Beaker
@logger.debug("Retrying provision for vmpooler host after waiting #{wait} second(s)") @logger.debug("Retrying provision for vmpooler host after waiting #{wait} second(s)")
sleep wait sleep wait
waited += wait waited += wait
last_wait, wait = wait, [last_wait + wait, 15].min + rand(5) last_wait, wait = wait, last_wait + wait
retry retry
end end
report_and_raise(@logger, e, 'Vmpooler.provision') report_and_raise(@logger, e, 'Vmpooler.provision')
@ -186,7 +197,6 @@ module Beaker
uri = URI.parse(@options[:pooling_api] + '/vm/' + h['vmhostname'].split('.')[0]) uri = URI.parse(@options[:pooling_api] + '/vm/' + h['vmhostname'].split('.')[0])
http = Net::HTTP.new(uri.host, uri.port) http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.instance_of?(URI::HTTPS)
request = Net::HTTP::Put.new(uri.request_uri) request = Net::HTTP::Put.new(uri.request_uri)
# merge pre-defined tags with host tags # merge pre-defined tags with host tags
@ -252,7 +262,6 @@ module Beaker
uri = URI.parse(get_template_url(@options['pooling_api'], name)) uri = URI.parse(get_template_url(@options['pooling_api'], name))
http = Net::HTTP.new( uri.host, uri.port ) http = Net::HTTP.new( uri.host, uri.port )
http.use_ssl = uri.instance_of?(URI::HTTPS)
request = Net::HTTP::Delete.new(uri.request_uri) request = Net::HTTP::Delete.new(uri.request_uri)
if @credentials[:vmpooler_token] if @credentials[:vmpooler_token]
@ -280,7 +289,6 @@ module Beaker
uri = URI.parse(@options[:pooling_api] + '/api/v1/vm/' + hostname + '/disk/' + disk_size.to_s) uri = URI.parse(@options[:pooling_api] + '/api/v1/vm/' + hostname + '/disk/' + disk_size.to_s)
http = Net::HTTP.new(uri.host, uri.port) http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.instance_of?(URI::HTTPS)
request = Net::HTTP::Post.new(uri.request_uri) request = Net::HTTP::Post.new(uri.request_uri)
request['X-AUTH-TOKEN'] = @credentials[:vmpooler_token] request['X-AUTH-TOKEN'] = @credentials[:vmpooler_token]
@ -313,7 +321,6 @@ module Beaker
uri = URI.parse(@options[:pooling_api] + '/vm/' + hostname) uri = URI.parse(@options[:pooling_api] + '/vm/' + hostname)
http = Net::HTTP.new(uri.host, uri.port) http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.instance_of?(URI::HTTPS)
request = Net::HTTP::Get.new(uri.request_uri) request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request) response = http.request(request)

View file

@ -0,0 +1,79 @@
require 'spec_helper'
module Beaker
describe Vcloud do
before :each do
MockVsphereHelper.set_config( fog_file_contents )
MockVsphereHelper.set_vms( make_hosts() )
stub_const( "VsphereHelper", MockVsphereHelper )
stub_const( "Net", MockNet )
json = double( 'json' )
allow( json ).to receive( :parse ) do |arg|
arg
end
stub_const( "JSON", json )
allow( Socket ).to receive( :getaddrinfo ).and_return( true )
end
describe "#provision" do
it 'instantiates vmpooler if pooling api is provided' do
opts = make_opts
opts[:pooling_api] = 'testpool'
hypervisor = Beaker::Vcloud.new( make_hosts, opts)
expect( hypervisor.class ).to be Beaker::Vmpooler
end
it 'provisions hosts and add them to the pool' do
MockVsphereHelper.powerOff
opts = make_opts
opts[:pooling_api] = nil
opts[:datacenter] = 'testdc'
vcloud = Beaker::Vcloud.new( make_hosts, opts )
allow( vcloud ).to receive( :require ).and_return( true )
allow( vcloud ).to receive( :sleep ).and_return( true )
vcloud.provision
hosts = vcloud.instance_variable_get( :@hosts )
hosts.each do | host |
name = host['vmhostname']
vm = MockVsphereHelper.find_vm( name )
expect( vm.toolsRunningStatus ).to be === "guestToolsRunning"
end
end
end
describe "#cleanup" do
it "cleans up hosts not in the pool" do
MockVsphereHelper.powerOn
opts = make_opts
opts[:pooling_api] = nil
opts[:datacenter] = 'testdc'
vcloud = Beaker::Vcloud.new( make_hosts, opts )
allow( vcloud ).to receive( :require ).and_return( true )
allow( vcloud ).to receive( :sleep ).and_return( true )
vcloud.provision
vcloud.cleanup
hosts = vcloud.instance_variable_get( :@hosts )
vm_names = hosts.map {|h| h['vmhostname'] }.compact
vm_names.each do | name |
vm = MockVsphereHelper.find_vm( name )
expect( vm.runtime.powerState ).to be === "poweredOff"
end
end
end
end
end

View file

@ -4,8 +4,11 @@ module Beaker
describe Vmpooler do describe Vmpooler do
before :each do before :each do
vms = make_hosts()
MockVsphereHelper.set_config( fog_file_contents )
MockVsphereHelper.set_vms( vms )
stub_const( "VsphereHelper", MockVsphereHelper )
stub_const( "Net", MockNet ) stub_const( "Net", MockNet )
allow_any_instance_of(MockNet::HTTP).to receive(:use_ssl=)
allow( JSON ).to receive( :parse ) do |arg| allow( JSON ).to receive( :parse ) do |arg|
arg arg
end end
@ -144,15 +147,20 @@ module Beaker
describe "#cleanup" do describe "#cleanup" do
it "cleans up hosts in the pool" do it "cleans up hosts in the pool" do
mock_http = MockNet::HTTP.new( "host", "port" ) MockVsphereHelper.powerOn
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
vmpooler.provision
vm_count = vmpooler.instance_variable_get( :@hosts ).count
expect( Net::HTTP ).to receive( :new ).exactly( vm_count ).times.and_return( mock_http ) vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( mock_http ).to receive( :request ).exactly( vm_count ).times allow( vmpooler ).to receive( :require ).and_return( true )
expect( Net::HTTP::Delete ).to receive( :new ).exactly( vm_count ).times allow( vmpooler ).to receive( :sleep ).and_return( true )
expect{ vmpooler.cleanup }.to_not raise_error vmpooler.provision
vmpooler.cleanup
hosts = vmpooler.instance_variable_get( :@hosts )
hosts.each do | host |
name = host.name
vm = MockVsphereHelper.find_vm( name )
expect( vm.runtime.powerState ).to be === "poweredOn" #handed back to the pool, stays on
end
end end
end end
end end
@ -160,6 +168,10 @@ module Beaker
describe Vmpooler do describe Vmpooler do
before :each do before :each do
vms = make_hosts()
MockVsphereHelper.set_config( fog_file_contents )
MockVsphereHelper.set_vms( vms )
stub_const( "VsphereHelper", MockVsphereHelper )
stub_const( "Net", MockNet ) stub_const( "Net", MockNet )
allow( JSON ).to receive( :parse ) do |arg| allow( JSON ).to receive( :parse ) do |arg|
arg arg
@ -169,38 +181,95 @@ module Beaker
describe "#load_credentials" do describe "#load_credentials" do
it 'loads credentials from a fog file' do it 'continues without credentials when fog file is missing' do
credentials = { :vmpooler_token => "example_token" } allow_any_instance_of( Beaker::Vmpooler ).to \
make_opts = { :dot_fog => '.fog' } receive(:read_fog_file).and_raise(Errno::ENOENT.new)
expect_any_instance_of( Beaker::Vmpooler ).to receive( :get_fog_credentials ).and_return(credentials)
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts ) vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == credentials
end
it 'continues without credentials when there are problems loading the fog file' do
logger = double( 'logger' )
make_opts = { :logger => logger, :dot_fog => '.fog' }
expect_any_instance_of( Beaker::Vmpooler ).to receive( :get_fog_credentials ).and_raise( ArgumentError, 'something went wrong' )
expect( logger ).to receive( :warn ).with( /Invalid credentials file.*something went wrong.*Proceeding without authentication/m )
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == {} expect( vmpooler.credentials ).to be == {}
end end
it 'continues without credentials when fog file has no vmpooler_token' do it 'continues without credentials when fog file is empty' do
logger = double( 'logger' ) allow_any_instance_of( Beaker::Vmpooler ).to \
make_opts = { :logger => logger, :dot_fog => '.fog' } receive(:read_fog_file).and_return(false)
expect_any_instance_of( Beaker::Vmpooler ).to receive( :get_fog_credentials ).and_return( {} ) vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( logger ).to receive( :warn ).with( /vmpooler_token not found in credentials file.*Proceeding without authentication/m ) expect( vmpooler.credentials ).to be == {}
end
it 'continues without credentials when fog file contains no :default section' do
data = { :some => { :other => :data } }
allow_any_instance_of( Beaker::Vmpooler ).to \
receive(:read_fog_file).and_return(data)
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == { }
end
it 'continues without credentials when fog file :default section has no :vmpooler_token' do
data = { :default => { :something_else => "TOKEN" } }
allow_any_instance_of( Beaker::Vmpooler ).to \
receive(:read_fog_file).and_return(data)
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == { }
end
it 'continues without credentials when there are formatting errors in the fog file' do
data = { "'default'" => { :vmpooler_token => "b2wl8prqe6ddoii70md" } }
allow_any_instance_of( Beaker::Vmpooler ).to \
receive(:read_fog_file).and_return(data)
logger = double('logger')
expect(logger).to receive(:warn).with(/is missing a :default section with a :vmpooler_token value/)
make_opts = {:logger => logger}
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == { }
end
it 'throws a TypeError and continues without credentials when there are syntax errors in the fog file' do
data = "'default'\n :vmpooler_token: z2wl8prqe0ddoii70ad"
allow( File ).to receive( :open ).and_yield( StringIO.new(data) )
logger = double('logger')
expect(logger).to receive(:warn).with(/TypeError: .* has invalid syntax/)
make_opts = {:logger => logger}
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts ) vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == {} expect( vmpooler.credentials ).to be == { }
end
it 'throws a Psych::SyntaxError and continues without credentials when there are syntax errors in the fog file' do
data = ";default;\n :vmpooler_token: z2wl8prqe0ddoii707d"
allow( File ).to receive( :open ).and_yield( StringIO.new(data) )
logger = double('logger')
expect(logger).to receive(:warn).with(/Psych::SyntaxError: .* invalid syntax/)
make_opts = {:logger => logger}
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == { }
end
it 'stores vmpooler token when found in fog file' do
data = { :default => { :vmpooler_token => "TOKEN" } }
allow_any_instance_of( Beaker::Vmpooler ).to \
receive(:read_fog_file).and_return(data)
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
expect( vmpooler.credentials ).to be == { :vmpooler_token => "TOKEN" }
end end
end end
end end

View file

@ -2,6 +2,7 @@ require 'simplecov'
require 'rspec/its' require 'rspec/its'
require 'beaker' require 'beaker'
require 'beaker/hypervisor/vmpooler' require 'beaker/hypervisor/vmpooler'
require 'beaker/hypervisor/vcloud'
# setup & require beaker's spec_helper.rb # setup & require beaker's spec_helper.rb
beaker_gem_spec = Gem::Specification.find_by_name('beaker') beaker_gem_spec = Gem::Specification.find_by_name('beaker')