Compare commits

..

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

11 changed files with 135 additions and 187 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

12
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,15 @@ 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" gem "beaker-abs", *location_for(ENV['ABS_VERSION'] || '~> 0.3.0')
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,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'

View file

@ -1,3 +1,3 @@
module BeakerVmpooler module BeakerVmpooler
VERSION = '1.4.0' VERSION = '1.2.0'
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 read_fog_file(dot_fog = '.fog')
YAML.load_file(dot_fog)
end
def connection_preference(host) def connection_preference(host)
[:vmhostname, :ip, :hostname] ['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

@ -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