beaker 2.18.0 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/HISTORY.md +699 -2
- data/acceptance/lib/beaker/acceptance/install_utils.rb +58 -0
- data/acceptance/pre_suite/puppet_gem/install.rb +1 -8
- data/acceptance/pre_suite/puppet_git/install.rb +6 -65
- data/acceptance/pre_suite/puppet_pkg/install.rb +1 -1
- data/acceptance/tests/foss_utils/clone_git_repo_on.rb +49 -0
- data/beaker.gemspec +2 -0
- data/lib/beaker/command.rb +1 -1
- data/lib/beaker/dsl/helpers/puppet_helpers.rb +8 -6
- data/lib/beaker/dsl/helpers/web_helpers.rb +2 -1
- data/lib/beaker/dsl/install_utils/aio_defaults.rb +0 -3
- data/lib/beaker/dsl/install_utils/foss_defaults.rb +19 -0
- data/lib/beaker/dsl/install_utils/foss_utils.rb +164 -67
- data/lib/beaker/dsl/install_utils/pe_defaults.rb +9 -11
- data/lib/beaker/dsl/install_utils/pe_utils.rb +48 -64
- data/lib/beaker/dsl/install_utils/puppet_utils.rb +43 -0
- data/lib/beaker/dsl/install_utils/windows_utils.rb +144 -0
- data/lib/beaker/dsl/roles.rb +20 -3
- data/lib/beaker/dsl/structure.rb +14 -3
- data/lib/beaker/host/freebsd/pkg.rb +18 -0
- data/lib/beaker/host/freebsd.rb +2 -0
- data/lib/beaker/host/unix/exec.rb +3 -3
- data/lib/beaker/host/unix/pkg.rb +37 -0
- data/lib/beaker/host/windows/exec.rb +3 -0
- data/lib/beaker/host.rb +38 -9
- data/lib/beaker/host_prebuilt_steps.rb +21 -11
- data/lib/beaker/hypervisor/aws_sdk.rb +22 -18
- data/lib/beaker/hypervisor/docker.rb +7 -0
- data/lib/beaker/hypervisor/openstack.rb +1 -0
- data/lib/beaker/hypervisor/vagrant_virtualbox.rb +10 -5
- data/lib/beaker/hypervisor/vmpooler.rb +4 -0
- data/lib/beaker/logger.rb +12 -1
- data/lib/beaker/options/command_line_parser.rb +9 -0
- data/lib/beaker/options/options_hash.rb +3 -296
- data/lib/beaker/options/parser.rb +12 -0
- data/lib/beaker/options/presets.rb +0 -1
- data/lib/beaker/platform.rb +3 -1
- data/lib/beaker/ssh_connection.rb +48 -23
- data/lib/beaker/test_case.rb +1 -1
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/dsl/helpers/puppet_helpers_spec.rb +0 -1
- data/spec/beaker/dsl/helpers/web_helpers_spec.rb +10 -1
- data/spec/beaker/dsl/install_utils/foss_utils_spec.rb +247 -49
- data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +116 -26
- data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +57 -0
- data/spec/beaker/dsl/install_utils/windows_utils_spec.rb +132 -0
- data/spec/beaker/dsl/roles_spec.rb +36 -5
- data/spec/beaker/dsl/structure_spec.rb +9 -2
- data/spec/beaker/host/unix/pkg_spec.rb +26 -6
- data/spec/beaker/host_prebuilt_steps_spec.rb +3 -2
- data/spec/beaker/host_spec.rb +24 -6
- data/spec/beaker/hypervisor/aixer_spec.rb +1 -1
- data/spec/beaker/hypervisor/aws_sdk_spec.rb +595 -58
- data/spec/beaker/hypervisor/docker_spec.rb +2 -1
- data/spec/beaker/hypervisor/solaris_spec.rb +1 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +20 -5
- data/spec/beaker/hypervisor/vagrant_virtualbox_spec.rb +1 -1
- data/spec/beaker/logger_spec.rb +39 -0
- data/spec/beaker/options/command_line_parser_spec.rb +2 -2
- data/spec/beaker/options/options_hash_spec.rb +1 -102
- data/spec/beaker/options/parser_spec.rb +19 -0
- data/spec/beaker/options/pe_version_scaper_spec.rb +11 -1
- data/spec/beaker/options/presets_spec.rb +8 -0
- data/spec/beaker/ssh_connection_spec.rb +39 -21
- data/spec/helpers.rb +9 -3
- data/spec/mocks.rb +2 -0
- metadata +35 -11
- data/lib/beaker/answers/version20.rb +0 -120
- data/lib/beaker/answers/version28.rb +0 -121
- data/lib/beaker/answers/version30.rb +0 -227
- data/lib/beaker/answers/version32.rb +0 -44
- data/lib/beaker/answers/version34.rb +0 -51
- data/lib/beaker/answers/version38.rb +0 -29
- data/lib/beaker/answers/version40.rb +0 -44
- data/lib/beaker/answers.rb +0 -143
- data/spec/beaker/answers_spec.rb +0 -547
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
[ 'aio_defaults', 'pe_defaults', 'puppet_utils' ].each do |lib|
|
|
1
|
+
[ 'aio_defaults', 'pe_defaults', 'puppet_utils', 'windows_utils' ].each do |lib|
|
|
2
2
|
require "beaker/dsl/install_utils/#{lib}"
|
|
3
3
|
end
|
|
4
|
+
require "beaker-answers"
|
|
4
5
|
module Beaker
|
|
5
6
|
module DSL
|
|
6
7
|
module InstallUtils
|
|
@@ -18,24 +19,7 @@ module Beaker
|
|
|
18
19
|
include AIODefaults
|
|
19
20
|
include PEDefaults
|
|
20
21
|
include PuppetUtils
|
|
21
|
-
|
|
22
|
-
# Set defaults and PATH for these hosts to be either pe or aio, have host['type'] == aio for aio settings, defaults
|
|
23
|
-
# to pe.
|
|
24
|
-
#
|
|
25
|
-
# @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
|
|
26
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
|
27
|
-
def configure_pe_defaults_on( hosts )
|
|
28
|
-
block_on hosts do |host|
|
|
29
|
-
if host[:pe_ver] && aio_version?(host) or (host['type'] && host['type'] =~ /aio/)
|
|
30
|
-
add_aio_defaults_on(host)
|
|
31
|
-
else
|
|
32
|
-
add_pe_defaults_on(host)
|
|
33
|
-
end
|
|
34
|
-
# add pathing env
|
|
35
|
-
add_puppet_paths_on(host)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
22
|
+
include WindowsUtils
|
|
39
23
|
|
|
40
24
|
# @!macro [new] common_opts
|
|
41
25
|
# @param [Hash{Symbol=>String}] opts Options to alter execution.
|
|
@@ -58,6 +42,7 @@ module Beaker
|
|
|
58
42
|
# running the command.
|
|
59
43
|
|
|
60
44
|
#Sort array of hosts so that it has the correct order for PE installation based upon each host's role
|
|
45
|
+
#@param subset [Array<Host>] An array of hosts to sort, defaults to global 'hosts' object
|
|
61
46
|
# @example
|
|
62
47
|
# h = sorted_hosts
|
|
63
48
|
#
|
|
@@ -68,12 +53,13 @@ module Beaker
|
|
|
68
53
|
# Fourth: everything else
|
|
69
54
|
#
|
|
70
55
|
# @!visibility private
|
|
71
|
-
def sorted_hosts
|
|
56
|
+
def sorted_hosts subset = hosts
|
|
72
57
|
special_nodes = []
|
|
73
58
|
[master, database, dashboard].uniq.each do |host|
|
|
74
|
-
special_nodes << host if host != nil
|
|
59
|
+
special_nodes << host if host != nil && subset.include?(host)
|
|
75
60
|
end
|
|
76
61
|
real_agents = agents - special_nodes
|
|
62
|
+
real_agents = real_agents.delete_if{ |host| !subset.include?(host) }
|
|
77
63
|
special_nodes + real_agents
|
|
78
64
|
end
|
|
79
65
|
|
|
@@ -81,8 +67,6 @@ module Beaker
|
|
|
81
67
|
# @param [Host] host The host that PE is to be installed on
|
|
82
68
|
# For UNIX machines using the full PE installer, the host object must have the 'pe_installer' field set correctly.
|
|
83
69
|
# @param [Hash{Symbol=>String}] opts The options
|
|
84
|
-
# @option opts [String] :pe_ver_win Default PE version to install or upgrade to on Windows hosts
|
|
85
|
-
# (Othersie uses individual Windows hosts pe_ver)
|
|
86
70
|
# @option opts [String] :pe_ver Default PE version to install or upgrade to
|
|
87
71
|
# (Otherwise uses individual hosts pe_ver)
|
|
88
72
|
# @option opts [Boolean] :pe_debug (false) Should we run the installer in debug mode?
|
|
@@ -91,17 +75,9 @@ module Beaker
|
|
|
91
75
|
# @api private
|
|
92
76
|
def installer_cmd(host, opts)
|
|
93
77
|
version = host['pe_ver'] || opts[:pe_ver]
|
|
94
|
-
if host['platform'] =~ /windows/
|
|
95
|
-
log_file = "#{File.basename(host['working_dir'])}.log"
|
|
96
|
-
pe_debug = host[:pe_debug] || opts[:pe_debug] ? " && cat #{log_file}" : ''
|
|
97
|
-
if host.is_cygwin?
|
|
98
|
-
"cd #{host['working_dir']} && cmd /C 'start /w msiexec.exe /qn /L*V #{log_file} /i #{host['dist']}.msi PUPPET_MASTER_SERVER=#{master} PUPPET_AGENT_CERTNAME=#{host}'#{pe_debug}"
|
|
99
|
-
else
|
|
100
|
-
"cd #{host['working_dir']} && msiexec.exe /qn /L*V #{log_file} /i #{host['dist']}.msi PUPPET_MASTER_SERVER=#{master} PUPPET_AGENT_CERTNAME=#{host}#{pe_debug}"
|
|
101
|
-
end
|
|
102
78
|
# Frictionless install didn't exist pre-3.2.0, so in that case we fall
|
|
103
79
|
# through and do a regular install.
|
|
104
|
-
|
|
80
|
+
if host['roles'].include? 'frictionless' and ! version_is_less(version, '3.2.0')
|
|
105
81
|
# PE 3.4 introduced the ability to pass in config options to the bash script in the form
|
|
106
82
|
# of <section>:<key>=<value>
|
|
107
83
|
frictionless_install_opts = []
|
|
@@ -342,6 +318,7 @@ module Beaker
|
|
|
342
318
|
# @option opts [Boolean] :fetch_local_then_push_to_host determines whether
|
|
343
319
|
# you use Beaker as the middleman for this (true), or curl the
|
|
344
320
|
# file from the host (false; default behavior)
|
|
321
|
+
# @option opts [Boolean] :masterless Are we performing a masterless installation?
|
|
345
322
|
#
|
|
346
323
|
# @example
|
|
347
324
|
# do_install(hosts, {:type => :upgrade, :pe_dir => path, :pe_ver => version, :pe_ver_win => version_win})
|
|
@@ -352,8 +329,7 @@ module Beaker
|
|
|
352
329
|
# @api private
|
|
353
330
|
#
|
|
354
331
|
def do_install hosts, opts = {}
|
|
355
|
-
masterless =
|
|
356
|
-
opts[:masterless] = masterless # has to pass masterless down for answer generation awareness
|
|
332
|
+
masterless = opts[:masterless]
|
|
357
333
|
opts[:type] = opts[:type] || :install
|
|
358
334
|
unless masterless
|
|
359
335
|
pre30database = version_is_less(opts[:pe_ver] || database['pe_ver'], '3.0')
|
|
@@ -414,18 +390,22 @@ module Beaker
|
|
|
414
390
|
install_hosts.each do |host|
|
|
415
391
|
if agent_only_check_needed && hosts_agent_only.include?(host)
|
|
416
392
|
host['type'] = 'aio'
|
|
417
|
-
install_puppet_agent_pe_promoted_repo_on(host, { :puppet_agent_version => opts[:puppet_agent_version],
|
|
418
|
-
:puppet_agent_sha => opts[:puppet_agent_sha],
|
|
419
|
-
:pe_ver => opts[:pe_ver],
|
|
420
|
-
:puppet_collection => opts[:puppet_collection] })
|
|
421
|
-
|
|
393
|
+
install_puppet_agent_pe_promoted_repo_on(host, { :puppet_agent_version => host[:puppet_agent_version] || opts[:puppet_agent_version],
|
|
394
|
+
:puppet_agent_sha => host[:puppet_agent_sha] || opts[:puppet_agent_sha],
|
|
395
|
+
:pe_ver => host[:pe_ver] || opts[:pe_ver],
|
|
396
|
+
:puppet_collection => host[:puppet_collection] || opts[:puppet_collection] })
|
|
397
|
+
# 1 since no certificate found and waitforcert disabled
|
|
398
|
+
acceptable_exit_codes = [0, 1]
|
|
399
|
+
acceptable_exit_codes << 2 if opts[:type] == :upgrade
|
|
400
|
+
setup_defaults_and_config_helper_on(host, master, acceptable_exit_codes)
|
|
422
401
|
elsif host['platform'] =~ /windows/
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
402
|
+
opts = { :debug => host[:pe_debug] || opts[:pe_debug] }
|
|
403
|
+
msi_path = "#{host['working_dir']}\\#{host['dist']}.msi"
|
|
404
|
+
install_msi_on(host, msi_path, {}, opts)
|
|
405
|
+
|
|
406
|
+
# 1 since no certificate found and waitforcert disabled
|
|
407
|
+
acceptable_exit_codes = 1
|
|
408
|
+
setup_defaults_and_config_helper_on(host, master, acceptable_exit_codes)
|
|
429
409
|
else
|
|
430
410
|
# We only need answers if we're using the classic installer
|
|
431
411
|
version = host['pe_ver'] || opts[:pe_ver]
|
|
@@ -436,17 +416,17 @@ module Beaker
|
|
|
436
416
|
deploy_frictionless_to_master(host)
|
|
437
417
|
end
|
|
438
418
|
on host, installer_cmd(host, opts)
|
|
439
|
-
|
|
419
|
+
configure_type_defaults_on(host)
|
|
440
420
|
elsif host['platform'] =~ /osx|eos/
|
|
441
421
|
# If we're not frictionless, we need to run the OSX special-case
|
|
442
422
|
on host, installer_cmd(host, opts)
|
|
443
423
|
acceptable_codes = host['platform'] =~ /osx/ ? [1] : [0, 1]
|
|
444
424
|
setup_defaults_and_config_helper_on(host, master, acceptable_codes)
|
|
445
425
|
else
|
|
446
|
-
answers =
|
|
426
|
+
answers = BeakerAnswers::Answers.create(opts[:pe_ver] || host['pe_ver'], hosts, opts)
|
|
447
427
|
create_remote_file host, "#{host['working_dir']}/answers", answers.answer_string(host)
|
|
448
428
|
on host, installer_cmd(host, opts)
|
|
449
|
-
|
|
429
|
+
configure_type_defaults_on(host)
|
|
450
430
|
end
|
|
451
431
|
end
|
|
452
432
|
|
|
@@ -534,7 +514,7 @@ module Beaker
|
|
|
534
514
|
# @return nil
|
|
535
515
|
# @api private
|
|
536
516
|
def setup_defaults_and_config_helper_on(host, master, acceptable_exit_codes=nil)
|
|
537
|
-
|
|
517
|
+
configure_type_defaults_on(host)
|
|
538
518
|
#set the certname and master
|
|
539
519
|
on host, puppet("config set server #{master}")
|
|
540
520
|
on host, puppet("config set certname #{host}")
|
|
@@ -550,12 +530,12 @@ module Beaker
|
|
|
550
530
|
|
|
551
531
|
#Install PE based upon host configuration and options
|
|
552
532
|
#
|
|
553
|
-
# @param [Host, Array<Host
|
|
554
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
|
533
|
+
# @param [Host, Array<Host>] install_hosts One or more hosts to act upon
|
|
555
534
|
# @!macro common_opts
|
|
535
|
+
# @option opts [Boolean] :masterless Are we performing a masterless installation?
|
|
556
536
|
# @option opts [String] :puppet_agent_version Version of puppet-agent to install. Required for PE agent
|
|
557
537
|
# only hosts on 4.0+
|
|
558
|
-
# @option opts [String] :puppet_agent_sha The sha of puppet-agent to install, defaults to
|
|
538
|
+
# @option opts [String] :puppet_agent_sha The sha of puppet-agent to install, defaults to puppet_agent_version.
|
|
559
539
|
# Required for PE agent only hosts on 4.0+
|
|
560
540
|
# @option opts [String] :pe_ver The version of PE (will also use host['pe_ver']), defaults to '4.0'
|
|
561
541
|
# @option opts [String] :puppet_collection The puppet collection for puppet-agent install.
|
|
@@ -567,17 +547,22 @@ module Beaker
|
|
|
567
547
|
# Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
|
|
568
548
|
# for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
|
|
569
549
|
#
|
|
570
|
-
def install_pe_on(
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
550
|
+
def install_pe_on(install_hosts, opts)
|
|
551
|
+
confine_block(:to, {}, install_hosts) do
|
|
552
|
+
sorted_hosts.each do |host|
|
|
553
|
+
#process the version files if necessary
|
|
574
554
|
host['pe_dir'] ||= opts[:pe_dir]
|
|
575
555
|
if host['platform'] =~ /windows/
|
|
576
|
-
|
|
577
|
-
|
|
556
|
+
# we don't need the pe_version if:
|
|
557
|
+
# * master pe_ver > 4.0
|
|
558
|
+
if not (!opts[:masterless] && master[:pe_ver] && !version_is_less(master[:pe_ver], '3.99'))
|
|
559
|
+
host['pe_ver'] ||= Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir] || opts[:pe_dir], opts[:pe_version_file_win])
|
|
560
|
+
else
|
|
561
|
+
# inherit the master's version
|
|
562
|
+
host['pe_ver'] ||= master[:pe_ver]
|
|
563
|
+
end
|
|
578
564
|
else
|
|
579
|
-
host['pe_ver']
|
|
580
|
-
Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir] || opts[:pe_dir], opts[:pe_version_file])
|
|
565
|
+
host['pe_ver'] ||= Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir] || opts[:pe_dir], opts[:pe_version_file])
|
|
581
566
|
end
|
|
582
567
|
end
|
|
583
568
|
do_install sorted_hosts, opts
|
|
@@ -591,8 +576,7 @@ module Beaker
|
|
|
591
576
|
end
|
|
592
577
|
|
|
593
578
|
#Upgrade PE based upon host configuration and options
|
|
594
|
-
# @param [Host, Array<Host
|
|
595
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
|
579
|
+
# @param [Host, Array<Host>] upgrade_hosts One or more hosts to act upon
|
|
596
580
|
# @!macro common_opts
|
|
597
581
|
# @param [String] path A path (either local directory or a URL to a listing of PE builds).
|
|
598
582
|
# Will contain a LATEST file indicating the latest build to install.
|
|
@@ -603,8 +587,8 @@ module Beaker
|
|
|
603
587
|
#
|
|
604
588
|
# @note Install file names are assumed to be of the format puppet-enterprise-VERSION-PLATFORM.(tar)|(tar.gz)
|
|
605
589
|
# for Unix like systems and puppet-enterprise-VERSION.msi for Windows systems.
|
|
606
|
-
def upgrade_pe_on
|
|
607
|
-
confine_block(:to, {},
|
|
590
|
+
def upgrade_pe_on upgrade_hosts, opts, path=nil
|
|
591
|
+
confine_block(:to, {}, upgrade_hosts) do
|
|
608
592
|
set_console_password = false
|
|
609
593
|
# if we are upgrading from something lower than 3.4 then we need to set the pe console password
|
|
610
594
|
if (dashboard[:pe_ver] ? version_is_less(dashboard[:pe_ver], "3.4.0") : true)
|
|
@@ -65,6 +65,46 @@ module Beaker
|
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
# Configure the provided hosts to be of their host[:type], it host[type] == nil do nothing
|
|
69
|
+
def configure_type_defaults_on( hosts )
|
|
70
|
+
block_on hosts do |host|
|
|
71
|
+
has_defaults = false
|
|
72
|
+
if host[:type]
|
|
73
|
+
host_type = host[:type]
|
|
74
|
+
# clean up the naming conventions here (some teams use foss-package, git-whatever, we need
|
|
75
|
+
# to correctly handle that
|
|
76
|
+
# don't worry about aio, that happens in the aio_version? check
|
|
77
|
+
host_type = case host_type
|
|
78
|
+
when /(\A|-)(git)|(foss)(\Z|-)/
|
|
79
|
+
'foss'
|
|
80
|
+
when /(\A|-)pe(\Z|-)/
|
|
81
|
+
'pe'
|
|
82
|
+
else
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
85
|
+
if host_type
|
|
86
|
+
add_method = "add_#{host_type}_defaults_on"
|
|
87
|
+
if self.respond_to?(add_method, host)
|
|
88
|
+
self.send(add_method, host)
|
|
89
|
+
else
|
|
90
|
+
raise "cannot add defaults of type #{host_type} for host #{host.name} (#{add_method} not present)"
|
|
91
|
+
end
|
|
92
|
+
has_defaults = true
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
if aio_version?(host)
|
|
96
|
+
add_aio_defaults_on(host)
|
|
97
|
+
has_defaults = true
|
|
98
|
+
end
|
|
99
|
+
# add pathing env
|
|
100
|
+
if has_defaults
|
|
101
|
+
add_puppet_paths_on(host)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
alias_method :configure_foss_defaults_on, :configure_type_defaults_on
|
|
106
|
+
alias_method :configure_pe_defaults_on, :configure_type_defaults_on
|
|
107
|
+
|
|
68
108
|
#If the host is associated with a type remove all defaults and environment associated with that type.
|
|
69
109
|
# @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
|
|
70
110
|
# or a role (String or Symbol) that identifies one or more hosts.
|
|
@@ -78,6 +118,9 @@ module Beaker
|
|
|
78
118
|
else
|
|
79
119
|
raise "cannot remove defaults of type #{host['type']} associated with host #{host.name} (#{remove_method} not present)"
|
|
80
120
|
end
|
|
121
|
+
if aio_version?(host)
|
|
122
|
+
remove_aio_defaults_on(host)
|
|
123
|
+
end
|
|
81
124
|
end
|
|
82
125
|
end
|
|
83
126
|
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module Beaker
|
|
2
|
+
module DSL
|
|
3
|
+
module InstallUtils
|
|
4
|
+
#
|
|
5
|
+
# This module contains methods useful for Windows installs
|
|
6
|
+
#
|
|
7
|
+
module WindowsUtils
|
|
8
|
+
|
|
9
|
+
# Given a host, returns it's system TEMP path
|
|
10
|
+
# @param [Host] host An object implementing {Beaker::Hosts}'s interface.
|
|
11
|
+
def get_temp_path(host)
|
|
12
|
+
# under CYGWIN %TEMP% may not be set
|
|
13
|
+
tmp_path = on(host, Command.new('ECHO %SYSTEMROOT%', [], { :cmdexe => true }))
|
|
14
|
+
tmp_path.output.gsub(/\n/, '') + '\\TEMP'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Generates commands to be inserted into a Windows batch file to launch an MSI install
|
|
18
|
+
# @param [String] msi_path The path of the MSI - can be a local Windows style file path like
|
|
19
|
+
# c:\temp\puppet.msi OR a url like https://download.com/puppet.msi or file://c:\temp\puppet.msi
|
|
20
|
+
# @param [Hash{String=>String}] msi_opts MSI installer options
|
|
21
|
+
# See https://docs.puppetlabs.com/guides/install_puppet/install_windows.html#msi-properties
|
|
22
|
+
# @param [String] log_path The path to write the MSI log - must be a local Windows style file path
|
|
23
|
+
#
|
|
24
|
+
# @api private
|
|
25
|
+
def msi_install_script(msi_path, msi_opts, log_path)
|
|
26
|
+
# msiexec requires backslashes in file paths launched under cmd.exe start /w
|
|
27
|
+
url_pattern = /^(https?|file):\/\//
|
|
28
|
+
msi_path = msi_path.gsub(/\//, "\\") if msi_path !~ url_pattern
|
|
29
|
+
|
|
30
|
+
msi_params = msi_opts.map{|k, v| "#{k}=#{v}"}.join(' ')
|
|
31
|
+
|
|
32
|
+
# msiexec requires quotes around paths with backslashes - c:\ or file://c:\
|
|
33
|
+
# not strictly needed for http:// but it simplifies this code
|
|
34
|
+
batch_contents = <<-BATCH
|
|
35
|
+
start /w msiexec.exe /i \"#{msi_path}\" /qn /L*V #{log_path} #{msi_params}
|
|
36
|
+
exit /B %errorlevel%
|
|
37
|
+
BATCH
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Given a host, path to MSI and MSI options, will create a batch file
|
|
41
|
+
# on the host, returning the path to the randomized batch file and
|
|
42
|
+
# the randomized log file
|
|
43
|
+
# @param [Host] host An object implementing {Beaker::Hosts}'s interface.
|
|
44
|
+
# @param [String] msi_path The path of the MSI - can be a local Windows style file path like
|
|
45
|
+
# c:\temp\puppet.msi OR a url like https://download.com/puppet.msi or file://c:\temp\puppet.msi
|
|
46
|
+
# @param [Hash{String=>String}] msi_opts MSI installer options
|
|
47
|
+
# See https://docs.puppetlabs.com/guides/install_puppet/install_windows.html#msi-properties
|
|
48
|
+
# @api private
|
|
49
|
+
def create_install_msi_batch_on(host, msi_path, msi_opts)
|
|
50
|
+
timestamp = Time.new.strftime('%Y-%m-%d_%H.%M.%S')
|
|
51
|
+
tmp_path = get_temp_path(host)
|
|
52
|
+
|
|
53
|
+
batch_name = "install-puppet-msi-#{timestamp}.bat"
|
|
54
|
+
batch_path = "#{tmp_path}\\#{batch_name}"
|
|
55
|
+
|
|
56
|
+
log_path = "#{tmp_path}\\install-puppet-#{timestamp}.log"
|
|
57
|
+
|
|
58
|
+
Tempfile.open(batch_name) do |tmp_file|
|
|
59
|
+
batch_contents = msi_install_script(msi_path, msi_opts, log_path)
|
|
60
|
+
|
|
61
|
+
File.open(tmp_file.path, 'w') { |file| file.puts(batch_contents) }
|
|
62
|
+
host.do_scp_to(tmp_file.path, batch_path, {})
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return batch_path, log_path
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Given hosts construct a PATH that includes puppetbindir, facterbindir and hierabindir
|
|
69
|
+
# @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon,
|
|
70
|
+
# or a role (String or Symbol) that identifies one or more hosts.
|
|
71
|
+
# @param [String] msi_path The path of the MSI - can be a local Windows style file path like
|
|
72
|
+
# c:\temp\puppet.msi OR a url like https://download.com/puppet.msi or file://c:\temp\puppet.msi
|
|
73
|
+
# @param [Hash{String=>String}] msi_opts MSI installer options
|
|
74
|
+
# See https://docs.puppetlabs.com/guides/install_puppet/install_windows.html#msi-properties
|
|
75
|
+
# @option msi_opts [String] INSTALLIDIR Where Puppet and its dependencies should be installed.
|
|
76
|
+
# (Defaults vary based on operating system and intaller architecture)
|
|
77
|
+
# Requires Puppet 2.7.12 / PE 2.5.0
|
|
78
|
+
# @option msi_opts [String] PUPPET_MASTER_SERVER The hostname where the puppet master server can be reached.
|
|
79
|
+
# (Defaults to puppet)
|
|
80
|
+
# Requires Puppet 2.7.12 / PE 2.5.0
|
|
81
|
+
# @option msi_opts [String] PUPPET_CA_SERVER The hostname where the CA puppet master server can be reached, if you are using multiple masters and only one of them is acting as the CA.
|
|
82
|
+
# (Defaults the value of PUPPET_MASTER_SERVER)
|
|
83
|
+
# Requires Puppet 2.7.12 / PE 2.5.0
|
|
84
|
+
# @option msi_opts [String] PUPPET_AGENT_CERTNAME The node’s certificate name, and the name it uses when requesting catalogs. This will set a value for
|
|
85
|
+
# (Defaults to the node's fqdn as discovered by facter fqdn)
|
|
86
|
+
# Requires Puppet 2.7.12 / PE 2.5.0
|
|
87
|
+
# @option msi_opts [String] PUPPET_AGENT_ENVIRONMENT The node’s environment.
|
|
88
|
+
# (Defaults to production)
|
|
89
|
+
# Requires Puppet 3.3.1 / PE 3.1.0
|
|
90
|
+
# @option msi_opts [String] PUPPET_AGENT_STARTUP_MODE Whether the puppet agent service should run (or be allowed to run)
|
|
91
|
+
# (Defaults to Manual - valid values are Automatic, Manual or Disabled)
|
|
92
|
+
# Requires Puppet 3.4.0 / PE 3.2.0
|
|
93
|
+
# @option msi_opts [String] PUPPET_AGENT_ACCOUNT_USER Whether the puppet agent service should run (or be allowed to run)
|
|
94
|
+
# (Defaults to LocalSystem)
|
|
95
|
+
# Requires Puppet 3.4.0 / PE 3.2.0
|
|
96
|
+
# @option msi_opts [String] PUPPET_AGENT_ACCOUNT_PASSWORD The password to use for puppet agent’s user account
|
|
97
|
+
# (No default)
|
|
98
|
+
# Requires Puppet 3.4.0 / PE 3.2.0
|
|
99
|
+
# @option msi_opts [String] PUPPET_AGENT_ACCOUNT_DOMAIN The domain of puppet agent’s user account.
|
|
100
|
+
# (Defaults to .)
|
|
101
|
+
# Requires Puppet 3.4.0 / PE 3.2.0
|
|
102
|
+
# @option opts [Boolean] :debug output the MSI installation log when set to true
|
|
103
|
+
# otherwise do not output log (false; default behavior)
|
|
104
|
+
#
|
|
105
|
+
# @example
|
|
106
|
+
# install_msi_on(hosts, 'c:\puppet.msi', {:debug => true})
|
|
107
|
+
#
|
|
108
|
+
# @api private
|
|
109
|
+
def install_msi_on(hosts, msi_path, msi_opts = {}, opts = {})
|
|
110
|
+
block_on hosts do | host |
|
|
111
|
+
msi_opts['PUPPET_AGENT_STARTUP_MODE'] ||= 'Manual'
|
|
112
|
+
batch_path, log_file = create_install_msi_batch_on(host, msi_path, msi_opts)
|
|
113
|
+
|
|
114
|
+
# begin / rescue here so that we can reuse existing error msg propagation
|
|
115
|
+
begin
|
|
116
|
+
# 1641 = ERROR_SUCCESS_REBOOT_INITIATED
|
|
117
|
+
# 3010 = ERROR_SUCCESS_REBOOT_REQUIRED
|
|
118
|
+
on host, Command.new("\"#{batch_path}\"", [], { :cmdexe => true }), :acceptable_exit_codes => [0, 1641, 3010]
|
|
119
|
+
rescue
|
|
120
|
+
on host, Command.new("type \"#{log_file}\"", [], { :cmdexe => true })
|
|
121
|
+
raise
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
if opts[:debug]
|
|
125
|
+
on host, Command.new("type \"#{log_file}\"", [], { :cmdexe => true })
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if !host.is_cygwin?
|
|
129
|
+
# HACK: for some reason, post install we need to refresh the connection to make puppet available for execution
|
|
130
|
+
host.close
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# verify service status post install
|
|
134
|
+
# if puppet service exists, then pe-puppet is not queried
|
|
135
|
+
# if puppet service does not exist, pe-puppet is queried and that exit code is used
|
|
136
|
+
# therefore, this command will always exit 0 if either service is installed
|
|
137
|
+
on host, Command.new("sc query puppet || sc query pe-puppet", [], { :cmdexe => true })
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
data/lib/beaker/dsl/roles.rb
CHANGED
|
@@ -119,16 +119,25 @@ module Beaker
|
|
|
119
119
|
host['roles'].length == 1 && host['roles'].include?('agent')
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
# Determine whether a host has an AIO version or not. If a host :pe_ver
|
|
122
|
+
# Determine whether a host has an AIO version or not. If a host :pe_ver or :version
|
|
123
123
|
# is not specified, then it is open-ended, and as such, can be an AIO
|
|
124
124
|
# version depending on the context.
|
|
125
125
|
#
|
|
126
|
+
# True when any of the following cases are true
|
|
127
|
+
# * has PE version (:pe_ver) >= 4.0
|
|
128
|
+
# * has FOSS version (:version) >= 4.0
|
|
129
|
+
# * host has role 'aio'
|
|
130
|
+
# * host as the type 'aio'
|
|
131
|
+
#
|
|
126
132
|
# @note aio version is just a base-line condition. If you want to check
|
|
127
133
|
# that a host is an aio agent, refer to {#aio_agent?}.
|
|
128
134
|
#
|
|
129
135
|
# @return [Boolean] whether or not a host is AIO-capable
|
|
130
136
|
def aio_version?(host)
|
|
131
|
-
return
|
|
137
|
+
return (( host[:pe_ver] && !version_is_less(host[:pe_ver], '4.0') ) ||
|
|
138
|
+
( host[:version] && !version_is_less(host[:version], '4.0') ) ||
|
|
139
|
+
( host[:roles] && host[:roles].include?('aio')) ||
|
|
140
|
+
( host[:type] && !!(host[:type] =~ /(\A|-)aio(\Z|-)/ ))) == true
|
|
132
141
|
end
|
|
133
142
|
|
|
134
143
|
# Determine if the host is an AIO agent
|
|
@@ -140,6 +149,14 @@ module Beaker
|
|
|
140
149
|
aio_version?(host) && agent_only(host)
|
|
141
150
|
end
|
|
142
151
|
|
|
152
|
+
# Add the provided role to the host
|
|
153
|
+
#
|
|
154
|
+
# @param [Host] host Host to add role to
|
|
155
|
+
# @param [String] role The role to add to host
|
|
156
|
+
def add_role(host, role)
|
|
157
|
+
host[:roles] = host[:roles] | [role]
|
|
158
|
+
end
|
|
159
|
+
|
|
143
160
|
#Create a new role method for a given arbitrary role name. Makes it possible to be able to run
|
|
144
161
|
#commands without having to refer to role by String or Symbol. Will not add a new method
|
|
145
162
|
#definition if the name is already in use.
|
|
@@ -156,7 +173,7 @@ module Beaker
|
|
|
156
173
|
else
|
|
157
174
|
if not respond_to? role
|
|
158
175
|
if role !~ /\A[[:alpha:]]+[a-zA-Z0-9_]*[!?=]?\Z/
|
|
159
|
-
raise "Role name format error for '#{role}'. Allowed characters are: \na-Z\n0-9 (as long as not at the beginning of name)\n'_'\n'?', '!' and '=' (only as individual last character at end of name)"
|
|
176
|
+
raise ArgumentError, "Role name format error for '#{role}'. Allowed characters are: \na-Z\n0-9 (as long as not at the beginning of name)\n'_'\n'?', '!' and '=' (only as individual last character at end of name)"
|
|
160
177
|
end
|
|
161
178
|
self.class.send :define_method, role.to_s do
|
|
162
179
|
hosts_with_role = hosts_as role.to_sym
|
data/lib/beaker/dsl/structure.rb
CHANGED
|
@@ -167,18 +167,29 @@ module Beaker
|
|
|
167
167
|
# @example Confining to an already defined subset of hosts
|
|
168
168
|
# confine :to, {}, agents
|
|
169
169
|
#
|
|
170
|
+
# @example Confining from an already defined subset of hosts
|
|
171
|
+
# confine :except, {}, agents
|
|
172
|
+
#
|
|
173
|
+
#
|
|
170
174
|
# @return [Array<Host>] Returns an array of hosts that are still valid
|
|
171
175
|
# targets for this tests case.
|
|
172
176
|
# @raise [SkipTest] Raises skip test if there are no valid hosts for
|
|
173
177
|
# this test case after confinement.
|
|
174
178
|
def confine(type, criteria, host_array = nil, &block)
|
|
175
|
-
hosts_to_modify = host_array || hosts
|
|
179
|
+
hosts_to_modify = Array( host_array || hosts )
|
|
176
180
|
case type
|
|
177
181
|
when :except
|
|
178
|
-
|
|
182
|
+
if criteria and ( not criteria.empty? )
|
|
183
|
+
hosts_to_modify = hosts_to_modify - select_hosts(criteria, hosts_to_modify, &block)
|
|
184
|
+
else
|
|
185
|
+
# confining to all hosts *except* provided array of hosts
|
|
186
|
+
hosts_to_modify = hosts - host_array
|
|
187
|
+
end
|
|
179
188
|
when :to
|
|
180
189
|
if criteria and ( not criteria.empty? )
|
|
181
190
|
hosts_to_modify = select_hosts(criteria, hosts_to_modify, &block)
|
|
191
|
+
else
|
|
192
|
+
# confining to only hosts in provided array of hosts
|
|
182
193
|
end
|
|
183
194
|
else
|
|
184
195
|
raise "Unknown option #{type}"
|
|
@@ -198,7 +209,7 @@ module Beaker
|
|
|
198
209
|
# @see #confine
|
|
199
210
|
def confine_block(type, criteria, host_array = nil, &block)
|
|
200
211
|
begin
|
|
201
|
-
host_array
|
|
212
|
+
host_array = Array( host_array || hosts )
|
|
202
213
|
original_hosts = self.hosts.dup
|
|
203
214
|
confine(type, criteria, host_array)
|
|
204
215
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module FreeBSD::Pkg
|
|
2
|
+
include Beaker::CommandFactory
|
|
3
|
+
|
|
4
|
+
def install_package(name, cmdline_args = nil, opts = {})
|
|
5
|
+
case self['platform']
|
|
6
|
+
when /freebsd-9/
|
|
7
|
+
cmdline_args ||= '-rF'
|
|
8
|
+
result = execute("pkg_add #{cmdline_args} #{name}", opts) { |result| result }
|
|
9
|
+
when /freebsd-10/
|
|
10
|
+
cmdline_args ||= '-y'
|
|
11
|
+
result = execute("pkg install #{cmdline_args} #{name}", opts) { |result| result }
|
|
12
|
+
else
|
|
13
|
+
raise "Package #{name} could not be installed on #{self}"
|
|
14
|
+
end
|
|
15
|
+
result.exit_code == 0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
data/lib/beaker/host/freebsd.rb
CHANGED
|
@@ -102,11 +102,11 @@ module Unix::Exec
|
|
|
102
102
|
env_file = self[:ssh_env_file]
|
|
103
103
|
escaped_val = Regexp.escape(val).gsub('/', '\/').gsub(';', '\;')
|
|
104
104
|
#see if the key/value pair already exists
|
|
105
|
-
if exec(Beaker::Command.new("grep
|
|
105
|
+
if exec(Beaker::Command.new("grep ^#{key}=.*#{escaped_val} #{env_file}"), :accept_all_exit_codes => true ).exit_code == 0
|
|
106
106
|
return #nothing to do here, key value pair already exists
|
|
107
107
|
#see if the key already exists
|
|
108
|
-
elsif exec(Beaker::Command.new("grep
|
|
109
|
-
exec(Beaker::SedCommand.new(self['platform'], "s
|
|
108
|
+
elsif exec(Beaker::Command.new("grep ^#{key} #{env_file}"), :accept_all_exit_codes => true ).exit_code == 0
|
|
109
|
+
exec(Beaker::SedCommand.new(self['platform'], "s/^#{key}=/#{key}=#{escaped_val}:/", env_file))
|
|
110
110
|
else
|
|
111
111
|
exec(Beaker::Command.new("echo \"#{key}=#{val}\" >> #{env_file}"))
|
|
112
112
|
end
|
data/lib/beaker/host/unix/pkg.rb
CHANGED
|
@@ -40,6 +40,8 @@ module Unix::Pkg
|
|
|
40
40
|
result = execute("pkg_info #{name}", opts) { |result| result }
|
|
41
41
|
when /freebsd-10/
|
|
42
42
|
result = execute("pkg info #{name}", opts) { |result| result }
|
|
43
|
+
when /openbsd/
|
|
44
|
+
result = execute("pkg_info #{name}", opts) { |result| result }
|
|
43
45
|
else
|
|
44
46
|
raise "Package #{name} cannot be queried on #{self}"
|
|
45
47
|
end
|
|
@@ -63,6 +65,11 @@ module Unix::Pkg
|
|
|
63
65
|
execute("zypper --non-interactive in #{name}", opts)
|
|
64
66
|
when /el-4/
|
|
65
67
|
@logger.debug("Package installation not supported on rhel4")
|
|
68
|
+
when /fedora-22/
|
|
69
|
+
if version
|
|
70
|
+
name = "#{name}-#{version}"
|
|
71
|
+
end
|
|
72
|
+
execute("dnf -y #{cmdline_args} install #{name}", opts)
|
|
66
73
|
when /cisco|fedora|centos|eos|el-/
|
|
67
74
|
if version
|
|
68
75
|
name = "#{name}-#{version}"
|
|
@@ -82,6 +89,32 @@ module Unix::Pkg
|
|
|
82
89
|
execute("pkg_add -fr #{cmdline_args} #{name}", opts)
|
|
83
90
|
when /freebsd-10/
|
|
84
91
|
execute("pkg #{cmdline_args} install #{name}", opts)
|
|
92
|
+
when /openbsd/
|
|
93
|
+
begin
|
|
94
|
+
execute("pkg_add -I #{cmdline_args} #{name}", opts) do |command|
|
|
95
|
+
# Handles where there are multiple rubies, installs the latest one
|
|
96
|
+
if command.stderr =~ /^Ambiguous: #{name} could be (.+)$/
|
|
97
|
+
name = $1.chomp.split(' ').collect { |x|
|
|
98
|
+
x =~ /-(\d[^-p]+)/
|
|
99
|
+
[x, $1]
|
|
100
|
+
}.select { |x|
|
|
101
|
+
# Blacklist Ruby 2.2.0+ for the sake of Puppet 3.x
|
|
102
|
+
Gem::Version.new(x[1]) < Gem::Version.new('2.2.0')
|
|
103
|
+
}.sort { |a,b|
|
|
104
|
+
Gem::Version.new(b[1]) <=> Gem::Version.new(a[1])
|
|
105
|
+
}.collect { |x|
|
|
106
|
+
x[0]
|
|
107
|
+
}.first
|
|
108
|
+
raise ArgumentException
|
|
109
|
+
end
|
|
110
|
+
# If the package advises symlinks to be created, do it
|
|
111
|
+
command.stdout.split(/\n/).select { |x| x =~ /^\s+ln\s/ }.each do |ln|
|
|
112
|
+
execute(ln, opts)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
rescue
|
|
116
|
+
retry
|
|
117
|
+
end
|
|
85
118
|
else
|
|
86
119
|
raise "Package #{name} cannot be installed on #{self}"
|
|
87
120
|
end
|
|
@@ -93,6 +126,8 @@ module Unix::Pkg
|
|
|
93
126
|
execute("zypper --non-interactive rm #{name}", opts)
|
|
94
127
|
when /el-4/
|
|
95
128
|
@logger.debug("Package uninstallation not supported on rhel4")
|
|
129
|
+
when /fedora-22/
|
|
130
|
+
execute("dnf -y #{cmdline_args} remove #{name}", opts)
|
|
96
131
|
when /cisco|fedora|centos|eos|el-/
|
|
97
132
|
execute("yum -y #{cmdline_args} remove #{name}", opts)
|
|
98
133
|
when /ubuntu|debian|cumulus/
|
|
@@ -117,6 +152,8 @@ module Unix::Pkg
|
|
|
117
152
|
execute("zypper --non-interactive --no-gpg-checks up #{name}", opts)
|
|
118
153
|
when /el-4/
|
|
119
154
|
@logger.debug("Package upgrade is not supported on rhel4")
|
|
155
|
+
when /fedora-22/
|
|
156
|
+
execute("dnf -y #{cmdline_args} update #{name}", opts)
|
|
120
157
|
when /cisco|fedora|centos|eos|el-/
|
|
121
158
|
execute("yum -y #{cmdline_args} update #{name}", opts)
|
|
122
159
|
when /ubuntu|debian|cumulus/
|
|
@@ -3,6 +3,9 @@ module Windows::Exec
|
|
|
3
3
|
|
|
4
4
|
def reboot
|
|
5
5
|
exec(Beaker::Command.new('shutdown /r /t 0 /d p:4:1 /c "Beaker::Host reboot command issued"'), :expect_connection_failure => true)
|
|
6
|
+
# rebooting on windows is sloooooow
|
|
7
|
+
# give it some breathing room before attempting a reconnect
|
|
8
|
+
sleep(30)
|
|
6
9
|
end
|
|
7
10
|
|
|
8
11
|
ABS_CMD = 'c:\\\\windows\\\\system32\\\\cmd.exe'
|