mirror of
https://github.com/puppetlabs/beaker-vmpooler.git
synced 2026-01-26 11:08:40 -05:00
BKR-834 made vmhostname the default lookup method for SSH connections but this broke hypervisors which don't have DNS support e.g. OpenStack. By setting the connection method in the hypervisor we can choose where to prefer specific methods.
301 lines
10 KiB
Ruby
301 lines
10 KiB
Ruby
require 'spec_helper'
|
|
|
|
module Beaker
|
|
describe Vmpooler 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 )
|
|
allow( JSON ).to receive( :parse ) do |arg|
|
|
arg
|
|
end
|
|
allow( Socket ).to receive( :getaddrinfo ).and_return( true )
|
|
allow_any_instance_of( Beaker::Vmpooler ).to \
|
|
receive(:load_credentials).and_return(fog_file_contents)
|
|
end
|
|
|
|
describe '#get_template_url' do
|
|
|
|
it 'works returns the valid url when passed valid pooling_api and template name' do
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
uri = vmpooler.get_template_url("http://pooling.com", "template")
|
|
expect( uri ).to be === "http://pooling.com/vm/template"
|
|
end
|
|
|
|
it 'adds a missing scheme to a given URL' do
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
uri = vmpooler.get_template_url("pooling.com", "template")
|
|
expect( URI.parse(uri).scheme ).to_not be === nil
|
|
end
|
|
|
|
it 'raises an error on an invalid pooling api url' do
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
expect{ vmpooler.get_template_url("pooling### ", "template")}.to raise_error ArgumentError
|
|
end
|
|
|
|
it 'raises an error on an invalide template name' do
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
expect{ vmpooler.get_template_url("pooling.com", "t!e&m*p(l\\a/t e")}.to raise_error ArgumentError
|
|
end
|
|
end
|
|
|
|
describe '#add_tags' do
|
|
let(:vmpooler) { Beaker::Vmpooler.new(make_hosts({:host_tags => {'test_tag' => 'test_value'}}), make_opts) }
|
|
|
|
it 'merges tags correctly' do
|
|
vmpooler.instance_eval {
|
|
@options = @options.merge({:project => 'vmpooler-spec'})
|
|
}
|
|
host = vmpooler.instance_variable_get(:@hosts)[0]
|
|
merged_tags = vmpooler.add_tags(host)
|
|
expected_hash = {
|
|
test_tag: 'test_value',
|
|
beaker_version: Beaker::Version::STRING,
|
|
project: 'vmpooler-spec'
|
|
}
|
|
expect(merged_tags).to include(expected_hash)
|
|
end
|
|
end
|
|
|
|
describe '#disk_added?' do
|
|
let(:vmpooler) { Beaker::Vmpooler.new(make_hosts, make_opts) }
|
|
let(:response_hash_no_disk) {
|
|
{
|
|
"ok" => "true",
|
|
"hostname" => {
|
|
"template"=>"redhat-7-x86_64",
|
|
"domain"=>"delivery.puppetlabs.net"
|
|
}
|
|
}
|
|
}
|
|
let(:response_hash_disk) {
|
|
{
|
|
"ok" => "true",
|
|
"hostname" => {
|
|
"disk" => [
|
|
'+16gb',
|
|
'+8gb'
|
|
],
|
|
"template"=>"redhat-7-x86_64",
|
|
"domain"=>"delivery.puppetlabs.net"
|
|
}
|
|
}
|
|
}
|
|
it 'returns false when there is no disk' do
|
|
host = response_hash_no_disk['hostname']
|
|
expect(vmpooler.disk_added?(host, "8", 0)).to be(false)
|
|
end
|
|
|
|
it 'returns true when there is a disk' do
|
|
host = response_hash_disk["hostname"]
|
|
expect(vmpooler.disk_added?(host, "16", 0)).to be(true)
|
|
expect(vmpooler.disk_added?(host, "8", 1)).to be(true)
|
|
end
|
|
end
|
|
|
|
describe "#provision" do
|
|
|
|
it 'provisions hosts from the pool' do
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
allow( vmpooler ).to receive( :require ).and_return( true )
|
|
allow( vmpooler ).to receive( :sleep ).and_return( true )
|
|
vmpooler.provision
|
|
|
|
hosts = vmpooler.instance_variable_get( :@hosts )
|
|
hosts.each do | host |
|
|
expect( host['vmhostname'] ).to be === 'pool'
|
|
end
|
|
end
|
|
|
|
it 'raises an error when a host template is not found in returned json' do
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
|
|
allow( vmpooler ).to receive( :require ).and_return( true )
|
|
allow( vmpooler ).to receive( :sleep ).and_return( true )
|
|
allow( vmpooler ).to receive( :get_host_info ).and_return( nil )
|
|
|
|
expect {
|
|
vmpooler.provision
|
|
}.to raise_error( RuntimeError,
|
|
/Vmpooler\.provision - requested VM templates \[.*\,.*\,.*\] not available/
|
|
)
|
|
end
|
|
|
|
it 'repeats asking only for failed hosts' do
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
|
|
allow( vmpooler ).to receive( :require ).and_return( true )
|
|
allow( vmpooler ).to receive( :sleep ).and_return( true )
|
|
allow( vmpooler ).to receive( :get_host_info ).with(
|
|
anything, "vm1_has_a_template" ).and_return( nil )
|
|
allow( vmpooler ).to receive( :get_host_info ).with(
|
|
anything, "vm2_has_a_template" ).and_return( 'y' )
|
|
allow( vmpooler ).to receive( :get_host_info ).with(
|
|
anything, "vm3_has_a_template" ).and_return( 'y' )
|
|
|
|
expect {
|
|
vmpooler.provision
|
|
}.to raise_error( RuntimeError,
|
|
/Vmpooler\.provision - requested VM templates \[[^\,]*\] not available/
|
|
) # should be only one item in the list, no commas
|
|
end
|
|
|
|
it 'ignores the ssh connection type when explicitly configured' do
|
|
hosts = make_hosts
|
|
hosts.each {|h| h[:connection_method] = 'explicit_connection_type'}
|
|
|
|
vmpooler = Beaker::Vmpooler.new( hosts, make_opts )
|
|
vmpooler.provision
|
|
|
|
hosts = vmpooler.instance_variable_get( :@hosts )
|
|
hosts.each do | host |
|
|
expect(host[:connection_method]).to be === 'explicit_connection_type'
|
|
end
|
|
end
|
|
|
|
it 'sets the ssh connection type to vmhostname when not explicitly configured' do
|
|
#p make_hosts
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
vmpooler.provision
|
|
|
|
hosts = vmpooler.instance_variable_get( :@hosts )
|
|
hosts.each do | host |
|
|
# p host
|
|
expect(host[:connection_method]).to be === 'vmhostname'
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#cleanup" do
|
|
|
|
it "cleans up hosts in the pool" do
|
|
MockVsphereHelper.powerOn
|
|
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
allow( vmpooler ).to receive( :require ).and_return( true )
|
|
allow( vmpooler ).to receive( :sleep ).and_return( true )
|
|
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
|
|
|
|
describe Vmpooler 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 )
|
|
allow( JSON ).to receive( :parse ) do |arg|
|
|
arg
|
|
end
|
|
allow( Socket ).to receive( :getaddrinfo ).and_return( true )
|
|
end
|
|
|
|
describe "#load_credentials" do
|
|
|
|
it 'continues without credentials when fog file is missing' do
|
|
allow_any_instance_of( Beaker::Vmpooler ).to \
|
|
receive(:read_fog_file).and_raise(Errno::ENOENT.new)
|
|
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
expect( vmpooler.credentials ).to be == {}
|
|
end
|
|
|
|
it 'continues without credentials when fog file is empty' do
|
|
allow_any_instance_of( Beaker::Vmpooler ).to \
|
|
receive(:read_fog_file).and_return(false)
|
|
|
|
vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
|
|
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 )
|
|
|
|
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
|