Skip to content

Commit

Permalink
Merge pull request #19 from kevpl/bkr831_install_windows
Browse files Browse the repository at this point in the history
(BKR-831) added dynamic puppet-agent version read from master
  • Loading branch information
smcelmurry authored Dec 19, 2016
2 parents e185d0d + d42ef8e commit 415d3f3
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 46 deletions.
126 changes: 89 additions & 37 deletions lib/beaker-pe/install/pe_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -386,39 +386,7 @@ def do_install hosts, opts = {}
add_extended_gpg_key_to_hosts(hosts, opts)

# Set PE distribution for all the hosts, create working dir
use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
hosts.each do |host|
next if agent_only_check_needed && hosts_agent_only.include?(host)
host['pe_installer'] ||= 'puppet-enterprise-installer'
if host['platform'] !~ /windows|osx/
platform = use_all_tar ? 'all' : host['platform']
version = host['pe_ver'] || opts[:pe_ver]
host['dist'] = "puppet-enterprise-#{version}-#{platform}"
elsif host['platform'] =~ /osx/
version = host['pe_ver'] || opts[:pe_ver]
host['dist'] = "puppet-enterprise-#{version}-#{host['platform']}"
elsif host['platform'] =~ /windows/
version = host[:pe_ver] || opts['pe_ver_win']
is_config_32 = true == (host['ruby_arch'] == 'x86') || host['install_32'] || opts['install_32']
should_install_64bit = !(version_is_less(version, '3.4')) && host.is_x86_64? && !is_config_32
#only install 64bit builds if
# - we are on pe version 3.4+
# - we do not have install_32 set on host
# - we do not have install_32 set globally
if !(version_is_less(version, '3.99'))
if should_install_64bit
host['dist'] = "puppet-agent-#{version}-x64"
else
host['dist'] = "puppet-agent-#{version}-x86"
end
elsif should_install_64bit
host['dist'] = "puppet-enterprise-#{version}-x64"
else
host['dist'] = "puppet-enterprise-#{version}"
end
end
host['working_dir'] = host.tmpdir(Time.new.strftime("%Y-%m-%d_%H.%M.%S"))
end
prepare_hosts(hosts_not_agent_only, opts)

fetch_pe(hosts_not_agent_only, opts)

Expand All @@ -434,10 +402,12 @@ def do_install hosts, opts = {}

if agent_only_check_needed && hosts_agent_only.include?(host) || is_windows_msi_and_aio
host['type'] = 'aio'
install_puppet_agent_pe_promoted_repo_on(host, { :puppet_agent_version => host[:puppet_agent_version] || opts[:puppet_agent_version],
:puppet_agent_sha => host[:puppet_agent_sha] || opts[:puppet_agent_sha],
:pe_ver => host[:pe_ver] || opts[:pe_ver],
:puppet_collection => host[:puppet_collection] || opts[:puppet_collection] })
install_puppet_agent_pe_promoted_repo_on(host, {
:puppet_agent_version => get_puppet_agent_version(host, opts),
:puppet_agent_sha => host[:puppet_agent_sha] || opts[:puppet_agent_sha],
:pe_ver => host[:pe_ver] || opts[:pe_ver],
:puppet_collection => host[:puppet_collection] || opts[:puppet_collection]
})
# 1 since no certificate found and waitforcert disabled
acceptable_exit_codes = [0, 1]
acceptable_exit_codes << 2 if opts[:type] == :upgrade
Expand Down Expand Up @@ -558,6 +528,88 @@ def do_install hosts, opts = {}
end
end

# Prepares hosts for rest of {#do_install} operations.
# This includes doing these tasks:
# - setting 'pe_installer' property on hosts
# - setting 'dist' property on hosts
# - creating and setting 'working_dir' property on hosts
#
# @note that these steps aren't necessary for all hosts. Specifically,
# 'agent_only' hosts do not require these steps to be executed.
#
# @param [Array<Host>] hosts Hosts to prepare
# @param [Hash{Symbol=>String}] local_options Local options, used to
# pass misc configuration required for the prep steps
#
# @return nil
def prepare_hosts(hosts, local_options={})
use_all_tar = ENV['PE_USE_ALL_TAR'] == 'true'
hosts.each do |host|
host['pe_installer'] ||= 'puppet-enterprise-installer'
if host['platform'] !~ /windows|osx/
platform = use_all_tar ? 'all' : host['platform']
version = host['pe_ver'] || local_options[:pe_ver]
host['dist'] = "puppet-enterprise-#{version}-#{platform}"
elsif host['platform'] =~ /osx/
version = host['pe_ver'] || local_options[:pe_ver]
host['dist'] = "puppet-enterprise-#{version}-#{host['platform']}"
elsif host['platform'] =~ /windows/
version = host[:pe_ver] || local_options['pe_ver_win']
is_config_32 = true == (host['ruby_arch'] == 'x86') || host['install_32'] || local_options['install_32']
should_install_64bit = !(version_is_less(version, '3.4')) && host.is_x86_64? && !is_config_32
#only install 64bit builds if
# - we are on pe version 3.4+
# - we do not have install_32 set on host
# - we do not have install_32 set globally
if !(version_is_less(version, '3.99'))
if should_install_64bit
host['dist'] = "puppet-agent-#{version}-x64"
else
host['dist'] = "puppet-agent-#{version}-x86"
end
elsif should_install_64bit
host['dist'] = "puppet-enterprise-#{version}-x64"
else
host['dist'] = "puppet-enterprise-#{version}"
end
end
host['working_dir'] = host.tmpdir(Time.new.strftime("%Y-%m-%d_%H.%M.%S"))
end
end

# Gets the puppet-agent version, hopefully from the host or local options.
# Will fall back to reading the `aio_agent_build` property on the master
# if neither of those two options are passed
#
# @note This method does have a side-effect: if it reads the
# `aio_agent_build` property from master, it will store it in the local
# options hash so that it won't have to do this more than once.
#
# @param [Beaker::Host] host Host to get puppet-agent for
# @param [Hash{Symbol=>String}] local_options local method options hash
#
# @return [String] puppet-agent version to install
def get_puppet_agent_version(host, local_options={})
puppet_agent_version = host[:puppet_agent_version] || local_options[:puppet_agent_version]
return puppet_agent_version if puppet_agent_version
log_prefix = "No :puppet_agent_version in host #{host} or local options."
fail_message = "#{log_prefix} Could not read facts from master to determine puppet_agent_version"
# we can query the master because do_install is called passing
# the {#sorted_hosts}, so we know the master will be installed
# before the agents
facts_result = on(master, 'puppet facts')
raise ArgumentError, fail_message if facts_result.exit_code != 0
facts_hash = JSON.parse(facts_result.stdout.chomp)
puppet_agent_version = facts_hash['values']['aio_agent_build']
# released masters don't have _build fact, fallback to _version
puppet_agent_version ||= facts_hash['values']['aio_agent_version']
raise ArgumentError, fail_message if puppet_agent_version.nil?
logger.warn("#{log_prefix} Read puppet-agent version #{puppet_agent_version} from master")
# saving so that we don't have to query the master more than once
local_options[:puppet_agent_version] = puppet_agent_version
puppet_agent_version
end

# True if version is greater than or equal to MEEP_CUTOVER_VERSION (2016.2.0)
def use_meep?(version)
!version_is_less(version, MEEP_CUTOVER_VERSION)
Expand Down
2 changes: 1 addition & 1 deletion lib/beaker-pe/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module DSL
module PE

module Version
STRING = '1.6.1'
STRING = '1.6.1.161128'
end

end
Expand Down
125 changes: 117 additions & 8 deletions spec/beaker-pe/install/pe_utils_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -772,15 +772,32 @@ def slice_installer_options(host)
"puppet #{arg}"
end

pa_version = 'rarified_air_9364'
allow( subject ).to receive( :get_puppet_agent_version ).and_return( pa_version )

allow( subject ).to receive( :hosts ).and_return( hosts )
#create answers file per-host, except windows
expect( subject ).to receive( :create_remote_file ).with( hosts[0], /answers/, /q/ ).once
#run installer on all hosts
expect( subject ).to receive( :on ).with( hosts[0], /puppet-enterprise-installer/ ).once
expect( subject ).to receive( :install_puppet_agent_pe_promoted_repo_on ).with( hosts[1],
{:puppet_agent_version=>nil, :puppet_agent_sha=>nil, :pe_ver=>hosts[1][:pe_ver], :puppet_collection=>nil} ).once
expect( subject ).to receive( :install_puppet_agent_pe_promoted_repo_on ).with( hosts[2],
{:puppet_agent_version=>nil, :puppet_agent_sha=>nil, :pe_ver=>hosts[2][:pe_ver], :puppet_collection=>nil} ).once
expect( subject ).to receive( :install_puppet_agent_pe_promoted_repo_on ).with(
hosts[1],
{
:puppet_agent_version => pa_version,
:puppet_agent_sha => nil,
:pe_ver => hosts[1][:pe_ver],
:puppet_collection => nil
}
).once
expect( subject ).to receive( :install_puppet_agent_pe_promoted_repo_on ).with(
hosts[2],
{
:puppet_agent_version => pa_version,
:puppet_agent_sha => nil,
:pe_ver => hosts[2][:pe_ver],
:puppet_collection => nil
}
).once
hosts.each do |host|
expect( subject ).to receive( :configure_type_defaults_on ).with( host ).once
expect( subject ).to receive( :sign_certificate_for ).with( host ).once
Expand Down Expand Up @@ -812,6 +829,9 @@ def slice_installer_options(host)
hosts[2][:platform] = Beaker::Platform.new('el-6-x86_64')
hosts[2][:pe_ver] = '3.8'

pa_version = 'rarified_air_1675'
allow( subject ).to receive( :get_puppet_agent_version ).and_return( pa_version )

allow( subject ).to receive( :hosts ).and_return( hosts )
allow( subject ).to receive( :options ).and_return(Beaker::Options::Presets.new.presets)
allow( subject ).to receive( :on ).and_return( Beaker::Result.new( {}, '' ) )
Expand All @@ -834,8 +854,15 @@ def slice_installer_options(host)
expect( subject ).to receive( :create_remote_file ).with( hosts[0], /answers/, /q/ ).once
#run installer on all hosts
expect( subject ).to receive( :on ).with( hosts[0], /puppet-enterprise-installer/ ).once
expect( subject ).to receive( :install_puppet_agent_pe_promoted_repo_on ).with( hosts[1],
{:puppet_agent_version=>nil, :puppet_agent_sha=>nil, :pe_ver=>hosts[1][:pe_ver], :puppet_collection=>nil} ).once
expect( subject ).to receive( :install_puppet_agent_pe_promoted_repo_on ).with(
hosts[1],
{
:puppet_agent_version => pa_version,
:puppet_agent_sha => nil,
:pe_ver => hosts[1][:pe_ver],
:puppet_collection => nil
}
).once
expect( subject ).to receive( :on ).with( hosts[2], /puppet-enterprise-installer/ ).once
hosts.each do |host|
expect( subject ).to receive( :configure_type_defaults_on ).with( host ).once
Expand Down Expand Up @@ -872,6 +899,9 @@ def slice_installer_options(host)
opts[:HOSTS][host.name] = host
end

pa_version = 'rarified_air_75699'
allow( subject ).to receive( :get_puppet_agent_version ).and_return( pa_version )

allow( subject ).to receive( :hosts ).and_return( hosts )
allow( subject ).to receive( :options ).and_return(Beaker::Options::Presets.new.presets)
allow( subject ).to receive( :on ).and_return( Beaker::Result.new( {}, '' ) )
Expand All @@ -897,7 +927,7 @@ def slice_installer_options(host)
allow( subject ).to receive(
:install_puppet_agent_pe_promoted_repo_on
).with( hosts[1], {
:puppet_agent_version => nil,
:puppet_agent_version => pa_version,
:puppet_agent_sha => nil,
:pe_ver => hosts[1][:pe_ver],
:puppet_collection => nil
Expand Down Expand Up @@ -1267,7 +1297,86 @@ def slice_installer_options(host)
expect(subject).to receive(:fail_test)
subject.check_console_status_endpoint({})
end

end

describe '#get_puppet_agent_version' do

context 'when the puppet_agent version is set on an argument' do

it 'uses host setting over all others' do
pa_version = 'pants of the dance'
host_arg = { :puppet_agent_version => pa_version }
local_options = { :puppet_agent_version => 'something else' }
expect( subject.get_puppet_agent_version( host_arg, local_options ) ).to be === pa_version
end

it 'uses local options over all others (except host setting)' do
pa_version = 'who did it?'
local_options = { :puppet_agent_version => pa_version }
expect( subject.get_puppet_agent_version( {}, local_options ) ).to be === pa_version
end
end

context 'when the puppet_agent version has to be read dynamically' do

def test_setup(mock_values={})
json_hash = mock_values[:json_hash]
pa_version = mock_values[:pa_version]
pa_version ||= 'pa_version_' + rand(10 ** 5).to_s.rjust(5,'0') # 5 digit random number string
json_hash ||= "{ \"values\": { \"aio_agent_build\": \"#{pa_version}\" }}"

allow( subject ).to receive( :master ).and_return( {} )
result_mock = Object.new
allow( result_mock ).to receive( :stdout ).and_return( json_hash )
allow( result_mock ).to receive( :exit_code ).and_return( 0 )
allow( subject ).to receive( :on ).and_return( result_mock )
pa_version
end

it 'parses and returns the command output correctly' do
pa_version = test_setup
expect( subject.get_puppet_agent_version( {} ) ).to be === pa_version
end

it 'saves the puppet_agent version in the local_options argument' do
pa_version = test_setup
local_options_hash = {}
subject.get_puppet_agent_version( {}, local_options_hash )
expect( local_options_hash[:puppet_agent_version] ).to be === pa_version
end

it 'falls back on aio_agent_version if _build is not available' do
pa_version = 'your_face_13587'
test_setup( :json_hash => "{ \"values\": { \"aio_agent_version\": \"#{pa_version}\" }}" )
expect( subject.get_puppet_agent_version( {} ) ).to be === pa_version
end
end

context 'failures' do

def test_setup(mock_values)
exit_code = mock_values[:exit_code] || 0
json_hash = mock_values[:json_hash]
pa_version = 'pa_version_'
pa_version << rand(10 ** 5).to_s.rjust(5,'0') # 5 digit random number string
json_hash ||= "{ \"values\": { \"aio_agent_build\": \"#{pa_version}\" }}"

allow( subject ).to receive( :master ).and_return( {} )
result_mock = Object.new
allow( result_mock ).to receive( :stdout ).and_return( json_hash )
allow( result_mock ).to receive( :exit_code ).and_return( exit_code )
allow( subject ).to receive( :on ).and_return( result_mock )
end

it 'fails if "puppet facts" does not succeed' do
test_setup( :exit_code => 1 )
expect { subject.get_puppet_agent_version( {} ) }.to raise_error( ArgumentError )
end

it 'fails if neither fact exists' do
test_setup( :json_hash => "{ \"values\": {}}" )
expect { subject.get_puppet_agent_version( {} ) }.to raise_error( ArgumentError )
end
end
end
end

0 comments on commit 415d3f3

Please sign in to comment.