mirror of
https://github.com/puppetlabs/beaker-vmpooler.git
synced 2026-01-26 02:58:42 -05:00
Compare commits
35 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f055e1202b | ||
|
|
c027b1bcef | ||
|
|
c309bf02ce | ||
|
|
4f5ee09807 | ||
|
|
278515e460 | ||
|
|
6acbc08aba | ||
|
|
d8ea6a2e4c | ||
| 5be58b1e82 | |||
|
|
5d04a41003 | ||
|
|
596e0d83f9 | ||
| e012919f08 | |||
|
|
639255b4de | ||
| 1da71ab4dc | |||
|
|
49f57963bc | ||
| bd4ae1ee8e | |||
|
|
252e92ab4f | ||
| f6bf085eab | |||
| ef72c2399a | |||
|
|
0c4dc910d3 | ||
|
|
79d0880c5b | ||
|
|
d54e825506 | ||
|
|
4063b01ba0 | ||
|
|
a504de0ae4 | ||
|
|
b463b50cbe | ||
|
|
64c827fab0 | ||
|
|
15acdf0d7f | ||
|
|
d1ad5bb083 | ||
|
|
5317f2c1db | ||
|
|
02684546cb | ||
|
|
7a4909805a | ||
|
|
b0bc656187 | ||
|
|
c0938fe1c8 | ||
|
|
b8804eb5f1 | ||
|
|
4cc317c488 | ||
|
|
b1f30c268f |
11 changed files with 186 additions and 134 deletions
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: bundler
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
open-pull-requests-limit: 10
|
||||
39
.github/workflows/release.yml
vendored
Normal file
39
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
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 }}'
|
||||
39
.github/workflows/security.yml
vendored
Normal file
39
.github/workflows/security.yml
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
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 }}
|
||||
26
.github/workflows/testing.yml
vendored
Normal file
26
.github/workflows/testing.yml
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
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
|
||||
2
CODEOWNERS
Normal file
2
CODEOWNERS
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
* @puppetlabs/release-engineering
|
||||
|
||||
12
Gemfile
12
Gemfile
|
|
@ -1,8 +1,6 @@
|
|||
source ENV['GEM_SOURCE'] || "https://rubygems.org"
|
||||
|
||||
gemspec
|
||||
|
||||
|
||||
gemspec :development_group => :acceptance_testing
|
||||
|
||||
def location_for(place, fake_version = nil)
|
||||
if place =~ /^(git:[^#]*)#(.*)/
|
||||
|
|
@ -14,15 +12,13 @@ def location_for(place, fake_version = nil)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
# We don't put beaker in as a test dependency because we
|
||||
# don't want to create a transitive dependency
|
||||
group :acceptance_testing do
|
||||
gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '~> 3.0')
|
||||
gem "beaker-abs", *location_for(ENV['ABS_VERSION'] || '~> 0.3.0')
|
||||
gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '>= 5.0', '< 7')
|
||||
gem "beaker-abs"
|
||||
end
|
||||
|
||||
|
||||
if File.exists? "#{__FILE__}.local"
|
||||
if File.exist? "#{__FILE__}.local"
|
||||
eval(File.read("#{__FILE__}.local"), binding)
|
||||
end
|
||||
|
|
|
|||
23
README.md
23
README.md
|
|
@ -3,8 +3,27 @@
|
|||
Beaker library to use vmpooler hypervisor
|
||||
|
||||
# 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 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.
|
||||
|
||||
This is a gem that allows you to use hosts with [vmpooler](vmpooler.md) hypervisor with [beaker](https://github.com/puppetlabs/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
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ Gem::Specification.new do |s|
|
|||
# Testing dependencies
|
||||
s.add_development_dependency 'rspec', '~> 3.0'
|
||||
s.add_development_dependency 'rspec-its'
|
||||
s.add_development_dependency 'fakefs', '~> 0.6'
|
||||
s.add_development_dependency 'rake', '~> 10.1'
|
||||
s.add_development_dependency 'fakefs', '~> 2.4'
|
||||
s.add_development_dependency 'rake', '~> 13.0'
|
||||
s.add_development_dependency 'simplecov'
|
||||
s.add_development_dependency 'pry', '~> 0.10'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
module BeakerVmpooler
|
||||
VERSION = '1.2.0'
|
||||
VERSION = '1.4.0'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,33 +27,21 @@ module Beaker
|
|||
|
||||
def load_credentials(dot_fog = '.fog')
|
||||
creds = {}
|
||||
|
||||
if fog = read_fog_file(dot_fog)
|
||||
if fog[:default] && fog[:default][:vmpooler_token]
|
||||
creds[:vmpooler_token] = fog[:default][:vmpooler_token]
|
||||
begin
|
||||
fog = get_fog_credentials(dot_fog)
|
||||
if fog[:vmpooler_token]
|
||||
creds[:vmpooler_token] = fog[:vmpooler_token]
|
||||
else
|
||||
@logger.warn "Credentials file (#{dot_fog}) is missing a :default section with a :vmpooler_token value; proceeding without authentication"
|
||||
@logger.warn "vmpooler_token not found in credentials file (#{dot_fog})\nProceeding without authentication"
|
||||
end
|
||||
else
|
||||
@logger.warn "Credentials file (#{dot_fog}) is empty; proceeding without authentication"
|
||||
rescue ArgumentError => e
|
||||
@logger.warn "Invalid credentials file:\n(#{e.class}) #{e.message}\nProceeding without authentication"
|
||||
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
|
||||
end
|
||||
|
||||
def read_fog_file(dot_fog = '.fog')
|
||||
YAML.load_file(dot_fog)
|
||||
end
|
||||
|
||||
def connection_preference(host)
|
||||
['vmhostname', 'ip', 'hostname']
|
||||
[:vmhostname, :ip, :hostname]
|
||||
end
|
||||
|
||||
def check_url url
|
||||
|
|
@ -126,6 +114,7 @@ module Beaker
|
|||
uri = URI.parse(@options['pooling_api'] + '/vm/')
|
||||
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
||||
request = Net::HTTP::Post.new(uri.request_uri)
|
||||
|
||||
if @credentials[:vmpooler_token]
|
||||
|
|
@ -181,7 +170,7 @@ module Beaker
|
|||
@logger.debug("Retrying provision for vmpooler host after waiting #{wait} second(s)")
|
||||
sleep wait
|
||||
waited += wait
|
||||
last_wait, wait = wait, last_wait + wait
|
||||
last_wait, wait = wait, [last_wait + wait, 15].min + rand(5)
|
||||
retry
|
||||
end
|
||||
report_and_raise(@logger, e, 'Vmpooler.provision')
|
||||
|
|
@ -197,6 +186,7 @@ module Beaker
|
|||
uri = URI.parse(@options[:pooling_api] + '/vm/' + h['vmhostname'].split('.')[0])
|
||||
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
||||
request = Net::HTTP::Put.new(uri.request_uri)
|
||||
|
||||
# merge pre-defined tags with host tags
|
||||
|
|
@ -262,6 +252,7 @@ module Beaker
|
|||
uri = URI.parse(get_template_url(@options['pooling_api'], name))
|
||||
|
||||
http = Net::HTTP.new( uri.host, uri.port )
|
||||
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
||||
request = Net::HTTP::Delete.new(uri.request_uri)
|
||||
|
||||
if @credentials[:vmpooler_token]
|
||||
|
|
@ -289,6 +280,7 @@ module Beaker
|
|||
uri = URI.parse(@options[:pooling_api] + '/api/v1/vm/' + hostname + '/disk/' + disk_size.to_s)
|
||||
|
||||
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['X-AUTH-TOKEN'] = @credentials[:vmpooler_token]
|
||||
|
||||
|
|
@ -321,6 +313,7 @@ module Beaker
|
|||
uri = URI.parse(@options[:pooling_api] + '/vm/' + hostname)
|
||||
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
||||
request = Net::HTTP::Get.new(uri.request_uri)
|
||||
|
||||
response = http.request(request)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,8 @@ 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_any_instance_of(MockNet::HTTP).to receive(:use_ssl=)
|
||||
allow( JSON ).to receive( :parse ) do |arg|
|
||||
arg
|
||||
end
|
||||
|
|
@ -147,20 +144,15 @@ module Beaker
|
|||
describe "#cleanup" do
|
||||
|
||||
it "cleans up hosts in the pool" do
|
||||
MockVsphereHelper.powerOn
|
||||
|
||||
mock_http = MockNet::HTTP.new( "host", "port" )
|
||||
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
|
||||
vm_count = vmpooler.instance_variable_get( :@hosts ).count
|
||||
|
||||
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
|
||||
expect( Net::HTTP ).to receive( :new ).exactly( vm_count ).times.and_return( mock_http )
|
||||
expect( mock_http ).to receive( :request ).exactly( vm_count ).times
|
||||
expect( Net::HTTP::Delete ).to receive( :new ).exactly( vm_count ).times
|
||||
expect{ vmpooler.cleanup }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -168,10 +160,6 @@ 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
|
||||
|
|
@ -181,96 +169,39 @@ module Beaker
|
|||
|
||||
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)
|
||||
it 'loads credentials from a fog file' do
|
||||
credentials = { :vmpooler_token => "example_token" }
|
||||
make_opts = { :dot_fog => '.fog' }
|
||||
|
||||
expect_any_instance_of( Beaker::Vmpooler ).to receive( :get_fog_credentials ).and_return(credentials)
|
||||
|
||||
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 == {}
|
||||
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)
|
||||
it 'continues without credentials when fog file has no vmpooler_token' do
|
||||
logger = double( 'logger' )
|
||||
make_opts = { :logger => logger, :dot_fog => '.fog' }
|
||||
|
||||
expect_any_instance_of( Beaker::Vmpooler ).to receive( :get_fog_credentials ).and_return( {} )
|
||||
expect( logger ).to receive( :warn ).with( /vmpooler_token not found in credentials file.*Proceeding without authentication/m )
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue