beaker 2.7.1 → 2.8.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 +121 -2
- data/lib/beaker/dsl.rb +2 -2
- data/lib/beaker/dsl/helpers.rb +13 -1429
- data/lib/beaker/dsl/helpers/facter_helpers.rb +48 -0
- data/lib/beaker/dsl/helpers/hiera_helpers.rb +71 -0
- data/lib/beaker/dsl/helpers/host_helpers.rb +506 -0
- data/lib/beaker/dsl/helpers/puppet_helpers.rb +698 -0
- data/lib/beaker/dsl/helpers/tk_helpers.rb +101 -0
- data/lib/beaker/dsl/helpers/web_helpers.rb +115 -0
- data/lib/beaker/dsl/install_utils.rb +8 -1570
- data/lib/beaker/dsl/install_utils/ezbake_utils.rb +256 -0
- data/lib/beaker/dsl/install_utils/module_utils.rb +237 -0
- data/lib/beaker/dsl/install_utils/pe_utils.rb +518 -0
- data/lib/beaker/dsl/install_utils/puppet_utils.rb +722 -0
- data/lib/beaker/dsl/outcomes.rb +0 -4
- data/lib/beaker/dsl/roles.rb +0 -3
- data/lib/beaker/dsl/structure.rb +127 -4
- data/lib/beaker/dsl/wrappers.rb +0 -4
- data/lib/beaker/host.rb +23 -0
- data/lib/beaker/host/unix/pkg.rb +4 -4
- data/lib/beaker/host_prebuilt_steps.rb +11 -5
- data/lib/beaker/hypervisor/vagrant.rb +1 -0
- data/lib/beaker/hypervisor/vmpooler.rb +38 -0
- data/lib/beaker/logger.rb +10 -4
- data/lib/beaker/network_manager.rb +5 -4
- data/lib/beaker/options/command_line_parser.rb +7 -0
- data/lib/beaker/shared.rb +2 -1
- data/lib/beaker/shared/semvar.rb +41 -0
- data/lib/beaker/test_suite.rb +20 -6
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/dsl/helpers/facter_helpers_spec.rb +59 -0
- data/spec/beaker/dsl/helpers/hiera_helpers_spec.rb +96 -0
- data/spec/beaker/dsl/helpers/host_helpers_spec.rb +413 -0
- data/spec/beaker/dsl/{helpers_spec.rb → helpers/puppet_helpers_spec.rb} +2 -611
- data/spec/beaker/dsl/helpers/tk_helpers_spec.rb +83 -0
- data/spec/beaker/dsl/helpers/web_helpers_spec.rb +60 -0
- data/spec/beaker/dsl/install_utils/module_utils_spec.rb +241 -0
- data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +475 -0
- data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +523 -0
- data/spec/beaker/dsl/structure_spec.rb +108 -0
- data/spec/beaker/host_prebuilt_steps_spec.rb +44 -0
- data/spec/beaker/host_spec.rb +41 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +2 -1
- data/spec/beaker/logger_spec.rb +9 -2
- data/spec/beaker/network_manager_spec.rb +7 -1
- data/spec/beaker/options/command_line_parser_spec.rb +3 -2
- data/spec/beaker/shared/semvar_spec.rb +36 -0
- data/spec/beaker/test_suite_spec.rb +48 -0
- data/spec/mocks.rb +10 -0
- metadata +23 -5
- data/lib/beaker/dsl/ezbake_utils.rb +0 -259
- data/spec/beaker/dsl/install_utils_spec.rb +0 -1242
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZjYxOGQ2OTU1ODFmMGMyYzU5YTE3ZTg2ZTNhYjUzYzVkMTE4ZmZhNg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NGU4Y2UxNGI0YmMxZjRiZTRkNmY2ZjljNDlmZTY2YjUzZDg0ZDdkNw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OTYwZTkxZDE1ZjIxZjdjNjcwZWM2OTg2MGM0YWIyZDUyMTEyY2U3OGExY2Jh
|
10
|
+
ZGNlNGMyYjA5YjJhOGIyZWE2MmI1NDlhMWM3NzI4YzZlNzkzNjg1MTY4ZWQ2
|
11
|
+
MWJmOTFiYjYzYTg1NTFkZDIxZTkxMmJlMzJkNmM3YTJkODE1YzQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MWYzNWYxNzcwZDI2YTc1ZWFmOGE4M2ZjNjNmMGY5NjRiMDVhMmZhNzE1ODJl
|
14
|
+
NjAxN2U5ZmQ4Yjc1NDZkYTkwYzkzZDIxOTY0NDNjZjYyMjdlYTk2NTdjOGRh
|
15
|
+
NWI2YmU3YjgyODM0ZDQ3ZjNhMGQyZmMyMDBmZjkyZDU0OTNiNDA=
|
data/HISTORY.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# default - History
|
2
2
|
## Tags
|
3
|
-
* [LATEST -
|
3
|
+
* [LATEST - 26 Mar, 2015 (f320c276)](#LATEST)
|
4
|
+
* [beaker2.7.1 - 19 Mar, 2015 (45b2bf10)](#beaker2.7.1)
|
4
5
|
* [beaker2.7.0 - 19 Mar, 2015 (38b14ef8)](#beaker2.7.0)
|
5
6
|
* [beaker2.6.0 - 12 Mar, 2015 (d4e731ab)](#beaker2.6.0)
|
6
7
|
* [beaker2.5.1 - 4 Mar, 2015 (009c2c63)](#beaker2.5.1)
|
@@ -75,7 +76,125 @@
|
|
75
76
|
* [pe1.2 - 6 Sep, 2011 (ba3dadd2)](#pe1.2)
|
76
77
|
|
77
78
|
## Details
|
78
|
-
### <a name = "LATEST">LATEST -
|
79
|
+
### <a name = "LATEST">LATEST - 26 Mar, 2015 (f320c276)
|
80
|
+
|
81
|
+
* (GEM) update beaker version to 2.8.0 (f320c276)
|
82
|
+
|
83
|
+
* Merge pull request #759 from sschneid/vmpooler_tagging (97052ab4)
|
84
|
+
|
85
|
+
|
86
|
+
```
|
87
|
+
Merge pull request #759 from sschneid/vmpooler_tagging
|
88
|
+
|
89
|
+
(BKR-155) Add simple tagging to vmpooler hosts
|
90
|
+
```
|
91
|
+
* Merge pull request #755 from anodelman/acceptance (0ac1460d)
|
92
|
+
|
93
|
+
|
94
|
+
```
|
95
|
+
Merge pull request #755 from anodelman/acceptance
|
96
|
+
|
97
|
+
(BKR-77) breakup dsl/helpers and dsl/install_utils
|
98
|
+
```
|
99
|
+
* Merge pull request #754 from anodelman/win-fix (f426a7cf)
|
100
|
+
|
101
|
+
|
102
|
+
```
|
103
|
+
Merge pull request #754 from anodelman/win-fix
|
104
|
+
|
105
|
+
(BKR-151) periodic failure to restart ssh on windows
|
106
|
+
```
|
107
|
+
* Merge pull request #734 from kevpl/bkr5_log_prefix (4aaedb45)
|
108
|
+
|
109
|
+
|
110
|
+
```
|
111
|
+
Merge pull request #734 from kevpl/bkr5_log_prefix
|
112
|
+
|
113
|
+
(BKR-5) added a default log_prefix of the hostfile name, and the --log-p...
|
114
|
+
```
|
115
|
+
* Wrap tagging attempt in a begin/rescue/end block (66f4629f)
|
116
|
+
|
117
|
+
* Merge pull request #745 from puppetlabs/fix_vagrant_insecure (77c14f7b)
|
118
|
+
|
119
|
+
|
120
|
+
```
|
121
|
+
Merge pull request #745 from puppetlabs/fix_vagrant_insecure
|
122
|
+
|
123
|
+
(BKR-148) Stop vagrant from generating ssh key
|
124
|
+
```
|
125
|
+
* Merge pull request #749 from kevpl/bkr79_deprecate_hostproperties (c7a6ef03)
|
126
|
+
|
127
|
+
|
128
|
+
```
|
129
|
+
Merge pull request #749 from kevpl/bkr79_deprecate_hostproperties
|
130
|
+
|
131
|
+
(BKR-79) added deprecated warning to host defaults
|
132
|
+
```
|
133
|
+
* Merge pull request #751 from petems/MAINT-fix-non-cygwin-root-enable (47a942ae)
|
134
|
+
|
135
|
+
|
136
|
+
```
|
137
|
+
Merge pull request #751 from petems/MAINT-fix-non-cygwin-root-enable
|
138
|
+
|
139
|
+
(MAINT) Fix enable root login on non-cygwin
|
140
|
+
```
|
141
|
+
* (BKR-155) Add simple tagging to vmpooler hosts (90d4e088)
|
142
|
+
|
143
|
+
* (BKR-151) periodic failure to restart ssh on windows (beec5281)
|
144
|
+
|
145
|
+
|
146
|
+
```
|
147
|
+
(BKR-151) periodic failure to restart ssh on windows
|
148
|
+
|
149
|
+
- wrap ssh stop/start in a repeat loop
|
150
|
+
```
|
151
|
+
* (BKR-77) breakup dsl/helpers and dsl/install_utils (73931bf3)
|
152
|
+
|
153
|
+
|
154
|
+
```
|
155
|
+
(BKR-77) breakup dsl/helpers and dsl/install_utils
|
156
|
+
|
157
|
+
- dsl/helpers.rb and dsl/install_utils.rb have grown too large and no
|
158
|
+
longer make sense as discreet units
|
159
|
+
- divide install_utils into modules with methods associated with
|
160
|
+
different applications (pe, puppet, modules)
|
161
|
+
- divide helpers into modules with methods exercising different areas of
|
162
|
+
functionality (facter, hiera, host, puppet, web, trapperkeeper)
|
163
|
+
- update spec testing stucture to reflect new install_utils/helpers
|
164
|
+
stucture
|
165
|
+
```
|
166
|
+
* (MAINT) Changes default to show warning (e17321ec)
|
167
|
+
|
168
|
+
|
169
|
+
```
|
170
|
+
(MAINT) Changes default to show warning
|
171
|
+
|
172
|
+
This means that we won't try to run the sed command on Windows boxes if they have false for cygwin
|
173
|
+
```
|
174
|
+
* (MAINT) Adds spec for `enable_root_login` method (1f666bef)
|
175
|
+
|
176
|
+
* (BKR-79) added deprecated warning to host defaults (f654a4f0)
|
177
|
+
|
178
|
+
* (BRK-148) Stop vagrant from generating ssh key (d7470ed9)
|
179
|
+
|
180
|
+
|
181
|
+
```
|
182
|
+
(BRK-148) Stop vagrant from generating ssh key
|
183
|
+
|
184
|
+
Hashicorp added new behavior that generates a new SSH key
|
185
|
+
when generating a box, and will remove any existing "insecure"
|
186
|
+
key found on a box. See https://github.com/mitchellh/vagrant/pull/4707
|
187
|
+
|
188
|
+
This has the unfortunate side effect of breaking the automation
|
189
|
+
used in Beaker to setup SSH keys, since it relied on the default
|
190
|
+
"insecure" vagrant keys being used. Current workaround is to disable
|
191
|
+
the new Vagrant behavior with a configuration option.
|
192
|
+
```
|
193
|
+
* (BKR-5) added a default log_prefix of the hostfile name, and the --log-prefix CLI option (6ce6cbd4)
|
194
|
+
|
195
|
+
### <a name = "beaker2.7.1">beaker2.7.1 - 19 Mar, 2015 (45b2bf10)
|
196
|
+
|
197
|
+
* (HISTORY) update beaker history for gem release 2.7.1 (45b2bf10)
|
79
198
|
|
80
199
|
* (GEM) update beaker version to 2.7.1 (2bf87b79)
|
81
200
|
|
data/lib/beaker/dsl.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
[ 'install_utils', 'roles', 'outcomes', 'assertions', 'patterns',
|
2
|
-
'structure', 'helpers', '
|
2
|
+
'structure', 'helpers', 'wrappers' ].each do |lib|
|
3
3
|
require "beaker/dsl/#{lib}"
|
4
4
|
end
|
5
5
|
|
@@ -69,6 +69,7 @@ module Beaker
|
|
69
69
|
# end
|
70
70
|
# end
|
71
71
|
#
|
72
|
+
#@api dsl
|
72
73
|
module DSL
|
73
74
|
include Beaker::DSL::Roles
|
74
75
|
include Beaker::DSL::Outcomes
|
@@ -76,7 +77,6 @@ module Beaker
|
|
76
77
|
include Beaker::DSL::Assertions
|
77
78
|
include Beaker::DSL::Wrappers
|
78
79
|
include Beaker::DSL::Helpers
|
79
|
-
include Beaker::DSL::EZBakeUtils
|
80
80
|
include Beaker::DSL::InstallUtils
|
81
81
|
include Beaker::DSL::Patterns
|
82
82
|
end
|
data/lib/beaker/dsl/helpers.rb
CHANGED
@@ -1,19 +1,14 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
|
3
|
-
require
|
4
|
-
|
5
|
-
require 'beaker/dsl/outcomes'
|
6
|
-
require 'beaker/options'
|
7
|
-
require 'hocon'
|
8
|
-
require 'hocon/config_error'
|
2
|
+
[ 'facter', 'hiera', 'host', 'puppet', 'tk', 'web' ].each do |lib|
|
3
|
+
require "beaker/dsl/helpers/#{lib}_helpers"
|
4
|
+
end
|
9
5
|
|
10
6
|
module Beaker
|
11
7
|
module DSL
|
12
|
-
|
13
|
-
# to
|
14
|
-
# and
|
15
|
-
|
16
|
-
#
|
8
|
+
|
9
|
+
# Contains methods to help you manage and configure your SUTs and configure and interact with puppet, facter
|
10
|
+
# and hiera.
|
11
|
+
|
17
12
|
# To mix this is into a class you need the following:
|
18
13
|
# * a method *hosts* that yields any hosts implementing
|
19
14
|
# {Beaker::Host}'s interface to act upon.
|
@@ -25,1424 +20,13 @@ module Beaker
|
|
25
20
|
# * the module {Beaker::DSL::Wrappers} the provides convenience methods for {Beaker::DSL::Command} creation
|
26
21
|
#
|
27
22
|
#
|
28
|
-
# @api dsl
|
29
23
|
module Helpers
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
# acceptable. An error will be thrown if the exit code does not
|
37
|
-
# match one of the values in this list.
|
38
|
-
# @option opts [Hash{String=>String}] :environment ({}) These will be
|
39
|
-
# treated as extra environment variables that should be set before
|
40
|
-
# running the command.
|
41
|
-
#
|
42
|
-
|
43
|
-
# The primary method for executing commands *on* some set of hosts.
|
44
|
-
#
|
45
|
-
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
46
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
47
|
-
# @param [String, Command] command The command to execute on *host*.
|
48
|
-
# @param [Proc] block Additional actions or assertions.
|
49
|
-
# @!macro common_opts
|
50
|
-
#
|
51
|
-
# @example Most basic usage
|
52
|
-
# on hosts, 'ls /tmp'
|
53
|
-
#
|
54
|
-
# @example Allowing additional exit codes to pass
|
55
|
-
# on agents, 'puppet agent -t', :acceptable_exit_codes => [0,2]
|
56
|
-
#
|
57
|
-
# @example Using the returned result for any kind of checking
|
58
|
-
# if on(host, 'ls -la ~').stdout =~ /\.bin/
|
59
|
-
# ...do some action...
|
60
|
-
# end
|
61
|
-
#
|
62
|
-
# @example Using TestCase helpers from within a test.
|
63
|
-
# agents.each do |agent|
|
64
|
-
# on agent, 'cat /etc/puppet/puppet.conf' do
|
65
|
-
# assert_match stdout, /server = #{master}/, 'WTF Mate'
|
66
|
-
# end
|
67
|
-
# end
|
68
|
-
#
|
69
|
-
# @example Using a role (defined in a String) to identify the host
|
70
|
-
# on "master", "echo hello"
|
71
|
-
#
|
72
|
-
# @example Using a role (defined in a Symbol) to identify the host
|
73
|
-
# on :dashboard, "echo hello"
|
74
|
-
#
|
75
|
-
# @return [Result] An object representing the outcome of *command*.
|
76
|
-
# @raise [FailTest] Raises an exception if *command* obviously fails.
|
77
|
-
def on(host, command, opts = {}, &block)
|
78
|
-
block_on host do | host |
|
79
|
-
cur_command = command
|
80
|
-
if command.is_a? Command
|
81
|
-
cur_command = command.cmd_line(host)
|
82
|
-
end
|
83
|
-
cmd_opts = {}
|
84
|
-
#add any additional environment variables to the command
|
85
|
-
if opts[:environment]
|
86
|
-
cmd_opts['ENV'] = opts[:environment]
|
87
|
-
end
|
88
|
-
@result = host.exec(Command.new(cur_command.to_s, [], cmd_opts), opts)
|
89
|
-
|
90
|
-
# Also, let additional checking be performed by the caller.
|
91
|
-
if block_given?
|
92
|
-
case block.arity
|
93
|
-
#block with arity of 0, just hand back yourself
|
94
|
-
when 0
|
95
|
-
yield self
|
96
|
-
#block with arity of 1 or greater, hand back the result object
|
97
|
-
else
|
98
|
-
yield @result
|
99
|
-
end
|
100
|
-
end
|
101
|
-
@result
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# The method for executing commands on the default host
|
106
|
-
#
|
107
|
-
# @param [String, Command] command The command to execute on *host*.
|
108
|
-
# @param [Proc] block Additional actions or assertions.
|
109
|
-
# @!macro common_opts
|
110
|
-
#
|
111
|
-
# @example Most basic usage
|
112
|
-
# shell 'ls /tmp'
|
113
|
-
#
|
114
|
-
# @example Allowing additional exit codes to pass
|
115
|
-
# shell 'puppet agent -t', :acceptable_exit_codes => [0,2]
|
116
|
-
#
|
117
|
-
# @example Using the returned result for any kind of checking
|
118
|
-
# if shell('ls -la ~').stdout =~ /\.bin/
|
119
|
-
# ...do some action...
|
120
|
-
# end
|
121
|
-
#
|
122
|
-
# @example Using TestCase helpers from within a test.
|
123
|
-
# agents.each do |agent|
|
124
|
-
# shell('cat /etc/puppet/puppet.conf') do |result|
|
125
|
-
# assert_match result.stdout, /server = #{master}/, 'WTF Mate'
|
126
|
-
# end
|
127
|
-
# end
|
128
|
-
#
|
129
|
-
# @return [Result] An object representing the outcome of *command*.
|
130
|
-
# @raise [FailTest] Raises an exception if *command* obviously fails.
|
131
|
-
def shell(command, opts = {}, &block)
|
132
|
-
on(default, command, opts, &block)
|
133
|
-
end
|
134
|
-
|
135
|
-
# @deprecated
|
136
|
-
# An proxy for the last {Beaker::Result#stdout} returned by
|
137
|
-
# a method that makes remote calls. Use the {Beaker::Result}
|
138
|
-
# object returned by the method directly instead. For Usage see
|
139
|
-
# {Beaker::Result}.
|
140
|
-
def stdout
|
141
|
-
return nil if @result.nil?
|
142
|
-
@result.stdout
|
143
|
-
end
|
144
|
-
|
145
|
-
# @deprecated
|
146
|
-
# An proxy for the last {Beaker::Result#stderr} returned by
|
147
|
-
# a method that makes remote calls. Use the {Beaker::Result}
|
148
|
-
# object returned by the method directly instead. For Usage see
|
149
|
-
# {Beaker::Result}.
|
150
|
-
def stderr
|
151
|
-
return nil if @result.nil?
|
152
|
-
@result.stderr
|
153
|
-
end
|
154
|
-
|
155
|
-
# @deprecated
|
156
|
-
# An proxy for the last {Beaker::Result#exit_code} returned by
|
157
|
-
# a method that makes remote calls. Use the {Beaker::Result}
|
158
|
-
# object returned by the method directly instead. For Usage see
|
159
|
-
# {Beaker::Result}.
|
160
|
-
def exit_code
|
161
|
-
return nil if @result.nil?
|
162
|
-
@result.exit_code
|
163
|
-
end
|
164
|
-
|
165
|
-
# Move a file from a remote to a local path
|
166
|
-
# @note If using {Beaker::Host} for the hosts *scp* is not
|
167
|
-
# required on the system as it uses Ruby's net/scp library. The
|
168
|
-
# net-scp gem however is required (and specified in the gemspec).
|
169
|
-
#
|
170
|
-
# @param [Host, #do_scp_from] host One or more hosts (or some object
|
171
|
-
# that responds like
|
172
|
-
# {Beaker::Host#do_scp_from}.
|
173
|
-
# @param [String] from_path A remote path to a file.
|
174
|
-
# @param [String] to_path A local path to copy *from_path* to.
|
175
|
-
# @!macro common_opts
|
176
|
-
#
|
177
|
-
# @return [Result] Returns the result of the SCP operation
|
178
|
-
def scp_from host, from_path, to_path, opts = {}
|
179
|
-
block_on host do | host |
|
180
|
-
@result = host.do_scp_from(from_path, to_path, opts)
|
181
|
-
@result.log logger
|
182
|
-
@result
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# Move a local file to a remote host using scp
|
187
|
-
# @note If using {Beaker::Host} for the hosts *scp* is not
|
188
|
-
# required on the system as it uses Ruby's net/scp library. The
|
189
|
-
# net-scp gem however is required (and specified in the gemspec.
|
190
|
-
# When using SCP with Windows it will now auto expand path when
|
191
|
-
# using `cygpath instead of failing or requiring full path
|
192
|
-
#
|
193
|
-
# @param [Host, #do_scp_to] host One or more hosts (or some object
|
194
|
-
# that responds like
|
195
|
-
# {Beaker::Host#do_scp_to}.
|
196
|
-
# @param [String] from_path A local path to a file.
|
197
|
-
# @param [String] to_path A remote path to copy *from_path* to.
|
198
|
-
# @!macro common_opts
|
199
|
-
#
|
200
|
-
# @return [Result] Returns the result of the SCP operation
|
201
|
-
def scp_to host, from_path, to_path, opts = {}
|
202
|
-
block_on host do | host |
|
203
|
-
if host['platform'] =~ /windows/ && to_path.match('`cygpath')
|
204
|
-
result = on host, "echo #{to_path}"
|
205
|
-
to_path = result.raw_output.chomp
|
206
|
-
end
|
207
|
-
@result = host.do_scp_to(from_path, to_path, opts)
|
208
|
-
@result.log logger
|
209
|
-
@result
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
# Move a local file or directory to a remote host using rsync
|
214
|
-
# @note rsync is required on the local host.
|
215
|
-
#
|
216
|
-
# @param [Host, #do_scp_to] host A host object that responds like
|
217
|
-
# {Beaker::Host}.
|
218
|
-
# @param [String] from_path A local path to a file or directory.
|
219
|
-
# @param [String] to_path A remote path to copy *from_path* to.
|
220
|
-
# @!macro common_opts
|
221
|
-
#
|
222
|
-
# @return [Result] Returns the result of the rsync operation
|
223
|
-
def rsync_to host, from_path, to_path, opts = {}
|
224
|
-
block_on host do | host |
|
225
|
-
if host['platform'] =~ /windows/ && to_path.match('`cygpath')
|
226
|
-
result = host.echo "#{to_path}"
|
227
|
-
to_path = result.raw_output.chomp
|
228
|
-
end
|
229
|
-
@result = host.do_rsync_to(from_path, to_path, opts)
|
230
|
-
@result
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
# Deploy packaging configurations generated by
|
235
|
-
# https://github.com/puppetlabs/packaging to a host.
|
236
|
-
#
|
237
|
-
# @note To ensure the repo configs are available for deployment,
|
238
|
-
# you should run `rake pl:jenkins:deb_repo_configs` and
|
239
|
-
# `rake pl:jenkins:rpm_repo_configs` on your project checkout
|
240
|
-
#
|
241
|
-
# @param [Host] host
|
242
|
-
# @param [String] path The path to the generated repository config
|
243
|
-
# files. ex: /myproject/pkg/repo_configs
|
244
|
-
# @param [String] name A human-readable name for the repository
|
245
|
-
# @param [String] version The version of the project, as used by the
|
246
|
-
# packaging tools. This can be determined with
|
247
|
-
# `rake pl:print_build_params` from the packaging
|
248
|
-
# repo.
|
249
|
-
def deploy_package_repo host, path, name, version
|
250
|
-
host.deploy_package_repo path, name, version
|
251
|
-
end
|
252
|
-
|
253
|
-
# Create a remote file out of a string
|
254
|
-
# @note This method uses Tempfile in Ruby's STDLIB as well as {#scp_to}.
|
255
|
-
#
|
256
|
-
# @param [Host, #do_scp_to] hosts One or more hosts (or some object
|
257
|
-
# that responds like
|
258
|
-
# {Beaker::Host#do_scp_from}.
|
259
|
-
# @param [String] file_path A remote path to place *file_content* at.
|
260
|
-
# @param [String] file_content The contents of the file to be placed.
|
261
|
-
# @!macro common_opts
|
262
|
-
# @option opts [String] :protocol Name of the underlying transfer method.
|
263
|
-
# Valid options are 'scp' or 'rsync'.
|
264
|
-
#
|
265
|
-
# @return [Result] Returns the result of the underlying SCP operation.
|
266
|
-
def create_remote_file(hosts, file_path, file_content, opts = {})
|
267
|
-
Tempfile.open 'beaker' do |tempfile|
|
268
|
-
File.open(tempfile.path, 'w') {|file| file.puts file_content }
|
269
|
-
|
270
|
-
opts[:protocol] ||= 'scp'
|
271
|
-
case opts[:protocol]
|
272
|
-
when 'scp'
|
273
|
-
scp_to hosts, tempfile.path, file_path, opts
|
274
|
-
when 'rsync'
|
275
|
-
rsync_to hosts, tempfile.path, file_path, opts
|
276
|
-
else
|
277
|
-
logger.debug "Unsupported transfer protocol, returning nil"
|
278
|
-
nil
|
279
|
-
end
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
# Create a temp directory on remote host owned by specified user.
|
284
|
-
#
|
285
|
-
# @param [Host] host A single remote host on which to create and adjust
|
286
|
-
# the ownership of a temp directory.
|
287
|
-
# @param [String] name A remote path prefix for the new temp
|
288
|
-
# directory. Default value is '/tmp/beaker'
|
289
|
-
# @param [String] user The name of user that should own the temp
|
290
|
-
# directory. If no username is specified, use `puppet master
|
291
|
-
# --configprint user` to obtain username from master. Raise RuntimeError
|
292
|
-
# if this puppet command returns a non-zero exit code.
|
293
|
-
#
|
294
|
-
# @return [String] Returns the name of the newly-created file.
|
295
|
-
def create_tmpdir_for_user(host, name='/tmp/beaker', user=nil)
|
296
|
-
if not user
|
297
|
-
result = on host, puppet("master --configprint user")
|
298
|
-
if not result.exit_code == 0
|
299
|
-
raise "`puppet master --configprint` failed, check that puppet is installed on #{host} or explicitly pass in a user name."
|
300
|
-
end
|
301
|
-
user = result.stdout.strip
|
302
|
-
end
|
303
|
-
|
304
|
-
if not on(host, "getent passwd #{user}").exit_code == 0
|
305
|
-
raise "User #{user} does not exist on #{host}."
|
306
|
-
end
|
307
|
-
|
308
|
-
if defined? host.tmpdir
|
309
|
-
dir = host.tmpdir(name)
|
310
|
-
on host, "chown #{user}:#{user} #{dir}"
|
311
|
-
return dir
|
312
|
-
else
|
313
|
-
raise "Host platform not supported by `create_tmpdir_for_user`."
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
# Move a local script to a remote host and execute it
|
318
|
-
# @note this relies on {#on} and {#scp_to}
|
319
|
-
#
|
320
|
-
# @param [Host, #do_scp_to] host One or more hosts (or some object
|
321
|
-
# that responds like
|
322
|
-
# {Beaker::Host#do_scp_from}.
|
323
|
-
# @param [String] script A local path to find an executable script at.
|
324
|
-
# @!macro common_opts
|
325
|
-
# @param [Proc] block Additional tests to run after script has executed
|
326
|
-
#
|
327
|
-
# @return [Result] Returns the result of the underlying SCP operation.
|
328
|
-
def run_script_on(host, script, opts = {}, &block)
|
329
|
-
# this is unsafe as it uses the File::SEPARATOR will be set to that
|
330
|
-
# of the coordinator node. This works for us because we use cygwin
|
331
|
-
# which will properly convert the paths. Otherwise this would not
|
332
|
-
# work for running tests on a windows machine when the coordinator
|
333
|
-
# that the harness is running on is *nix. We should use
|
334
|
-
# {Beaker::Host#temp_path} instead. TODO
|
335
|
-
remote_path = File.join("", "tmp", File.basename(script))
|
336
|
-
|
337
|
-
scp_to host, script, remote_path
|
338
|
-
on host, remote_path, opts, &block
|
339
|
-
end
|
340
|
-
|
341
|
-
# Move a local script to default host and execute it
|
342
|
-
# @see #run_script_on
|
343
|
-
def run_script(script, opts = {}, &block)
|
344
|
-
run_script_on(default, script, opts, &block)
|
345
|
-
end
|
346
|
-
|
347
|
-
# Limit the hosts a test case is run against
|
348
|
-
# @note This will modify the {Beaker::TestCase#hosts} member
|
349
|
-
# in place unless an array of hosts is passed into it and
|
350
|
-
# {Beaker::TestCase#logger} yielding an object that responds
|
351
|
-
# like {Beaker::Logger#warn}, as well as
|
352
|
-
# {Beaker::DSL::Outcomes#skip_test}, and optionally
|
353
|
-
# {Beaker::TestCase#hosts}.
|
354
|
-
#
|
355
|
-
# @param [Symbol] type The type of confinement to do. Valid parameters
|
356
|
-
# are *:to* to confine the hosts to only those that
|
357
|
-
# match *criteria* or *:except* to confine the test
|
358
|
-
# case to only those hosts that do not match
|
359
|
-
# criteria.
|
360
|
-
# @param [Hash{Symbol,String=>String,Regexp,Array<String,Regexp>}]
|
361
|
-
# criteria Specify the criteria with which a host should be
|
362
|
-
# considered for inclusion or exclusion. The key is any attribute
|
363
|
-
# of the host that will be yielded by {Beaker::Host#[]}.
|
364
|
-
# The value can be any string/regex or array of strings/regexp.
|
365
|
-
# The values are compared using [Enumerable#any?] so that if one
|
366
|
-
# value of an array matches the host is considered a match for that
|
367
|
-
# criteria.
|
368
|
-
# @param [Array<Host>] host_array This creatively named parameter is
|
369
|
-
# an optional array of hosts to confine to. If not passed in, this
|
370
|
-
# method will modify {Beaker::TestCase#hosts} in place.
|
371
|
-
# @param [Proc] block Addition checks to determine suitability of hosts
|
372
|
-
# for confinement. Each host that is still valid after checking
|
373
|
-
# *criteria* is then passed in turn into this block. The block
|
374
|
-
# should return true if the host matches this additional criteria.
|
375
|
-
#
|
376
|
-
# @example Basic usage to confine to debian OSes.
|
377
|
-
# confine :to, :platform => 'debian'
|
378
|
-
#
|
379
|
-
# @example Confining to anything but Windows and Solaris
|
380
|
-
# confine :except, :platform => ['windows', 'solaris']
|
381
|
-
#
|
382
|
-
# @example Using additional block to confine to Solaris global zone.
|
383
|
-
# confine :to, :platform => 'solaris' do |solaris|
|
384
|
-
# on( solaris, 'zonename' ) =~ /global/
|
385
|
-
# end
|
386
|
-
#
|
387
|
-
# @return [Array<Host>] Returns an array of hosts that are still valid
|
388
|
-
# targets for this tests case.
|
389
|
-
# @raise [SkipTest] Raises skip test if there are no valid hosts for
|
390
|
-
# this test case after confinement.
|
391
|
-
def confine(type, criteria, host_array = nil, &block)
|
392
|
-
hosts_to_modify = host_array || hosts
|
393
|
-
case type
|
394
|
-
when :except
|
395
|
-
hosts_to_modify = hosts_to_modify - select_hosts(criteria, hosts_to_modify, &block)
|
396
|
-
when :to
|
397
|
-
hosts_to_modify = select_hosts(criteria, hosts_to_modify, &block)
|
398
|
-
else
|
399
|
-
raise "Unknown option #{type}"
|
400
|
-
end
|
401
|
-
if hosts_to_modify.empty?
|
402
|
-
logger.warn "No suitable hosts with: #{criteria.inspect}"
|
403
|
-
skip_test 'No suitable hosts found'
|
404
|
-
end
|
405
|
-
self.hosts = hosts_to_modify
|
406
|
-
hosts_to_modify
|
407
|
-
end
|
408
|
-
|
409
|
-
# Ensures that host restrictions as specifid by type, criteria and
|
410
|
-
# host_array are confined to activity within the passed block.
|
411
|
-
# TestCase#hosts is reset after block has executed.
|
412
|
-
#
|
413
|
-
# @see #confine
|
414
|
-
def confine_block(type, criteria, host_array = nil, &block)
|
415
|
-
begin
|
416
|
-
original_hosts = self.hosts.dup
|
417
|
-
confine(type, criteria, host_array)
|
418
|
-
|
419
|
-
yield
|
420
|
-
|
421
|
-
ensure
|
422
|
-
self.hosts = original_hosts
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
#Return a set of hosts that meet the given criteria
|
427
|
-
# @param [Hash{Symbol,String=>String,Regexp,Array<String,Regexp>}]
|
428
|
-
# criteria Specify the criteria with which a host should be
|
429
|
-
# considered for inclusion. The key is any attribute
|
430
|
-
# of the host that will be yielded by {Beaker::Host#[]}.
|
431
|
-
# The value can be any string/regex or array of strings/regexp.
|
432
|
-
# The values are compared using [Enumerable#any?] so that if one
|
433
|
-
# value of an array matches the host is considered a match for that
|
434
|
-
# criteria.
|
435
|
-
# @param [Array<Host>] host_array This creatively named parameter is
|
436
|
-
# an optional array of hosts to confine to. If not passed in, this
|
437
|
-
# method will modify {Beaker::TestCase#hosts} in place.
|
438
|
-
# @param [Proc] block Addition checks to determine suitability of hosts
|
439
|
-
# for selection. Each host that is still valid after checking
|
440
|
-
# *criteria* is then passed in turn into this block. The block
|
441
|
-
# should return true if the host matches this additional criteria.
|
442
|
-
#
|
443
|
-
# @return [Array<Host>] Returns an array of hosts that meet the provided criteria
|
444
|
-
def select_hosts(criteria, host_array = nil, &block)
|
445
|
-
hosts_to_select_from = host_array || hosts
|
446
|
-
criteria.each_pair do |property, value|
|
447
|
-
hosts_to_select_from = hosts_to_select_from.select do |host|
|
448
|
-
inspect_host host, property, value
|
449
|
-
end
|
450
|
-
end
|
451
|
-
if block_given?
|
452
|
-
hosts_to_select_from = hosts_to_select_from.select do |host|
|
453
|
-
yield host
|
454
|
-
end
|
455
|
-
end
|
456
|
-
hosts_to_select_from
|
457
|
-
end
|
458
|
-
|
459
|
-
# Return the name of the puppet user.
|
460
|
-
#
|
461
|
-
# @param [Host] host One object that acts like a Beaker::Host
|
462
|
-
#
|
463
|
-
# @note This method assumes puppet is installed on the host.
|
464
|
-
#
|
465
|
-
def puppet_user(host)
|
466
|
-
return host.puppet('master')['user']
|
467
|
-
end
|
468
|
-
|
469
|
-
# Return the name of the puppet group.
|
470
|
-
#
|
471
|
-
# @param [Host] host One object that acts like a Beaker::Host
|
472
|
-
#
|
473
|
-
# @note This method assumes puppet is installed on the host.
|
474
|
-
#
|
475
|
-
def puppet_group(host)
|
476
|
-
return host.puppet('master')['group']
|
477
|
-
end
|
478
|
-
|
479
|
-
# @!visibility private
|
480
|
-
def inspect_host(host, property, one_or_more_values)
|
481
|
-
values = Array(one_or_more_values)
|
482
|
-
return values.any? do |value|
|
483
|
-
true_false = false
|
484
|
-
case value
|
485
|
-
when String
|
486
|
-
true_false = host[property.to_s].include? value
|
487
|
-
when Regexp
|
488
|
-
true_false = host[property.to_s] =~ value
|
489
|
-
end
|
490
|
-
true_false
|
491
|
-
end
|
492
|
-
end
|
493
|
-
|
494
|
-
|
495
|
-
# Test Puppet running in a certain run mode with specific options.
|
496
|
-
# This ensures the following steps are performed:
|
497
|
-
# 1. The pre-test Puppet configuration is backed up
|
498
|
-
# 2. A new Puppet configuraton file is layed down
|
499
|
-
# 3. Puppet is started or restarted in the specified run mode
|
500
|
-
# 4. Ensure Puppet has started correctly
|
501
|
-
# 5. Further tests are yielded to
|
502
|
-
# 6. Revert Puppet to the pre-test state
|
503
|
-
# 7. Testing artifacts are saved in a folder named for the test
|
504
|
-
#
|
505
|
-
# @param [Host] host One object that act like Host
|
506
|
-
#
|
507
|
-
# @param [Hash{Symbol=>String}] conf_opts Represents puppet settings.
|
508
|
-
# Sections of the puppet.conf may be
|
509
|
-
# specified, if no section is specified the
|
510
|
-
# a puppet.conf file will be written with the
|
511
|
-
# options put in a section named after [mode]
|
512
|
-
# @option conf_opts [String] :__commandline_args__ A special setting for
|
513
|
-
# command_line arguments such as --debug or
|
514
|
-
# --logdest, which cannot be set in
|
515
|
-
# puppet.conf. For example:
|
516
|
-
#
|
517
|
-
# :__commandline_args__ => '--logdest /tmp/a.log'
|
518
|
-
#
|
519
|
-
# These will only be applied when starting a FOSS
|
520
|
-
# master, as a pe master is just bounced.
|
521
|
-
# @option conf_opts [Hash] :__service_args__ A special setting of options
|
522
|
-
# for controlling how the puppet master service is
|
523
|
-
# handled. The only setting currently is
|
524
|
-
# :bypass_service_script, which if set true will
|
525
|
-
# force stopping and starting a webrick master
|
526
|
-
# using the start_puppet_from_source_* methods,
|
527
|
-
# even if it seems the host has passenger.
|
528
|
-
# This is needed in FOSS tests to initialize
|
529
|
-
# SSL.
|
530
|
-
# @param [File] testdir The temporary directory which will hold backup
|
531
|
-
# configuration, and other test artifacts.
|
532
|
-
#
|
533
|
-
# @param [Block] block The point of this method, yields so
|
534
|
-
# tests may be ran. After the block is finished
|
535
|
-
# puppet will revert to a previous state.
|
536
|
-
#
|
537
|
-
# @example A simple use case to ensure a master is running
|
538
|
-
# with_puppet_running_on( master ) do
|
539
|
-
# ...tests that require a master...
|
540
|
-
# end
|
541
|
-
#
|
542
|
-
# @example Fully utilizing the possiblities of config options
|
543
|
-
# with_puppet_running_on( master,
|
544
|
-
# :main => {:logdest => '/var/blah'},
|
545
|
-
# :master => {:masterlog => '/elswhere'},
|
546
|
-
# :agent => {:server => 'localhost'} ) do
|
547
|
-
#
|
548
|
-
# ...tests to be ran...
|
549
|
-
# end
|
550
|
-
#
|
551
|
-
# @api dsl
|
552
|
-
def with_puppet_running_on host, conf_opts, testdir = host.tmpdir(File.basename(@path)), &block
|
553
|
-
raise(ArgumentError, "with_puppet_running_on's conf_opts must be a Hash. You provided a #{conf_opts.class}: '#{conf_opts}'") if !conf_opts.kind_of?(Hash)
|
554
|
-
cmdline_args = conf_opts[:__commandline_args__]
|
555
|
-
service_args = conf_opts[:__service_args__] || {}
|
556
|
-
conf_opts = conf_opts.reject { |k,v| [:__commandline_args__, :__service_args__].include?(k) }
|
557
|
-
|
558
|
-
curl_retries = host['master-start-curl-retries'] || options['master-start-curl-retries']
|
559
|
-
logger.debug "Setting curl retries to #{curl_retries}"
|
560
|
-
|
561
|
-
if options[:is_puppetserver]
|
562
|
-
confdir = host.puppet('master')['confdir']
|
563
|
-
vardir = host.puppet('master')['vardir']
|
564
|
-
|
565
|
-
if cmdline_args
|
566
|
-
split_args = cmdline_args.split()
|
567
|
-
|
568
|
-
split_args.each do |arg|
|
569
|
-
case arg
|
570
|
-
when /--confdir=(.*)/
|
571
|
-
confdir = $1
|
572
|
-
when /--vardir=(.*)/
|
573
|
-
vardir = $1
|
574
|
-
end
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
puppetserver_opts = { "jruby-puppet" => {
|
579
|
-
"master-conf-dir" => confdir,
|
580
|
-
"master-var-dir" => vardir,
|
581
|
-
}}
|
582
|
-
|
583
|
-
puppetserver_conf = File.join("#{host['puppetserver-confdir']}", "puppetserver.conf")
|
584
|
-
modify_tk_config(host, puppetserver_conf, puppetserver_opts)
|
585
|
-
end
|
586
|
-
|
587
|
-
begin
|
588
|
-
backup_file = backup_the_file(host, host.puppet('master')['confdir'], testdir, 'puppet.conf')
|
589
|
-
lay_down_new_puppet_conf host, conf_opts, testdir
|
590
|
-
|
591
|
-
if host.use_service_scripts? && !service_args[:bypass_service_script]
|
592
|
-
bounce_service( host, host['puppetservice'], curl_retries )
|
593
|
-
else
|
594
|
-
puppet_master_started = start_puppet_from_source_on!( host, cmdline_args )
|
595
|
-
end
|
596
|
-
|
597
|
-
yield self if block_given?
|
598
|
-
|
599
|
-
rescue Beaker::DSL::Assertions, Minitest::Assertion => early_assertion
|
600
|
-
fail_test(early_assertion)
|
601
|
-
rescue Exception => early_exception
|
602
|
-
original_exception = RuntimeError.new("PuppetAcceptance::DSL::Helpers.with_puppet_running_on failed (check backtrace for location) because: #{early_exception}\n#{early_exception.backtrace.join("\n")}\n")
|
603
|
-
raise(original_exception)
|
604
|
-
|
605
|
-
ensure
|
606
|
-
begin
|
607
|
-
|
608
|
-
if host.use_service_scripts? && !service_args[:bypass_service_script]
|
609
|
-
restore_puppet_conf_from_backup( host, backup_file )
|
610
|
-
bounce_service( host, host['puppetservice'], curl_retries )
|
611
|
-
else
|
612
|
-
if puppet_master_started
|
613
|
-
stop_puppet_from_source_on( host )
|
614
|
-
else
|
615
|
-
dump_puppet_log(host)
|
616
|
-
end
|
617
|
-
restore_puppet_conf_from_backup( host, backup_file )
|
618
|
-
end
|
619
|
-
|
620
|
-
rescue Exception => teardown_exception
|
621
|
-
begin
|
622
|
-
if !host.is_pe?
|
623
|
-
dump_puppet_log(host)
|
624
|
-
end
|
625
|
-
rescue Exception => dumping_exception
|
626
|
-
logger.error("Raised during attempt to dump puppet logs: #{dumping_exception}")
|
627
|
-
end
|
628
|
-
|
629
|
-
if original_exception
|
630
|
-
logger.error("Raised during attempt to teardown with_puppet_running_on: #{teardown_exception}\n---\n")
|
631
|
-
raise original_exception
|
632
|
-
else
|
633
|
-
raise teardown_exception
|
634
|
-
end
|
635
|
-
end
|
636
|
-
end
|
637
|
-
end
|
638
|
-
|
639
|
-
# Test Puppet running in a certain run mode with specific options,
|
640
|
-
# on the default host
|
641
|
-
# @api dsl
|
642
|
-
# @see #with_puppet_running_on
|
643
|
-
def with_puppet_running conf_opts, testdir = host.tmpdir(File.basename(@path)), &block
|
644
|
-
with_puppet_running_on(default, conf_opts, testdir, &block)
|
645
|
-
end
|
646
|
-
|
647
|
-
# @!visibility private
|
648
|
-
def restore_puppet_conf_from_backup( host, backup_file )
|
649
|
-
puppet_conf = host.puppet('master')['config']
|
650
|
-
|
651
|
-
if backup_file
|
652
|
-
host.exec( Command.new( "if [ -f '#{backup_file}' ]; then " +
|
653
|
-
"cat '#{backup_file}' > " +
|
654
|
-
"'#{puppet_conf}'; " +
|
655
|
-
"rm -f '#{backup_file}'; " +
|
656
|
-
"fi" ) )
|
657
|
-
else
|
658
|
-
host.exec( Command.new( "rm -f '#{puppet_conf}'" ))
|
659
|
-
end
|
660
|
-
|
661
|
-
end
|
662
|
-
|
663
|
-
# Back up the given file in the current_dir to the new_dir
|
664
|
-
#
|
665
|
-
# @!visibility private
|
666
|
-
#
|
667
|
-
# @param host [Beaker::Host] The target host
|
668
|
-
# @param current_dir [String] The directory containing the file to back up
|
669
|
-
# @param new_dir [String] The directory to copy the file to
|
670
|
-
# @param filename [String] The file to back up. Defaults to 'puppet.conf'
|
671
|
-
#
|
672
|
-
# @return [String, nil] The path to the file if the file exists, nil if it
|
673
|
-
# doesn't exist.
|
674
|
-
def backup_the_file host, current_dir, new_dir, filename = 'puppet.conf'
|
675
|
-
|
676
|
-
old_location = current_dir + '/' + filename
|
677
|
-
new_location = new_dir + '/' + filename + '.bak'
|
678
|
-
|
679
|
-
if host.file_exist? old_location
|
680
|
-
host.exec( Command.new( "cp #{old_location} #{new_location}" ) )
|
681
|
-
return new_location
|
682
|
-
else
|
683
|
-
logger.warn "Could not backup file '#{old_location}': no such file"
|
684
|
-
nil
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
|
-
# @!visibility private
|
689
|
-
def start_puppet_from_source_on! host, args = ''
|
690
|
-
host.exec( puppet( 'master', args ) )
|
691
|
-
|
692
|
-
logger.debug 'Waiting for the puppet master to start'
|
693
|
-
unless port_open_within?( host, 8140, 10 )
|
694
|
-
raise Beaker::DSL::FailTest, 'Puppet master did not start in a timely fashion'
|
695
|
-
end
|
696
|
-
logger.debug 'The puppet master has started'
|
697
|
-
return true
|
698
|
-
end
|
699
|
-
|
700
|
-
# @!visibility private
|
701
|
-
def stop_puppet_from_source_on( host )
|
702
|
-
pid = host.exec( Command.new('cat `puppet master --configprint pidfile`') ).stdout.chomp
|
703
|
-
host.exec( Command.new( "kill #{pid}" ) )
|
704
|
-
Timeout.timeout(10) do
|
705
|
-
while host.exec( Command.new( "kill -0 #{pid}"), :acceptable_exit_codes => [0,1] ).exit_code == 0 do
|
706
|
-
# until kill -0 finds no process and we know that puppet has finished cleaning up
|
707
|
-
sleep 1
|
708
|
-
end
|
709
|
-
end
|
710
|
-
end
|
711
|
-
|
712
|
-
# @!visibility private
|
713
|
-
def dump_puppet_log(host)
|
714
|
-
syslogfile = case host['platform']
|
715
|
-
when /fedora|centos|el|redhat|scientific/ then '/var/log/messages'
|
716
|
-
when /ubuntu|debian|cumulus/ then '/var/log/syslog'
|
717
|
-
else return
|
718
|
-
end
|
719
|
-
|
720
|
-
logger.notify "\n*************************"
|
721
|
-
logger.notify "* Dumping master log *"
|
722
|
-
logger.notify "*************************"
|
723
|
-
host.exec( Command.new( "tail -n 100 #{syslogfile}" ), :acceptable_exit_codes => [0,1])
|
724
|
-
logger.notify "*************************\n"
|
725
|
-
end
|
726
|
-
|
727
|
-
# @!visibility private
|
728
|
-
def lay_down_new_puppet_conf( host, configuration_options, testdir )
|
729
|
-
puppetconf_main = host.puppet('master')['config']
|
730
|
-
puppetconf_filename = File.basename(puppetconf_main)
|
731
|
-
puppetconf_test = File.join(testdir, puppetconf_filename)
|
732
|
-
|
733
|
-
new_conf = puppet_conf_for( host, configuration_options )
|
734
|
-
create_remote_file host, puppetconf_test, new_conf.to_s
|
735
|
-
|
736
|
-
host.exec(
|
737
|
-
Command.new( "cat #{puppetconf_test} > #{puppetconf_main}" ),
|
738
|
-
:silent => true
|
739
|
-
)
|
740
|
-
host.exec( Command.new( "cat #{puppetconf_main}" ) )
|
741
|
-
end
|
742
|
-
|
743
|
-
# @!visibility private
|
744
|
-
def puppet_conf_for host, conf_opts
|
745
|
-
puppetconf = host.exec( Command.new( "cat #{host.puppet('master')['config']}" ) ).stdout
|
746
|
-
new_conf = IniFile.new( puppetconf ).merge( conf_opts )
|
747
|
-
|
748
|
-
new_conf
|
749
|
-
end
|
750
|
-
|
751
|
-
# Modify the given TrapperKeeper config file.
|
752
|
-
#
|
753
|
-
# @param [Host] host A host object
|
754
|
-
# @param [OptionsHash] options_hash New hash which will be merged into
|
755
|
-
# the given TrapperKeeper config.
|
756
|
-
# @param [String] config_file_path Path to the TrapperKeeper config on
|
757
|
-
# the given host which is to be
|
758
|
-
# modified.
|
759
|
-
# @param [Bool] replace If set true, instead of updating the existing
|
760
|
-
# TrapperKeeper configuration, replace it entirely
|
761
|
-
# with the contents of the given hash.
|
762
|
-
#
|
763
|
-
# @note TrapperKeeper config files can be HOCON, JSON, or Ini. We don't
|
764
|
-
# particularly care which of these the file named by `config_file_path` on
|
765
|
-
# the SUT actually is, just that the contents can be parsed into a map.
|
766
|
-
#
|
767
|
-
def modify_tk_config(host, config_file_path, options_hash, replace=false)
|
768
|
-
if options_hash.empty?
|
769
|
-
return nil
|
770
|
-
end
|
771
|
-
|
772
|
-
new_hash = Beaker::Options::OptionsHash.new
|
773
|
-
|
774
|
-
if replace
|
775
|
-
new_hash.merge!(options_hash)
|
776
|
-
else
|
777
|
-
if not host.file_exist?( config_file_path )
|
778
|
-
raise "Error: #{config_file_path} does not exist on #{host}"
|
779
|
-
end
|
780
|
-
file_string = host.exec( Command.new( "cat #{config_file_path}" )).stdout
|
781
|
-
|
782
|
-
begin
|
783
|
-
tk_conf_hash = read_tk_config_string(file_string)
|
784
|
-
rescue RuntimeError
|
785
|
-
raise "Error reading trapperkeeper config: #{config_file_path} at host: #{host}"
|
786
|
-
end
|
787
|
-
|
788
|
-
new_hash.merge!(tk_conf_hash)
|
789
|
-
new_hash.merge!(options_hash)
|
790
|
-
end
|
791
|
-
|
792
|
-
file_string = JSON.dump(new_hash)
|
793
|
-
create_remote_file host, config_file_path, file_string
|
794
|
-
end
|
795
|
-
|
796
|
-
# The Trapperkeeper config service will accept HOCON (aka typesafe), JSON,
|
797
|
-
# or Ini configuration files which means we need to safely handle the the
|
798
|
-
# exceptions that might come from parsing the given string with the wrong
|
799
|
-
# parser and fall back to the next valid parser in turn. We finally raise
|
800
|
-
# a RuntimeException if none of the parsers succeed.
|
801
|
-
#
|
802
|
-
# @!visibility private
|
803
|
-
def read_tk_config_string( string )
|
804
|
-
begin
|
805
|
-
return Hocon.parse(string)
|
806
|
-
rescue Hocon::ConfigError
|
807
|
-
nil
|
808
|
-
end
|
809
|
-
|
810
|
-
begin
|
811
|
-
return JSON.parse(string)
|
812
|
-
rescue JSON::JSONError
|
813
|
-
nil
|
814
|
-
end
|
815
|
-
|
816
|
-
begin
|
817
|
-
return IniFile.new(string)
|
818
|
-
rescue IniFile::Error
|
819
|
-
nil
|
820
|
-
end
|
821
|
-
|
822
|
-
raise "Failed to read TrapperKeeper config!"
|
823
|
-
end
|
824
|
-
|
825
|
-
# @!visibility private
|
826
|
-
def bounce_service host, service, curl_retries = 120
|
827
|
-
if host.graceful_restarts?
|
828
|
-
apachectl_path = host.is_pe? ? "#{host['puppetsbindir']}/apache2ctl" : 'apache2ctl'
|
829
|
-
host.exec(Command.new("#{apachectl_path} graceful"))
|
830
|
-
else
|
831
|
-
host.exec puppet_resource('service', service, 'ensure=stopped')
|
832
|
-
host.exec puppet_resource('service', service, 'ensure=running')
|
833
|
-
end
|
834
|
-
curl_with_retries(" #{service} ", host, "https://localhost:8140", [35, 60], curl_retries)
|
835
|
-
end
|
836
|
-
|
837
|
-
# Blocks until the port is open on the host specified, returns false
|
838
|
-
# on failure
|
839
|
-
def port_open_within?( host, port = 8140, seconds = 120 )
|
840
|
-
repeat_for( seconds ) do
|
841
|
-
host.port_open?( port )
|
842
|
-
end
|
843
|
-
end
|
844
|
-
|
845
|
-
# Runs 'puppet apply' on a remote host, piping manifest through stdin
|
846
|
-
#
|
847
|
-
# @param [Host] host The host that this command should be run on
|
848
|
-
#
|
849
|
-
# @param [String] manifest The puppet manifest to apply
|
850
|
-
#
|
851
|
-
# @!macro common_opts
|
852
|
-
# @option opts [Boolean] :parseonly (false) If this key is true, the
|
853
|
-
# "--parseonly" command line parameter will
|
854
|
-
# be passed to the 'puppet apply' command.
|
855
|
-
#
|
856
|
-
# @option opts [Boolean] :trace (false) If this key exists in the Hash,
|
857
|
-
# the "--trace" command line parameter will be
|
858
|
-
# passed to the 'puppet apply' command.
|
859
|
-
#
|
860
|
-
# @option opts [Array<Integer>] :acceptable_exit_codes ([0]) The list of exit
|
861
|
-
# codes that will NOT raise an error when found upon
|
862
|
-
# command completion. If provided, these values will
|
863
|
-
# be combined with those used in :catch_failures and
|
864
|
-
# :expect_failures to create the full list of
|
865
|
-
# passing exit codes.
|
866
|
-
#
|
867
|
-
# @option opts [Hash] :environment Additional environment variables to be
|
868
|
-
# passed to the 'puppet apply' command
|
869
|
-
#
|
870
|
-
# @option opts [Boolean] :catch_failures (false) By default `puppet
|
871
|
-
# --apply` will exit with 0, which does not count
|
872
|
-
# as a test failure, even if there were errors or
|
873
|
-
# changes when applying the manifest. This option
|
874
|
-
# enables detailed exit codes and causes a test
|
875
|
-
# failure if `puppet --apply` indicates there was
|
876
|
-
# a failure during its execution.
|
877
|
-
#
|
878
|
-
# @option opts [Boolean] :catch_changes (false) This option enables
|
879
|
-
# detailed exit codes and causes a test failure
|
880
|
-
# if `puppet --apply` indicates that there were
|
881
|
-
# changes or failures during its execution.
|
882
|
-
#
|
883
|
-
# @option opts [Boolean] :expect_changes (false) This option enables
|
884
|
-
# detailed exit codes and causes a test failure
|
885
|
-
# if `puppet --apply` indicates that there were
|
886
|
-
# no resource changes during its execution.
|
887
|
-
#
|
888
|
-
# @option opts [Boolean] :expect_failures (false) This option enables
|
889
|
-
# detailed exit codes and causes a test failure
|
890
|
-
# if `puppet --apply` indicates there were no
|
891
|
-
# failure during its execution.
|
892
|
-
#
|
893
|
-
# @option opts [Boolean] :future_parser (false) This option enables
|
894
|
-
# the future parser option that is available
|
895
|
-
# from Puppet verion 3.2
|
896
|
-
# By default it will use the 'current' parser.
|
897
|
-
#
|
898
|
-
# @option opts [Boolean] :noop (false) If this option exists, the
|
899
|
-
# the "--noop" command line parameter will be
|
900
|
-
# passed to the 'puppet apply' command.
|
901
|
-
#
|
902
|
-
# @option opts [String] :modulepath The search path for modules, as
|
903
|
-
# a list of directories separated by the system
|
904
|
-
# path separator character. (The POSIX path separator
|
905
|
-
# is ‘:’, and the Windows path separator is ‘;’.)
|
906
|
-
#
|
907
|
-
# @option opts [String] :debug (false) If this option exists,
|
908
|
-
# the "--debug" command line parameter
|
909
|
-
# will be passed to the 'puppet apply' command.
|
910
|
-
#
|
911
|
-
# @param [Block] block This method will yield to a block of code passed
|
912
|
-
# by the caller; this can be used for additional
|
913
|
-
# validation, etc.
|
914
|
-
#
|
915
|
-
def apply_manifest_on(host, manifest, opts = {}, &block)
|
916
|
-
block_on host do | host |
|
917
|
-
on_options = {}
|
918
|
-
on_options[:acceptable_exit_codes] = Array(opts[:acceptable_exit_codes])
|
919
|
-
|
920
|
-
puppet_apply_opts = {}
|
921
|
-
if opts[:debug]
|
922
|
-
puppet_apply_opts[:debug] = nil
|
923
|
-
else
|
924
|
-
puppet_apply_opts[:verbose] = nil
|
925
|
-
end
|
926
|
-
puppet_apply_opts[:parseonly] = nil if opts[:parseonly]
|
927
|
-
puppet_apply_opts[:trace] = nil if opts[:trace]
|
928
|
-
puppet_apply_opts[:parser] = 'future' if opts[:future_parser]
|
929
|
-
puppet_apply_opts[:modulepath] = opts[:modulepath] if opts[:modulepath]
|
930
|
-
puppet_apply_opts[:noop] = nil if opts[:noop]
|
931
|
-
|
932
|
-
# From puppet help:
|
933
|
-
# "... an exit code of '2' means there were changes, an exit code of
|
934
|
-
# '4' means there were failures during the transaction, and an exit
|
935
|
-
# code of '6' means there were both changes and failures."
|
936
|
-
if [opts[:catch_changes],opts[:catch_failures],opts[:expect_failures],opts[:expect_changes]].compact.length > 1
|
937
|
-
raise(ArgumentError,
|
938
|
-
'Cannot specify more than one of `catch_failures`, ' +
|
939
|
-
'`catch_changes`, `expect_failures`, or `expect_changes` ' +
|
940
|
-
'for a single manifest')
|
941
|
-
end
|
942
|
-
|
943
|
-
if opts[:catch_changes]
|
944
|
-
puppet_apply_opts['detailed-exitcodes'] = nil
|
945
|
-
|
946
|
-
# We're after idempotency so allow exit code 0 only.
|
947
|
-
on_options[:acceptable_exit_codes] |= [0]
|
948
|
-
elsif opts[:catch_failures]
|
949
|
-
puppet_apply_opts['detailed-exitcodes'] = nil
|
950
|
-
|
951
|
-
# We're after only complete success so allow exit codes 0 and 2 only.
|
952
|
-
on_options[:acceptable_exit_codes] |= [0, 2]
|
953
|
-
elsif opts[:expect_failures]
|
954
|
-
puppet_apply_opts['detailed-exitcodes'] = nil
|
955
|
-
|
956
|
-
# We're after failures specifically so allow exit codes 1, 4, and 6 only.
|
957
|
-
on_options[:acceptable_exit_codes] |= [1, 4, 6]
|
958
|
-
elsif opts[:expect_changes]
|
959
|
-
puppet_apply_opts['detailed-exitcodes'] = nil
|
960
|
-
|
961
|
-
# We're after changes specifically so allow exit code 2 only.
|
962
|
-
on_options[:acceptable_exit_codes] |= [2]
|
963
|
-
else
|
964
|
-
# Either use the provided acceptable_exit_codes or default to [0]
|
965
|
-
on_options[:acceptable_exit_codes] |= [0]
|
966
|
-
end
|
967
|
-
|
968
|
-
# Not really thrilled with this implementation, might want to improve it
|
969
|
-
# later. Basically, there is a magic trick in the constructor of
|
970
|
-
# PuppetCommand which allows you to pass in a Hash for the last value in
|
971
|
-
# the *args Array; if you do so, it will be treated specially. So, here
|
972
|
-
# we check to see if our caller passed us a hash of environment variables
|
973
|
-
# that they want to set for the puppet command. If so, we set the final
|
974
|
-
# value of *args to a new hash with just one entry (the value of which
|
975
|
-
# is our environment variables hash)
|
976
|
-
if opts.has_key?(:environment)
|
977
|
-
puppet_apply_opts['ENV'] = opts[:environment]
|
978
|
-
end
|
979
|
-
|
980
|
-
file_path = host.tmpfile('apply_manifest.pp')
|
981
|
-
create_remote_file(host, file_path, manifest + "\n")
|
982
|
-
|
983
|
-
if host[:default_apply_opts].respond_to? :merge
|
984
|
-
puppet_apply_opts = host[:default_apply_opts].merge( puppet_apply_opts )
|
985
|
-
end
|
986
|
-
|
987
|
-
on host, puppet('apply', file_path, puppet_apply_opts), on_options, &block
|
988
|
-
end
|
989
|
-
end
|
990
|
-
|
991
|
-
# Runs 'puppet apply' on default host, piping manifest through stdin
|
992
|
-
# @see #apply_manifest_on
|
993
|
-
def apply_manifest(manifest, opts = {}, &block)
|
994
|
-
apply_manifest_on(default, manifest, opts, &block)
|
995
|
-
end
|
996
|
-
|
997
|
-
# @deprecated
|
998
|
-
def run_agent_on(host, arg='--no-daemonize --verbose --onetime --test',
|
999
|
-
options={}, &block)
|
1000
|
-
block_on host do | host |
|
1001
|
-
on host, puppet_agent(arg), options, &block
|
1002
|
-
end
|
1003
|
-
end
|
1004
|
-
|
1005
|
-
# FIX: this should be moved into host/platform
|
1006
|
-
# @visibility private
|
1007
|
-
def run_cron_on(host, action, user, entry="", &block)
|
1008
|
-
block_on host do | host |
|
1009
|
-
platform = host['platform']
|
1010
|
-
if platform.include?('solaris') || platform.include?('aix') then
|
1011
|
-
case action
|
1012
|
-
when :list then args = '-l'
|
1013
|
-
when :remove then args = '-r'
|
1014
|
-
when :add
|
1015
|
-
on( host,
|
1016
|
-
"echo '#{entry}' > /var/spool/cron/crontabs/#{user}",
|
1017
|
-
&block )
|
1018
|
-
end
|
1019
|
-
|
1020
|
-
else # default for GNU/Linux platforms
|
1021
|
-
case action
|
1022
|
-
when :list then args = '-l -u'
|
1023
|
-
when :remove then args = '-r -u'
|
1024
|
-
when :add
|
1025
|
-
on( host,
|
1026
|
-
"echo '#{entry}' > /tmp/#{user}.cron && " +
|
1027
|
-
"crontab -u #{user} /tmp/#{user}.cron",
|
1028
|
-
&block )
|
1029
|
-
end
|
1030
|
-
end
|
1031
|
-
|
1032
|
-
if args
|
1033
|
-
case action
|
1034
|
-
when :list, :remove then on(host, "crontab #{args} #{user}", &block)
|
1035
|
-
end
|
1036
|
-
end
|
1037
|
-
end
|
1038
|
-
end
|
1039
|
-
|
1040
|
-
# This method using the puppet resource 'host' will setup host aliases
|
1041
|
-
# and register the remove of host aliases via Beaker::TestCase#teardown
|
1042
|
-
#
|
1043
|
-
# A teardown step is also added to make sure unstubbing of the host is
|
1044
|
-
# removed always.
|
1045
|
-
#
|
1046
|
-
# @param [Host, Array<Host>, String, Symbol] machine One or more hosts to act upon,
|
1047
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1048
|
-
# @param ip_spec [Hash{String=>String}] a hash containing the host to ip
|
1049
|
-
# mappings
|
1050
|
-
# @example Stub puppetlabs.com on the master to 127.0.0.1
|
1051
|
-
# stub_hosts_on(master, 'puppetlabs.com' => '127.0.0.1')
|
1052
|
-
def stub_hosts_on(machine, ip_spec)
|
1053
|
-
block_on machine do | host |
|
1054
|
-
ip_spec.each do |address, ip|
|
1055
|
-
logger.notify("Stubbing address #{address} to IP #{ip} on machine #{host}")
|
1056
|
-
on( host, puppet('resource', 'host', address, 'ensure=present', "ip=#{ip}") )
|
1057
|
-
end
|
1058
|
-
|
1059
|
-
teardown do
|
1060
|
-
ip_spec.each do |address, ip|
|
1061
|
-
logger.notify("Unstubbing address #{address} to IP #{ip} on machine #{host}")
|
1062
|
-
on( host, puppet('resource', 'host', address, 'ensure=absent') )
|
1063
|
-
end
|
1064
|
-
end
|
1065
|
-
end
|
1066
|
-
end
|
1067
|
-
|
1068
|
-
# This method accepts a block and using the puppet resource 'host' will
|
1069
|
-
# setup host aliases before and after that block.
|
1070
|
-
#
|
1071
|
-
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
1072
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1073
|
-
# @param ip_spec [Hash{String=>String}] a hash containing the host to ip
|
1074
|
-
# mappings
|
1075
|
-
# @example Stub puppetlabs.com on the master to 127.0.0.1
|
1076
|
-
# with_host_stubbed_on(master, 'forgeapi.puppetlabs.com' => '127.0.0.1') do
|
1077
|
-
# puppet( "module install puppetlabs-stdlib" )
|
1078
|
-
# end
|
1079
|
-
def with_host_stubbed_on(host, ip_spec, &block)
|
1080
|
-
begin
|
1081
|
-
block_on host do |host|
|
1082
|
-
ip_spec.each_pair do |address, ip|
|
1083
|
-
logger.notify("Stubbing address #{address} to IP #{ip} on machine #{host}")
|
1084
|
-
on( host, puppet('resource', 'host', address, 'ensure=present', "ip=#{ip}") )
|
1085
|
-
end
|
1086
|
-
end
|
1087
|
-
|
1088
|
-
block.call
|
1089
|
-
|
1090
|
-
ensure
|
1091
|
-
ip_spec.each do |address, ip|
|
1092
|
-
logger.notify("Unstubbing address #{address} to IP #{ip} on machine #{host}")
|
1093
|
-
on( host, puppet('resource', 'host', address, 'ensure=absent') )
|
1094
|
-
end
|
1095
|
-
end
|
1096
|
-
end
|
1097
|
-
|
1098
|
-
# This method accepts a block and using the puppet resource 'host' will
|
1099
|
-
# setup host aliases before and after that block on the default host
|
1100
|
-
#
|
1101
|
-
# @example Stub puppetlabs.com on the default host to 127.0.0.1
|
1102
|
-
# stub_hosts('puppetlabs.com' => '127.0.0.1')
|
1103
|
-
# @see #stub_hosts_on
|
1104
|
-
def stub_hosts(ip_spec)
|
1105
|
-
stub_hosts_on(default, ip_spec)
|
1106
|
-
end
|
1107
|
-
|
1108
|
-
# This wraps the method `stub_hosts_on` and makes the stub specific to
|
1109
|
-
# the forge alias.
|
1110
|
-
#
|
1111
|
-
# forge api v1 canonical source is forge.puppetlabs.com
|
1112
|
-
# forge api v3 canonical source is forgeapi.puppetlabs.com
|
1113
|
-
#
|
1114
|
-
# @param machine [String] the host to perform the stub on
|
1115
|
-
# @param forge_host [String] The URL to use as the forge alias, will default to using :forge_host in the
|
1116
|
-
# global options hash
|
1117
|
-
def stub_forge_on(machine, forge_host = nil)
|
1118
|
-
#use global options hash
|
1119
|
-
forge_host ||= options[:forge_host]
|
1120
|
-
@forge_ip ||= Resolv.getaddress(forge_host)
|
1121
|
-
block_on machine do | host |
|
1122
|
-
stub_hosts_on(host, 'forge.puppetlabs.com' => @forge_ip)
|
1123
|
-
stub_hosts_on(host, 'forgeapi.puppetlabs.com' => @forge_ip)
|
1124
|
-
end
|
1125
|
-
end
|
1126
|
-
|
1127
|
-
# This wraps the method `with_host_stubbed_on` and makes the stub specific to
|
1128
|
-
# the forge alias.
|
1129
|
-
#
|
1130
|
-
# forge api v1 canonical source is forge.puppetlabs.com
|
1131
|
-
# forge api v3 canonical source is forgeapi.puppetlabs.com
|
1132
|
-
#
|
1133
|
-
# @param host [String] the host to perform the stub on
|
1134
|
-
# @param forge_host [String] The URL to use as the forge alias, will default to using :forge_host in the
|
1135
|
-
# global options hash
|
1136
|
-
def with_forge_stubbed_on( host, forge_host = nil, &block )
|
1137
|
-
#use global options hash
|
1138
|
-
forge_host ||= options[:forge_host]
|
1139
|
-
@forge_ip ||= Resolv.getaddress(forge_host)
|
1140
|
-
with_host_stubbed_on( host,
|
1141
|
-
{'forge.puppetlabs.com' => @forge_ip,
|
1142
|
-
'forgeapi.puppetlabs.com' => @forge_ip},
|
1143
|
-
&block )
|
1144
|
-
end
|
1145
|
-
|
1146
|
-
# This wraps `with_forge_stubbed_on` and provides it the default host
|
1147
|
-
# @see with_forge_stubbed_on
|
1148
|
-
def with_forge_stubbed( forge_host = nil, &block )
|
1149
|
-
with_forge_stubbed_on( default, forge_host, &block )
|
1150
|
-
end
|
1151
|
-
|
1152
|
-
# This wraps the method `stub_hosts` and makes the stub specific to
|
1153
|
-
# the forge alias.
|
1154
|
-
#
|
1155
|
-
# @see #stub_forge_on
|
1156
|
-
def stub_forge(forge_host = nil)
|
1157
|
-
#use global options hash
|
1158
|
-
forge_host ||= options[:forge_host]
|
1159
|
-
stub_forge_on(default, forge_host)
|
1160
|
-
end
|
1161
|
-
|
1162
|
-
def sleep_until_puppetdb_started(host)
|
1163
|
-
curl_with_retries("start puppetdb", host, "http://localhost:8080", 0, 120)
|
1164
|
-
curl_with_retries("start puppetdb (ssl)",
|
1165
|
-
host, "https://#{host.node_name}:8081", [35, 60])
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
def sleep_until_puppetserver_started(host)
|
1169
|
-
curl_with_retries("start puppetserver (ssl)",
|
1170
|
-
host, "https://#{host.node_name}:8140", [35, 60])
|
1171
|
-
end
|
1172
|
-
|
1173
|
-
def sleep_until_nc_started(host)
|
1174
|
-
curl_with_retries("start nodeclassifier (ssl)",
|
1175
|
-
host, "https://#{host.node_name}:4433", [35, 60])
|
1176
|
-
end
|
1177
|
-
|
1178
|
-
def curl_with_retries(desc, host, url, desired_exit_codes, max_retries = 60, retry_interval = 1)
|
1179
|
-
opts = {
|
1180
|
-
:desired_exit_codes => desired_exit_codes,
|
1181
|
-
:max_retries => max_retries,
|
1182
|
-
:retry_interval => retry_interval
|
1183
|
-
}
|
1184
|
-
retry_on(host, "curl -m 1 #{url}", opts)
|
1185
|
-
end
|
1186
|
-
|
1187
|
-
# This command will execute repeatedly until success or it runs out with an error
|
1188
|
-
#
|
1189
|
-
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
1190
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1191
|
-
# @param [String, Command] command The command to execute on *host*.
|
1192
|
-
# @param [Hash{Symbol=>String}] opts Options to alter execution.
|
1193
|
-
# @param [Proc] block Additional actions or assertions.
|
1194
|
-
#
|
1195
|
-
# @option opts [Array<Fixnum>, Fixnum] :desired_exit_codes (0) An array
|
1196
|
-
# or integer exit code(s) that should be considered
|
1197
|
-
# acceptable. An error will be thrown if the exit code never
|
1198
|
-
# matches one of the values in this list.
|
1199
|
-
# @option opts [Fixnum] :max_retries (60) number of times the
|
1200
|
-
# command will be tried before failing
|
1201
|
-
# @option opts [Float] :retry_interval (1) number of seconds
|
1202
|
-
# that we'll wait between tries
|
1203
|
-
# @option opts [Boolean] :verbose (false)
|
1204
|
-
def retry_on(host, command, opts = {}, &block)
|
1205
|
-
option_exit_codes = opts[:desired_exit_codes]
|
1206
|
-
option_max_retries = opts[:max_retries].to_i
|
1207
|
-
option_retry_interval = opts[:retry_interval].to_f
|
1208
|
-
desired_exit_codes = option_exit_codes ? [option_exit_codes].flatten : [0]
|
1209
|
-
desired_exit_codes = [0] if desired_exit_codes.empty?
|
1210
|
-
max_retries = option_max_retries == 0 ? 60 : option_max_retries # nil & "" both return 0
|
1211
|
-
retry_interval = option_retry_interval == 0 ? 1 : option_retry_interval
|
1212
|
-
verbose = true.to_s == opts[:verbose]
|
1213
|
-
|
1214
|
-
log_prefix = host.log_prefix
|
1215
|
-
logger.debug "\n#{log_prefix} #{Time.new.strftime('%H:%M:%S')}$ #{command}"
|
1216
|
-
logger.debug " Trying command #{max_retries} times."
|
1217
|
-
logger.debug ".", add_newline=false
|
1218
|
-
|
1219
|
-
result = on host, command, {:acceptable_exit_codes => (0...127), :silent => !verbose}, &block
|
1220
|
-
num_retries = 0
|
1221
|
-
until desired_exit_codes.include?(result.exit_code)
|
1222
|
-
sleep retry_interval
|
1223
|
-
result = on host, command, {:acceptable_exit_codes => (0...127), :silent => !verbose}, &block
|
1224
|
-
num_retries += 1
|
1225
|
-
logger.debug ".", add_newline=false
|
1226
|
-
if (num_retries > max_retries)
|
1227
|
-
logger.debug " Command \`#{command}\` failed."
|
1228
|
-
fail("Command \`#{command}\` failed.")
|
1229
|
-
end
|
1230
|
-
end
|
1231
|
-
logger.debug "\n#{log_prefix} #{Time.new.strftime('%H:%M:%S')}$ #{command} ostensibly successful."
|
1232
|
-
result
|
1233
|
-
end
|
1234
|
-
|
1235
|
-
#Is semver-ish version a less than semver-ish version b
|
1236
|
-
#@param [String] a A version of the from '\d.\d.\d.*'
|
1237
|
-
#@param [String] b A version of the form '\d.\d.\d.*'
|
1238
|
-
#@return [Boolean] true if a is less than b, otherwise return false
|
1239
|
-
#
|
1240
|
-
#@note 3.0.0-160-gac44cfb is greater than 3.0.0, and 2.8.2
|
1241
|
-
#@note -rc being less than final builds is not yet implemented.
|
1242
|
-
def version_is_less a, b
|
1243
|
-
a_nums = a.split('-')[0].split('.')
|
1244
|
-
b_nums = b.split('-')[0].split('.')
|
1245
|
-
(0...a_nums.length).each do |i|
|
1246
|
-
if i < b_nums.length
|
1247
|
-
if a_nums[i] < b_nums[i]
|
1248
|
-
return true
|
1249
|
-
elsif a_nums[i] > b_nums[i]
|
1250
|
-
return false
|
1251
|
-
end
|
1252
|
-
else
|
1253
|
-
return false
|
1254
|
-
end
|
1255
|
-
end
|
1256
|
-
#checks all dots, they are equal so examine the rest
|
1257
|
-
a_rest = a.split('-', 2)[1]
|
1258
|
-
b_rest = b.split('-', 2)[1]
|
1259
|
-
if a_rest and b_rest and a_rest < b_rest
|
1260
|
-
return false
|
1261
|
-
elsif a_rest and not b_rest
|
1262
|
-
return false
|
1263
|
-
elsif not a_rest and b_rest
|
1264
|
-
return true
|
1265
|
-
end
|
1266
|
-
return false
|
1267
|
-
end
|
1268
|
-
|
1269
|
-
#stops the puppet agent running on the host
|
1270
|
-
# @param [Host, Array<Host>, String, Symbol] agent One or more hosts to act upon,
|
1271
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1272
|
-
def stop_agent_on(agent)
|
1273
|
-
block_on agent do | host |
|
1274
|
-
vardir = agent.puppet['vardir']
|
1275
|
-
agent_running = true
|
1276
|
-
while agent_running
|
1277
|
-
agent_running = agent.file_exist?("#{vardir}/state/agent_catalog_run.lock")
|
1278
|
-
if agent_running
|
1279
|
-
sleep 2
|
1280
|
-
end
|
1281
|
-
end
|
1282
|
-
|
1283
|
-
# The agent service is `pe-puppet` everywhere EXCEPT certain linux distros on PE 2.8
|
1284
|
-
# In all the case that it is different, this init script will exist. So we can assume
|
1285
|
-
# that if the script doesn't exist, we should just use `pe-puppet`
|
1286
|
-
agent_service = 'pe-puppet-agent'
|
1287
|
-
agent_service = 'pe-puppet' unless agent.file_exist?('/etc/init.d/pe-puppet-agent')
|
1288
|
-
|
1289
|
-
# Under a number of stupid circumstances, we can't stop the
|
1290
|
-
# agent using puppet. This is usually because of issues with
|
1291
|
-
# the init script or system on that particular configuration.
|
1292
|
-
avoid_puppet_at_all_costs = false
|
1293
|
-
avoid_puppet_at_all_costs ||= agent['platform'] =~ /el-4/
|
1294
|
-
avoid_puppet_at_all_costs ||= agent['pe_ver'] && version_is_less(agent['pe_ver'], '3.2') && agent['platform'] =~ /sles/
|
1295
|
-
|
1296
|
-
if avoid_puppet_at_all_costs
|
1297
|
-
# When upgrading, puppet is already stopped. On EL4, this causes an exit code of '1'
|
1298
|
-
on agent, "/etc/init.d/#{agent_service} stop", :acceptable_exit_codes => [0, 1]
|
1299
|
-
else
|
1300
|
-
on agent, puppet_resource('service', agent_service, 'ensure=stopped')
|
1301
|
-
end
|
1302
|
-
end
|
1303
|
-
end
|
1304
|
-
|
1305
|
-
#stops the puppet agent running on the default host
|
1306
|
-
# @see #stop_agent_on
|
1307
|
-
def stop_agent
|
1308
|
-
stop_agent_on(default)
|
1309
|
-
end
|
1310
|
-
|
1311
|
-
|
1312
|
-
#wait for a given host to appear in the dashboard
|
1313
|
-
def wait_for_host_in_dashboard(host)
|
1314
|
-
hostname = host.node_name
|
1315
|
-
retry_on(dashboard, "! curl --tlsv1 -k -I https://#{dashboard}/nodes/#{hostname} | grep '404 Not Found'")
|
1316
|
-
end
|
1317
|
-
|
1318
|
-
# Ensure the host has requested a cert, then sign it
|
1319
|
-
#
|
1320
|
-
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
1321
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1322
|
-
#
|
1323
|
-
# @return nil
|
1324
|
-
# @raise [FailTest] if process times out
|
1325
|
-
def sign_certificate_for(host)
|
1326
|
-
block_on host do | host |
|
1327
|
-
if [master, dashboard, database].include? host
|
1328
|
-
|
1329
|
-
on host, puppet( 'agent -t' ), :acceptable_exit_codes => [0,1,2]
|
1330
|
-
on master, puppet( "cert --allow-dns-alt-names sign #{host}" ), :acceptable_exit_codes => [0,24]
|
1331
|
-
|
1332
|
-
else
|
1333
|
-
|
1334
|
-
hostname = Regexp.escape host.node_name
|
1335
|
-
|
1336
|
-
last_sleep = 0
|
1337
|
-
next_sleep = 1
|
1338
|
-
(0..10).each do |i|
|
1339
|
-
fail_test("Failed to sign cert for #{hostname}") if i == 10
|
1340
|
-
|
1341
|
-
on master, puppet("cert --sign --all --allow-dns-alt-names"), :acceptable_exit_codes => [0,24]
|
1342
|
-
break if on(master, puppet("cert --list --all")).stdout =~ /\+ "?#{hostname}"?/
|
1343
|
-
sleep next_sleep
|
1344
|
-
(last_sleep, next_sleep) = next_sleep, last_sleep+next_sleep
|
1345
|
-
end
|
1346
|
-
|
1347
|
-
end
|
1348
|
-
end
|
1349
|
-
end
|
1350
|
-
|
1351
|
-
#prompt the master to sign certs then check to confirm the cert for the default host is signed
|
1352
|
-
#@see #sign_certificate_for
|
1353
|
-
def sign_certificate
|
1354
|
-
sign_certificate_for(default)
|
1355
|
-
end
|
1356
|
-
|
1357
|
-
# Get a facter fact from a provided host
|
1358
|
-
#
|
1359
|
-
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
1360
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1361
|
-
# @param [String] name The name of the fact to query for
|
1362
|
-
# @!macro common_opts
|
1363
|
-
#
|
1364
|
-
# @return String The value of the fact 'name' on the provided host
|
1365
|
-
# @raise [FailTest] Raises an exception if call to facter fails
|
1366
|
-
def fact_on(host, name, opts = {})
|
1367
|
-
result = on host, facter(name, opts)
|
1368
|
-
if result.kind_of?(Array)
|
1369
|
-
result.map { |res| res.stdout.chomp }
|
1370
|
-
else
|
1371
|
-
result.stdout.chomp
|
1372
|
-
end
|
1373
|
-
end
|
1374
|
-
|
1375
|
-
# Get a facter fact from the default host
|
1376
|
-
# @see #fact_on
|
1377
|
-
def fact(name, opts = {})
|
1378
|
-
fact_on(default, name, opts)
|
1379
|
-
end
|
1380
|
-
|
1381
|
-
#Run a curl command on the provided host(s)
|
1382
|
-
#
|
1383
|
-
# @param [Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
1384
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1385
|
-
# @param [String, Command] cmd The curl command to execute on *host*.
|
1386
|
-
# @param [Proc] block Additional actions or assertions.
|
1387
|
-
# @!macro common_opts
|
1388
|
-
#
|
1389
|
-
def curl_on(host, cmd, opts = {}, &block)
|
1390
|
-
if options.is_pe? #check global options hash
|
1391
|
-
on host, "curl --tlsv1 %s" % cmd, opts, &block
|
1392
|
-
else
|
1393
|
-
on host, "curl %s" % cmd, opts, &block
|
1394
|
-
end
|
1395
|
-
end
|
1396
|
-
|
1397
|
-
# Write hiera config file on one or more provided hosts
|
1398
|
-
#
|
1399
|
-
# @param[Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
1400
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1401
|
-
# @param[Array] One or more hierarchy paths
|
1402
|
-
def write_hiera_config_on(host, hierarchy)
|
1403
|
-
|
1404
|
-
block_on host do |host|
|
1405
|
-
hiera_config=Hash.new
|
1406
|
-
hiera_config[:backends] = 'yaml'
|
1407
|
-
hiera_config[:yaml] = {}
|
1408
|
-
hiera_config[:yaml][:datadir] = hiera_datadir(host)
|
1409
|
-
hiera_config[:hierarchy] = hierarchy
|
1410
|
-
hiera_config[:logger] = 'console'
|
1411
|
-
create_remote_file host, host.puppet['hiera_config'], hiera_config.to_yaml
|
1412
|
-
end
|
1413
|
-
end
|
1414
|
-
|
1415
|
-
# Write hiera config file for the default host
|
1416
|
-
# @see #write_hiera_config_on
|
1417
|
-
def write_hiera_config(hierarchy)
|
1418
|
-
write_hiera_config_on(default, hierarchy)
|
1419
|
-
end
|
1420
|
-
|
1421
|
-
# Copy hiera data files to one or more provided hosts
|
1422
|
-
#
|
1423
|
-
# @param[Host, Array<Host>, String, Symbol] host One or more hosts to act upon,
|
1424
|
-
# or a role (String or Symbol) that identifies one or more hosts.
|
1425
|
-
# @param[String] Directory containing the hiera data files.
|
1426
|
-
def copy_hiera_data_to(host, source)
|
1427
|
-
scp_to host, File.expand_path(source), hiera_datadir(host)
|
1428
|
-
end
|
1429
|
-
|
1430
|
-
# Copy hiera data files to the default host
|
1431
|
-
# @see #copy_hiera_data_to
|
1432
|
-
def copy_hiera_data(source)
|
1433
|
-
copy_hiera_data_to(default, source)
|
1434
|
-
end
|
1435
|
-
|
1436
|
-
# Get file path to the hieradatadir for a given host.
|
1437
|
-
# Handles whether or not a host is AIO-based & backwards compatibility
|
1438
|
-
#
|
1439
|
-
# @param[Host] host Host you want to use the hieradatadir from
|
1440
|
-
#
|
1441
|
-
# @return [String] Path to the hiera data directory
|
1442
|
-
def hiera_datadir(host)
|
1443
|
-
host[:type] =~ /aio/ ? File.join(host.puppet['codedir'], 'hieradata') : host[:hieradatadir]
|
1444
|
-
end
|
1445
|
-
|
24
|
+
include Beaker::DSL::Helpers::FacterHelpers
|
25
|
+
include Beaker::DSL::Helpers::HieraHelpers
|
26
|
+
include Beaker::DSL::Helpers::HostHelpers
|
27
|
+
include Beaker::DSL::Helpers::PuppetHelpers
|
28
|
+
include Beaker::DSL::Helpers::TKHelpers
|
29
|
+
include Beaker::DSL::Helpers::WebHelpers
|
1446
30
|
end
|
1447
31
|
end
|
1448
32
|
end
|