beaker 2.25.0 → 2.26.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 +142 -2
- data/lib/beaker/cli.rb +5 -3
- data/lib/beaker/dsl/helpers/host_helpers.rb +19 -0
- data/lib/beaker/dsl/install_utils/foss_utils.rb +1 -0
- data/lib/beaker/dsl/wrappers.rb +39 -2
- data/lib/beaker/host.rb +1 -1
- data/lib/beaker/host/pswindows/exec.rb +1 -1
- data/lib/beaker/host/windows/exec.rb +1 -1
- data/lib/beaker/hypervisor/docker.rb +20 -3
- data/lib/beaker/logger.rb +1 -3
- data/lib/beaker/options/command_line_parser.rb +8 -2
- data/lib/beaker/options/presets.rb +1 -1
- data/lib/beaker/perf.rb +53 -1
- data/lib/beaker/ssh_connection.rb +44 -15
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/dsl/install_utils/foss_utils_spec.rb +1 -0
- data/spec/beaker/dsl/wrappers_spec.rb +49 -0
- data/spec/beaker/hypervisor/docker_spec.rb +32 -0
- data/spec/beaker/options/command_line_parser_spec.rb +1 -1
- data/spec/beaker/perf_spec.rb +4 -4
- data/spec/beaker/ssh_connection_spec.rb +2 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YzQ4ODE5YmE3ZTJlMmJiY2UxYjgyYjEzYjM2NzYxYTkwNjYzZWRhNg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjRiNzY1ZTEyMTdkYWQwYjAxYWVhY2NiMzE1MzM2ODdmMjEzZTk5ZQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NDFmOWFiZWMwMjcxOWMwMGQwMzUxMzFiNDU1ZDE0M2E1ZGI4YmI3ZTY3YjZh
|
10
|
+
NjdlYzE5Y2QxZTczMDJmNzI3MTEyZDVmNDExMWQwNGZkYzYxYjY5Y2JhYzVj
|
11
|
+
MWI2NTE2NzdjYmY2OWI3Y2I3NTFjN2VjMDE1YmY5OTNiOGU3YWE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NjViMjNhMDc1MDVhZTY5MThlNjQyM2M3ZTE2MDdiOTU4ZmQ0N2U1OGIwYWRj
|
14
|
+
MWMxYjA2NThhMWM0YzU5YjNmNmQ4MDI4OWY0ZTU2NmEzZmI4ZTAzMDc1OTM4
|
15
|
+
NGI0YTQ2NGQ1ODY0M2Q1MzVlMjVjMmM3ZGFkMzBlMzRlM2E3NWI=
|
data/HISTORY.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# default - History
|
2
2
|
## Tags
|
3
|
-
* [LATEST -
|
3
|
+
* [LATEST - 13 Oct, 2015 (d581b613)](#LATEST)
|
4
|
+
* [2.25.0 - 1 Oct, 2015 (51d4cb1a)](#2.25.0)
|
4
5
|
* [2.24.0 - 15 Sep, 2015 (c12e9054)](#2.24.0)
|
5
6
|
* [2.23.0 - 9 Sep, 2015 (2532324a)](#2.23.0)
|
6
7
|
* [2.22.0 - 1 Sep, 2015 (96ec20a7)](#2.22.0)
|
@@ -97,7 +98,146 @@
|
|
97
98
|
* [pe1.2 - 6 Sep, 2011 (ba3dadd2)](#pe1.2)
|
98
99
|
|
99
100
|
## Details
|
100
|
-
### <a name = "LATEST">LATEST -
|
101
|
+
### <a name = "LATEST">LATEST - 13 Oct, 2015 (d581b613)
|
102
|
+
|
103
|
+
* (GEM) update beaker version to 2.26.0 (d581b613)
|
104
|
+
|
105
|
+
* Merge pull request #971 from sschneid/sysprofile (e2c5f6fc)
|
106
|
+
|
107
|
+
|
108
|
+
```
|
109
|
+
Merge pull request #971 from sschneid/sysprofile
|
110
|
+
|
111
|
+
(BKR-580) --collect-perf-data enhancements
|
112
|
+
```
|
113
|
+
* Merge pull request #980 from johnduarte/patch-sol-pkg-names (4ef4ba07)
|
114
|
+
|
115
|
+
|
116
|
+
```
|
117
|
+
Merge pull request #980 from johnduarte/patch-sol-pkg-names
|
118
|
+
|
119
|
+
(maint) Fix Solaris 11 package name logic
|
120
|
+
```
|
121
|
+
* Merge pull request #975 from anodelman/win-fix (6a1e14a9)
|
122
|
+
|
123
|
+
|
124
|
+
```
|
125
|
+
Merge pull request #975 from anodelman/win-fix
|
126
|
+
|
127
|
+
(BKR-275) PowerShell Wrapper Does not Handle Quoting
|
128
|
+
```
|
129
|
+
* (BKR-275) PowerShell Wrapper Does not Handle Quoting (5bffbaa0)
|
130
|
+
|
131
|
+
|
132
|
+
```
|
133
|
+
(BKR-275) PowerShell Wrapper Does not Handle Quoting
|
134
|
+
|
135
|
+
- add spec test coverage for EncodedCommand support in powershell
|
136
|
+
wrapper
|
137
|
+
```
|
138
|
+
* (maint) Fix Solaris 11 package name logic (fcbd6018)
|
139
|
+
|
140
|
+
|
141
|
+
```
|
142
|
+
(maint) Fix Solaris 11 package name logic
|
143
|
+
|
144
|
+
This commit fixes a bug in the Solaris 11 package naming logic
|
145
|
+
that dropped the SHA suffix entirely from the final package name.
|
146
|
+
The SHA should be incorporated into the package name.
|
147
|
+
|
148
|
+
An additional spec test has been added for the expected package
|
149
|
+
name in this circumstance.
|
150
|
+
```
|
151
|
+
* (BKR-275) PowerShell Wrapper Does not Handle Quoting (d364123b)
|
152
|
+
|
153
|
+
|
154
|
+
```
|
155
|
+
(BKR-275) PowerShell Wrapper Does not Handle Quoting
|
156
|
+
|
157
|
+
- add unicode support
|
158
|
+
```
|
159
|
+
* Merge pull request #968 from anodelman/new-platform (ad037a82)
|
160
|
+
|
161
|
+
|
162
|
+
```
|
163
|
+
Merge pull request #968 from anodelman/new-platform
|
164
|
+
|
165
|
+
(BKR-488) Add support for Windows 10 (x86, x64)
|
166
|
+
```
|
167
|
+
* (BKR-275) PowerShell Wrapper Does not Handle Quoting (c530b8c5)
|
168
|
+
|
169
|
+
|
170
|
+
```
|
171
|
+
(BKR-275) PowerShell Wrapper Does not Handle Quoting
|
172
|
+
|
173
|
+
- create new powershell dsl helper:
|
174
|
+
execute_powershell_script_on
|
175
|
+
* takes as input a string representing a powershell script
|
176
|
+
* create a file on the host containing the script
|
177
|
+
* executes the script using powershell -File
|
178
|
+
- add the ability to execute an encoded powershell string
|
179
|
+
powershell("Set Content -path 'fu.txt', -value 'fu'", {'EncodedCommand => true})
|
180
|
+
* the command will be Base64 encoded for you
|
181
|
+
* bypasses quoting sadness
|
182
|
+
```
|
183
|
+
* Merge pull request #907 from hamidnazari/master (a28c8cf1)
|
184
|
+
|
185
|
+
|
186
|
+
```
|
187
|
+
Merge pull request #907 from hamidnazari/master
|
188
|
+
|
189
|
+
(BKR-427) Support for Docker Container Names and Container Reuse
|
190
|
+
```
|
191
|
+
* (BKR-580) Different Debian vs EL crontab differences (a4c78dac)
|
192
|
+
|
193
|
+
* (BKR-580) Fix spec tests broken in 9b16bef (3ec3fad0)
|
194
|
+
|
195
|
+
* (BKR-580) --collect-perf-data enhancements (c57d4d44)
|
196
|
+
|
197
|
+
|
198
|
+
```
|
199
|
+
(BKR-580) --collect-perf-data enhancements
|
200
|
+
|
201
|
+
* allow --collect-perf-data modes:
|
202
|
+
|
203
|
+
'aggressive' (poll every minute)
|
204
|
+
'normal' (poll every 10 minutes)
|
205
|
+
'none' (do not collect perf data)
|
206
|
+
|
207
|
+
If a mode is unspecified, --collect-perf-data will default to 'normal',
|
208
|
+
which mimics past behavior.
|
209
|
+
|
210
|
+
* allow metric exporting to Graphite:
|
211
|
+
|
212
|
+
Set via the HOSTS file, eg:
|
213
|
+
|
214
|
+
|
215
|
+
`json
|
216
|
+
graphite_server: graphite.example.com
|
217
|
+
graphite_perf_data: beaker.perf
|
218
|
+
|
219
|
+
`
|
220
|
+
```
|
221
|
+
* (BKR-427) Added support for Docker container names and container reuse (e8a65c67)
|
222
|
+
|
223
|
+
* (BKR-488) Add support for Windows 10 (x86, x64) (5b2918db)
|
224
|
+
|
225
|
+
|
226
|
+
```
|
227
|
+
(BKR-488) Add support for Windows 10 (x86, x64)
|
228
|
+
|
229
|
+
- improve the 'wait_for_connection_failure' ssh connection method
|
230
|
+
* increase the timeouts
|
231
|
+
* send actual data down the pipe, seems to improve the function of
|
232
|
+
the test
|
233
|
+
* remove 'abort' calls from the code, we can recover and retry
|
234
|
+
* added yard docs
|
235
|
+
- add /f to the windows reboot call
|
236
|
+
* forces closure of any open applications
|
237
|
+
```
|
238
|
+
### <a name = "2.25.0">2.25.0 - 1 Oct, 2015 (51d4cb1a)
|
239
|
+
|
240
|
+
* (HISTORY) update beaker history for gem release 2.25.0 (51d4cb1a)
|
101
241
|
|
102
242
|
* (GEM) update beaker version to 2.25.0 (e21f5581)
|
103
243
|
|
data/lib/beaker/cli.rb
CHANGED
@@ -85,7 +85,9 @@ module Beaker
|
|
85
85
|
provision
|
86
86
|
|
87
87
|
# Setup perf monitoring if needed
|
88
|
-
|
88
|
+
if @options[:collect_perf_data].to_s =~ /(aggressive)|(normal)/
|
89
|
+
@perf = Beaker::Perf.new( @hosts, @options )
|
90
|
+
end
|
89
91
|
|
90
92
|
errored = false
|
91
93
|
|
@@ -101,11 +103,13 @@ module Beaker
|
|
101
103
|
#run post-suite if we are in fail-slow mode
|
102
104
|
if @options[:fail_mode].to_s =~ /slow/
|
103
105
|
run_suite(:post_suite)
|
106
|
+
@perf.print_perf_info if defined? @perf
|
104
107
|
end
|
105
108
|
raise e
|
106
109
|
else
|
107
110
|
#post acceptance on success
|
108
111
|
run_suite(:post_suite)
|
112
|
+
@perf.print_perf_info if defined? @perf
|
109
113
|
end
|
110
114
|
#cleanup phase
|
111
115
|
rescue => e
|
@@ -119,7 +123,6 @@ module Beaker
|
|
119
123
|
preserve_hosts_file
|
120
124
|
end
|
121
125
|
|
122
|
-
@perf.print_perf_info if @options[:collect_perf_data]
|
123
126
|
print_reproduction_info( :error )
|
124
127
|
|
125
128
|
@logger.error "Failed running the test suite."
|
@@ -139,7 +142,6 @@ module Beaker
|
|
139
142
|
if @logger.is_debug?
|
140
143
|
print_reproduction_info( :debug )
|
141
144
|
end
|
142
|
-
@perf.print_perf_info if @options[:collect_perf_data]
|
143
145
|
end
|
144
146
|
end
|
145
147
|
|
@@ -265,6 +265,25 @@ module Beaker
|
|
265
265
|
end
|
266
266
|
end
|
267
267
|
|
268
|
+
# Execute a powershell script from file, remote file created from provided string
|
269
|
+
# @note This method uses Tempfile in Ruby's STDLIB as well as {#create_remote_file}.
|
270
|
+
#
|
271
|
+
# @param [Host] hosts One or more hosts (or some object
|
272
|
+
# that responds like
|
273
|
+
# {Beaker::Host#do_scp_from}.
|
274
|
+
# @param [String] powershell_script A string describing a set of powershell actions
|
275
|
+
#
|
276
|
+
# @return [Result] Returns the result of the powershell command execution
|
277
|
+
def execute_powershell_script_on(hosts, powershell_script, opts = {})
|
278
|
+
block_on hosts do |host|
|
279
|
+
script_path = "beaker_powershell_script_#{Time.now.to_i}.ps1"
|
280
|
+
create_remote_file(host, script_path, powershell_script, opts)
|
281
|
+
native_path = script_path.gsub(/\//, "\\")
|
282
|
+
on host, powershell("", {"File" => native_path }), opts
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
268
287
|
# Move a local script to a remote host and execute it
|
269
288
|
# @note this relies on {#on} and {#scp_to}
|
270
289
|
#
|
@@ -1182,6 +1182,7 @@ module Beaker
|
|
1182
1182
|
component_version.gsub!(/(^-)|(-$)/, '')
|
1183
1183
|
# Here we strip leading 0 from version components but leave
|
1184
1184
|
# singular 0 on their own.
|
1185
|
+
component_version = component_version.split('-').join('.')
|
1185
1186
|
component_version = component_version.split('.').map(&:to_i).join('.')
|
1186
1187
|
end
|
1187
1188
|
release_file = "puppet-agent#{solaris_name_conjunction}#{component_version}#{solaris_release_version}#{solaris_revision_conjunction}#{revision}.#{arch}.#{pkg_suffix}"
|
data/lib/beaker/dsl/wrappers.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'base64'
|
1
2
|
module Beaker
|
2
3
|
module DSL
|
3
4
|
# These are wrappers to equivalent {Beaker::Command} objects
|
@@ -107,7 +108,7 @@ module Beaker
|
|
107
108
|
# Returns a {Beaker::Command} object for executing powershell commands on a host
|
108
109
|
#
|
109
110
|
# @param [String] command The powershell command to execute
|
110
|
-
# @param [Hash] args The commandline
|
111
|
+
# @param [Hash] args The commandline parameters to be passed to powershell
|
111
112
|
#
|
112
113
|
# @example Setting the contents of a file
|
113
114
|
# powershell("Set-Content -path 'fu.txt' -value 'fu'")
|
@@ -115,6 +116,12 @@ module Beaker
|
|
115
116
|
# @example Using an alternative execution policy
|
116
117
|
# powershell("Set-Content -path 'fu.txt' -value 'fu'", {'ExecutionPolicy' => 'Unrestricted'})
|
117
118
|
#
|
119
|
+
# @example Using an EncodedCommand (defaults to non-encoded)
|
120
|
+
# powershell("Set Content -path 'fu.txt', -value 'fu'", {'EncodedCommand => true})
|
121
|
+
#
|
122
|
+
# @example executing from a file
|
123
|
+
# powershell("", {'-File' => '/path/to/file'})
|
124
|
+
#
|
118
125
|
# @return [Command]
|
119
126
|
def powershell(command, args={})
|
120
127
|
ps_opts = {
|
@@ -124,8 +131,17 @@ module Beaker
|
|
124
131
|
'NoProfile' => '',
|
125
132
|
'NonInteractive' => ''
|
126
133
|
}
|
134
|
+
encoded = false
|
127
135
|
ps_opts.merge!(args)
|
128
136
|
ps_args = []
|
137
|
+
|
138
|
+
# determine if the command should be encoded
|
139
|
+
if ps_opts.has_key?('EncodedCommand')
|
140
|
+
v = ps_opts.delete('EncodedCommand')
|
141
|
+
# encode the commend if v is true, nil or empty
|
142
|
+
encoded = v || v.eql?('') || v.nil?
|
143
|
+
end
|
144
|
+
|
129
145
|
ps_opts.each do |k, v|
|
130
146
|
if v.eql?('') or v.nil?
|
131
147
|
ps_args << "-#{k}"
|
@@ -133,10 +149,31 @@ module Beaker
|
|
133
149
|
ps_args << "-#{k} #{v}"
|
134
150
|
end
|
135
151
|
end
|
136
|
-
|
152
|
+
|
153
|
+
# may not have a command if executing a file
|
154
|
+
if command && !command.empty?
|
155
|
+
if encoded
|
156
|
+
ps_args << "-EncodedCommand #{encode_command(command)}"
|
157
|
+
else
|
158
|
+
ps_args << "-Command #{command}"
|
159
|
+
end
|
160
|
+
end
|
137
161
|
|
138
162
|
Command.new("powershell.exe", ps_args)
|
139
163
|
end
|
164
|
+
|
165
|
+
# Convert the provided command string to Base64
|
166
|
+
# @param [String] cmd The command to convert to Base64
|
167
|
+
# @return [String] The converted string
|
168
|
+
# @api private
|
169
|
+
def encode_command(cmd)
|
170
|
+
cmd = cmd.chars.to_a.join("\x00").chomp
|
171
|
+
cmd << "\x00" unless cmd[-1].eql? "\x00"
|
172
|
+
# use strict_encode because linefeeds are not correctly handled in our model
|
173
|
+
cmd = Base64.strict_encode64(cmd).chomp
|
174
|
+
cmd
|
175
|
+
end
|
176
|
+
|
140
177
|
end
|
141
178
|
end
|
142
179
|
end
|
data/lib/beaker/host.rb
CHANGED
@@ -295,7 +295,7 @@ module Beaker
|
|
295
295
|
if options[:expect_connection_failure] && result.exit_code
|
296
296
|
# should have had a connection failure, but didn't
|
297
297
|
# wait to see if the connection failure will be generation, otherwise raise error
|
298
|
-
if not connection.wait_for_connection_failure
|
298
|
+
if not connection.wait_for_connection_failure(options, output_callback)
|
299
299
|
raise CommandFailure, "Host '#{self}' should have resulted in a connection failure running:\n #{cmdline}\nLast #{@options[:trace_limit]} lines of output were:\n#{result.formatted_output(@options[:trace_limit])}"
|
300
300
|
end
|
301
301
|
end
|
@@ -2,7 +2,7 @@ module Windows::Exec
|
|
2
2
|
include Beaker::CommandFactory
|
3
3
|
|
4
4
|
def reboot
|
5
|
-
exec(Beaker::Command.new('shutdown /r /t 0 /d p:4:1 /c "Beaker::Host reboot command issued"'), :expect_connection_failure => true)
|
5
|
+
exec(Beaker::Command.new('shutdown /f /r /t 0 /d p:4:1 /c "Beaker::Host reboot command issued"'), :expect_connection_failure => true)
|
6
6
|
# rebooting on windows is sloooooow
|
7
7
|
# give it some breathing room before attempting a reconnect
|
8
8
|
sleep(40)
|
@@ -64,11 +64,28 @@ module Beaker
|
|
64
64
|
image_name = image.id
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
|
-
container = ::Docker::Container.create({
|
67
|
+
container_opts = {
|
69
68
|
'Image' => image_name,
|
70
69
|
'Hostname' => host.name,
|
71
|
-
}
|
70
|
+
}
|
71
|
+
|
72
|
+
unless host['docker_container_name'].nil?
|
73
|
+
@logger.debug("Looking for an existing container called #{host['docker_container_name']}")
|
74
|
+
existing_container = ::Docker::Container.all.select do |container| container.info['Names'].include? "/#{host['docker_container_name']}" end
|
75
|
+
|
76
|
+
# Prepare to use the existing container or else create it
|
77
|
+
if existing_container.any?
|
78
|
+
container = existing_container[0]
|
79
|
+
else
|
80
|
+
container_opts['name'] = host['docker_container_name']
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# If the specified container exists, then use it rather creating a new one
|
85
|
+
if container.nil?
|
86
|
+
@logger.debug("Creating container from image #{image_name}")
|
87
|
+
container = ::Docker::Container.create(container_opts)
|
88
|
+
end
|
72
89
|
|
73
90
|
@logger.debug("Starting container #{container.id}")
|
74
91
|
container.start({"PublishAllPorts" => true, "Privileged" => true})
|
data/lib/beaker/logger.rb
CHANGED
@@ -248,9 +248,7 @@ module Beaker
|
|
248
248
|
# @param args[Array<String>] Strings to be reported
|
249
249
|
def perf_output *args
|
250
250
|
return unless is_debug?
|
251
|
-
|
252
|
-
string = strings.join
|
253
|
-
optionally_color MAGENTA, string, false
|
251
|
+
optionally_color MAGENTA, *args
|
254
252
|
end
|
255
253
|
|
256
254
|
# Report a trace message.
|
@@ -195,8 +195,14 @@ module Beaker
|
|
195
195
|
@cmd_options[:validate] = bool
|
196
196
|
end
|
197
197
|
|
198
|
-
opts.on '--collect-perf-data',
|
199
|
-
|
198
|
+
opts.on '--collect-perf-data [MODE]',
|
199
|
+
'Collect SUT performance and load data',
|
200
|
+
'Possible values:',
|
201
|
+
'aggressive (poll every minute)',
|
202
|
+
'normal (poll every 10 minutes)',
|
203
|
+
'none (do not collect perf data)',
|
204
|
+
'(default: normal)' do |mode|
|
205
|
+
@cmd_options[:collect_perf_data] = mode || 'normal'
|
200
206
|
end
|
201
207
|
|
202
208
|
opts.on('--version', 'Report currently running version of beaker' ) do
|
@@ -179,7 +179,7 @@ module Beaker
|
|
179
179
|
:dot_fog => File.join(ENV['HOME'], '.fog'),
|
180
180
|
:ec2_yaml => 'config/image_templates/ec2.yaml',
|
181
181
|
:help => false,
|
182
|
-
:collect_perf_data =>
|
182
|
+
:collect_perf_data => 'none',
|
183
183
|
:ssh => {
|
184
184
|
:config => false,
|
185
185
|
:paranoid => false,
|
data/lib/beaker/perf.rb
CHANGED
@@ -46,6 +46,14 @@ module Beaker
|
|
46
46
|
@logger.perf_output("Creating symlink from /etc/sysstat/sysstat.cron to /etc/cron.d")
|
47
47
|
host.exec(Command.new('ln -s /etc/sysstat/sysstat.cron /etc/cron.d'),:acceptable_exit_codes => [0,1])
|
48
48
|
end
|
49
|
+
if @options[:collect_perf_data] =~ /aggressive/
|
50
|
+
@logger.perf_output("Enabling aggressive sysstat polling")
|
51
|
+
if host['platform'] =~ /debian|ubuntu/
|
52
|
+
host.exec(Command.new('sed -i s/5-55\\\/10/*/ /etc/cron.d/sysstat'))
|
53
|
+
elsif host['platform'] =~ /centos|el|fedora|oracle|redhats|scientific/
|
54
|
+
host.exec(Command.new('sed -i s/*\\\/10/*/ /etc/cron.d/sysstat'))
|
55
|
+
end
|
56
|
+
end
|
49
57
|
if host['platform'] =~ PERF_START_PLATFORMS # SLES doesn't need this step
|
50
58
|
host.exec(Command.new('service sysstat start'))
|
51
59
|
end
|
@@ -66,10 +74,54 @@ module Beaker
|
|
66
74
|
def get_perf_data(host, perf_start, perf_end)
|
67
75
|
@logger.perf_output("Getting perf data for host: " + host)
|
68
76
|
if host['platform'] =~ PERF_SUPPORTED_PLATFORMS # All flavours of Linux
|
69
|
-
|
77
|
+
if not @options[:collect_perf_data] =~ /aggressive/
|
78
|
+
host.exec(Command.new("sar -A -s #{perf_start.strftime("%H:%M:%S")} -e #{perf_end.strftime("%H:%M:%S")}"),:acceptable_exit_codes => [0,1,2])
|
79
|
+
end
|
80
|
+
if (defined? @options[:graphite_server] and not @options[:graphite_server].nil?) and
|
81
|
+
(defined? @options[:graphite_perf_data] and not @options[:graphite_perf_data].nil?)
|
82
|
+
export_perf_data_to_graphite(host)
|
83
|
+
end
|
70
84
|
else
|
71
85
|
@logger.perf_output("Perf (sysstat) not supported on host: " + host)
|
72
86
|
end
|
73
87
|
end
|
88
|
+
|
89
|
+
# Send performance report numbers to an external Graphite instance
|
90
|
+
# @param [Host] host The host we are working with
|
91
|
+
# @return [void] The report is sent to the logging output
|
92
|
+
def export_perf_data_to_graphite(host)
|
93
|
+
@logger.perf_output("Sending data to Graphite server: " + @options[:graphite_server])
|
94
|
+
|
95
|
+
data = JSON.parse(host.exec(Command.new("sadf -j -- -A"),:silent => true).stdout)
|
96
|
+
hostname = host['vmhostname'].split('.')[0]
|
97
|
+
|
98
|
+
data['sysstat']['hosts'].each do |host|
|
99
|
+
host['statistics'].each do |poll|
|
100
|
+
timestamp = DateTime.parse(poll['timestamp']['date'] + ' ' + poll['timestamp']['time']).to_time.to_i
|
101
|
+
|
102
|
+
poll.keys.each do |stat|
|
103
|
+
case stat
|
104
|
+
when 'cpu-load-all'
|
105
|
+
poll[stat].each do |s|
|
106
|
+
s.keys.each do |k|
|
107
|
+
next if k == 'cpu'
|
108
|
+
|
109
|
+
socket = TCPSocket.new(@options[:graphite_server], 2003)
|
110
|
+
socket.puts "#{@options[:graphite_perf_data]}.#{hostname}.cpu.#{s['cpu']}.#{k} #{s[k]} #{timestamp}"
|
111
|
+
socket.close
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
when 'memory'
|
116
|
+
poll[stat].keys.each do |s|
|
117
|
+
socket = TCPSocket.new(@options[:graphite_server], 2003)
|
118
|
+
socket.puts "#{@options[:graphite_perf_data]}.#{hostname}.memory.#{s} #{poll[stat][s]} #{timestamp}"
|
119
|
+
socket.close
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
74
126
|
end
|
75
127
|
end
|
@@ -17,8 +17,11 @@ module Beaker
|
|
17
17
|
Errno::ECONNREFUSED,
|
18
18
|
Errno::ECONNRESET,
|
19
19
|
Errno::ENETUNREACH,
|
20
|
+
Net::SSH::Exception,
|
20
21
|
Net::SSH::Disconnect,
|
21
22
|
Net::SSH::AuthenticationFailed,
|
23
|
+
Net::SSH::ChannelRequestFailed,
|
24
|
+
Net::SSH::ChannelOpenFailed,
|
22
25
|
IOError,
|
23
26
|
]
|
24
27
|
|
@@ -46,7 +49,7 @@ module Beaker
|
|
46
49
|
@logger.debug "Attempting ssh connection to #{host}, user: #{user}, opts: #{ssh_opts}"
|
47
50
|
Net::SSH.start(host, user, ssh_opts)
|
48
51
|
rescue *RETRYABLE_EXCEPTIONS => e
|
49
|
-
if try <=
|
52
|
+
if try <= 11
|
50
53
|
@logger.warn "Try #{try} -- Host #{host} unreachable: #{e.class.name} - #{e.message}"
|
51
54
|
@logger.warn "Trying again in #{wait} seconds"
|
52
55
|
sleep wait
|
@@ -103,26 +106,52 @@ module Beaker
|
|
103
106
|
end
|
104
107
|
end
|
105
108
|
|
106
|
-
#
|
107
|
-
|
109
|
+
# Wait for the ssh connection to fail, returns true on connection failure and false otherwise
|
110
|
+
# @param [Hash{Symbol=>String}] options Options hash to control method conditionals
|
111
|
+
# @option options [Boolean] :pty Should we request a terminal when attempting
|
112
|
+
# to send a command over this connection?
|
113
|
+
# @option options [String] :stdin Any input to be sent along with the command
|
114
|
+
# @param [IO] stdout_callback An IO stream to send connection stdout to, defaults to nil
|
115
|
+
# @param [IO] stderr_callback An IO stream to send connection stderr to, defaults to nil
|
116
|
+
# @return [Boolean] true if connection failed, false otherwise
|
117
|
+
def wait_for_connection_failure options = {}, stdout_callback = nil, stderr_callback = stdout_callback
|
108
118
|
try = 1
|
109
|
-
last_wait =
|
110
|
-
wait =
|
119
|
+
last_wait = 2
|
120
|
+
wait = 3
|
121
|
+
command = 'echo echo' #can be run on all platforms (I'm looking at you, windows)
|
111
122
|
while try < 11
|
123
|
+
result = Result.new(@hostname, command)
|
112
124
|
begin
|
113
|
-
@logger.
|
125
|
+
@logger.notify "Waiting for connection failure on #{@hostname} (attempt #{try}, try again in #{wait} second(s))"
|
126
|
+
@logger.debug("\n#{@hostname} #{Time.new.strftime('%H:%M:%S')}$ #{command}")
|
114
127
|
@ssh.open_channel do |channel|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
128
|
+
request_terminal_for( channel, command ) if options[:pty]
|
129
|
+
|
130
|
+
channel.exec(command) do |terminal, success|
|
131
|
+
raise Net::SSH::Exception.new("FAILED: to execute command on a new channel on #{@hostname}") unless success
|
132
|
+
register_stdout_for terminal, result, stdout_callback
|
133
|
+
register_stderr_for terminal, result, stderr_callback
|
134
|
+
register_exit_code_for terminal, result
|
135
|
+
|
136
|
+
process_stdin_for( terminal, options[:stdin] ) if options[:stdin]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
loop_tries = 0
|
140
|
+
#loop is actually loop_forever, so let it try 3 times and then quit instead of endless blocking
|
141
|
+
@ssh.loop { loop_tries += 1 ; loop_tries < 4 }
|
120
142
|
rescue *RETRYABLE_EXCEPTIONS => e
|
121
143
|
@logger.debug "Connection on #{@hostname} failed as expected (#{e.class.name} - #{e.message})"
|
122
144
|
close #this connection is bad, shut it down
|
123
145
|
return true
|
124
146
|
end
|
125
|
-
|
147
|
+
slept = 0
|
148
|
+
stdout_callback.call("sleep #{wait} second(s): ")
|
149
|
+
while slept < wait
|
150
|
+
sleep slept
|
151
|
+
stdout_callback.call('.')
|
152
|
+
slept += 1
|
153
|
+
end
|
154
|
+
stdout_callback.call("\n")
|
126
155
|
(last_wait, wait) = wait, last_wait + wait
|
127
156
|
try += 1
|
128
157
|
end
|
@@ -143,7 +172,7 @@ module Beaker
|
|
143
172
|
request_terminal_for( channel, command ) if options[:pty]
|
144
173
|
|
145
174
|
channel.exec(command) do |terminal, success|
|
146
|
-
|
175
|
+
raise Net::SSH::Exception.new("FAILED: to execute command on a new channel on #{@hostname}") unless success
|
147
176
|
register_stdout_for terminal, result, stdout_callback
|
148
177
|
register_stderr_for terminal, result, stderr_callback
|
149
178
|
register_exit_code_for terminal, result
|
@@ -198,8 +227,8 @@ module Beaker
|
|
198
227
|
if success
|
199
228
|
@logger.debug "Allocated a PTY on #{@hostname} for #{command.inspect}"
|
200
229
|
else
|
201
|
-
|
202
|
-
"#{@hostname} for #{command.inspect}"
|
230
|
+
raise Net::SSH::Exception.new("FAILED: could not allocate a pty when requested on " +
|
231
|
+
"#{@hostname} for #{command.inspect}")
|
203
232
|
end
|
204
233
|
end
|
205
234
|
end
|
data/lib/beaker/version.rb
CHANGED
@@ -1124,6 +1124,7 @@ describe ClassMixedWithDSLInstallUtils do
|
|
1124
1124
|
['1.0.1.0000786.477', '1.0.1.786.477'],
|
1125
1125
|
['1.000000.1.786.477', '1.0.1.786.477'],
|
1126
1126
|
['-1.0.1.786.477', '1.0.1.786.477'],
|
1127
|
+
['1.2.5-78-gbb3022f', '1.2.5.78.3022'],
|
1127
1128
|
['1.2.5.38.6813', '1.2.5.38.6813']
|
1128
1129
|
].each do |val, expected|
|
1129
1130
|
|
@@ -72,5 +72,54 @@ describe ClassMixedWithDSLWrappers do
|
|
72
72
|
expect( command.args ).to be === ["-ExecutionPolicy Unrestricted", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command Set-Content -path 'fu.txt' -value 'fu'"]
|
73
73
|
expect( command.options ).to be === {}
|
74
74
|
end
|
75
|
+
|
76
|
+
it 'should use EncodedCommand when EncodedCommand => true' do
|
77
|
+
cmd = "Set-Content -path 'fu.txt' -value 'fu'"
|
78
|
+
cmd = subject.encode_command(cmd)
|
79
|
+
command = subject.powershell("Set-Content -path 'fu.txt' -value 'fu'", {'EncodedCommand' => true})
|
80
|
+
expect(command.command ).to be === 'powershell.exe'
|
81
|
+
expect( command.args).to be === ["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand #{cmd}"]
|
82
|
+
expect( command.options ).to be === {}
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should use EncodedCommand when EncodedCommand => ""' do
|
86
|
+
cmd = "Set-Content -path 'fu.txt' -value 'fu'"
|
87
|
+
cmd = subject.encode_command(cmd)
|
88
|
+
command = subject.powershell("Set-Content -path 'fu.txt' -value 'fu'", {'EncodedCommand' => ""})
|
89
|
+
expect(command.command ).to be === 'powershell.exe'
|
90
|
+
expect( command.args).to be === ["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand #{cmd}"]
|
91
|
+
expect( command.options ).to be === {}
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should use EncodedCommand when EncodedCommand => nil' do
|
95
|
+
cmd = "Set-Content -path 'fu.txt' -value 'fu'"
|
96
|
+
cmd = subject.encode_command(cmd)
|
97
|
+
command = subject.powershell("Set-Content -path 'fu.txt' -value 'fu'", {'EncodedCommand' => nil})
|
98
|
+
expect(command.command ).to be === 'powershell.exe'
|
99
|
+
expect( command.args).to be === ["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand #{cmd}"]
|
100
|
+
expect( command.options ).to be === {}
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should not use EncodedCommand when EncodedCommand => false' do
|
104
|
+
command = subject.powershell("Set-Content -path 'fu.txt' -value 'fu'", {'EncodedCommand' => false})
|
105
|
+
expect(command.command ).to be === 'powershell.exe'
|
106
|
+
expect( command.args).to be === ["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command Set-Content -path 'fu.txt' -value 'fu'"]
|
107
|
+
expect( command.options ).to be === {}
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should not use EncodedCommand when EncodedCommand not present' do
|
111
|
+
command = subject.powershell("Set-Content -path 'fu.txt' -value 'fu'", {})
|
112
|
+
expect(command.command ).to be === 'powershell.exe'
|
113
|
+
expect( command.args).to be === ["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command Set-Content -path 'fu.txt' -value 'fu'"]
|
114
|
+
expect( command.options ).to be === {}
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'has no -Command/-EncodedCommand when command is empty' do
|
118
|
+
command = subject.powershell("", {"File" => 'myfile.ps1'})
|
119
|
+
expect(command.command ).to be === 'powershell.exe'
|
120
|
+
expect( command.args).to be === ["-ExecutionPolicy Bypass", "-InputFormat None", "-NoLogo", "-NoProfile", "-NonInteractive", "-File myfile.ps1"]
|
121
|
+
expect( command.options ).to be === {}
|
122
|
+
|
123
|
+
end
|
75
124
|
end
|
76
125
|
end
|
@@ -39,6 +39,9 @@ module Beaker
|
|
39
39
|
container = double('Docker::Container')
|
40
40
|
allow( container ).to receive(:id)
|
41
41
|
allow( container ).to receive(:start)
|
42
|
+
allow( container ).to receive(:info).and_return(
|
43
|
+
*(0..2).map { |index| { 'Names' => ["/spec-container-#{index}"] } }
|
44
|
+
)
|
42
45
|
allow( container ).to receive(:json).and_return({
|
43
46
|
'NetworkSettings' => {
|
44
47
|
'IPAddress' => '192.0.2.1',
|
@@ -162,6 +165,35 @@ module Beaker
|
|
162
165
|
docker.provision
|
163
166
|
end
|
164
167
|
|
168
|
+
it 'should create a named container based on the Image (identified by image.id)' do
|
169
|
+
hosts.each_with_index do |host, index|
|
170
|
+
container_name = "spec-container-#{index}"
|
171
|
+
host['docker_container_name'] = container_name
|
172
|
+
|
173
|
+
expect( ::Docker::Container ).to receive(:all).and_return([])
|
174
|
+
|
175
|
+
expect( ::Docker::Container ).to receive(:create).with({
|
176
|
+
'Image' => image.id,
|
177
|
+
'Hostname' => host.name,
|
178
|
+
'name' => container_name,
|
179
|
+
})
|
180
|
+
end
|
181
|
+
|
182
|
+
docker.provision
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should not create a container if a named one already exists' do
|
186
|
+
hosts.each_with_index do |host, index|
|
187
|
+
container_name = "spec-container-#{index}"
|
188
|
+
host['docker_container_name'] = container_name
|
189
|
+
|
190
|
+
expect( ::Docker::Container ).to receive(:all).and_return([container])
|
191
|
+
expect( ::Docker::Container ).not_to receive(:create)
|
192
|
+
end
|
193
|
+
|
194
|
+
docker.provision
|
195
|
+
end
|
196
|
+
|
165
197
|
it 'should start the container' do
|
166
198
|
expect( container ).to receive(:start).with({'PublishAllPorts' => true, 'Privileged' => true})
|
167
199
|
|
@@ -7,7 +7,7 @@ module Beaker
|
|
7
7
|
let(:parser) {Beaker::Options::CommandLineParser.new}
|
8
8
|
let(:test_opts) {["-h", "vcloud.cfg", "--debug", "--tests", "test.rb", "--help"]}
|
9
9
|
let(:full_opts_in) {["--hosts", "host.cfg", "--options", "opts_file", "--helper", "path_to_helper", "--load-path", "load_path", "--tests", "test1.rb,test2.rb,test3.rb", "--pre-suite", "pre_suite.rb", "--post-suite", "post_suite.rb", "--no-provision", "--preserve-hosts", "always", "--root-keys", "--keyfile", "../.ssh/id_rsa", "--install", "gitrepopath", "-m", "module", "-q", "--dry-run", "--no-ntp", "--repo-proxy", "--add-el-extras", "--config", "anotherfile.cfg", "--fail-mode", "fast", "--no-color", "--no-color-host-output", "--version", "--log-level", "info", "--package-proxy", "http://192.168.100.1:3128", "--collect-perf-data", "--parse-only", "--validate", "--timeout", "40", "--log-prefix", "pants", "--configure", "--tag", "1,2,3", "--exclude-tag", "4,5,6", "--xml-time-order"]}
|
10
|
-
let(:full_opts_out) {{:hosts_file=>"anotherfile.cfg",:options_file=>"opts_file", :helper => "path_to_helper", :load_path => "load_path", :tests => "test1.rb,test2.rb,test3.rb", :pre_suite => "pre_suite.rb", :post_suite => "post_suite.rb", :provision=>false, :preserve_hosts => "always", :root_keys=>true, :keyfile => "../.ssh/id_rsa", :install => "gitrepopath", :modules=>"module", :quiet=>true, :dry_run=>true, :timesync=>false, :repo_proxy=>true, :add_el_extras=>true, :fail_mode => "fast", :color=>false, :color_host_output=>false, :beaker_version_print=>true, :log_level => "info", :package_proxy => "http://192.168.100.1:3128", :collect_perf_data=>
|
10
|
+
let(:full_opts_out) {{:hosts_file=>"anotherfile.cfg",:options_file=>"opts_file", :helper => "path_to_helper", :load_path => "load_path", :tests => "test1.rb,test2.rb,test3.rb", :pre_suite => "pre_suite.rb", :post_suite => "post_suite.rb", :provision=>false, :preserve_hosts => "always", :root_keys=>true, :keyfile => "../.ssh/id_rsa", :install => "gitrepopath", :modules=>"module", :quiet=>true, :dry_run=>true, :timesync=>false, :repo_proxy=>true, :add_el_extras=>true, :fail_mode => "fast", :color=>false, :color_host_output=>false, :beaker_version_print=>true, :log_level => "info", :package_proxy => "http://192.168.100.1:3128", :collect_perf_data=>"normal", :parse_only=>true, :validate=>true, :timeout => "40", :log_prefix => "pants", :configure => true, :tag_includes => "1,2,3", :tag_excludes => "4,5,6", :xml_time_enabled => true}}
|
11
11
|
let(:validate_true) {["--validate"]}
|
12
12
|
let(:validate_false) {["--no-validate"]}
|
13
13
|
let(:configure_true) {['--configure']}
|
data/spec/beaker/perf_spec.rb
CHANGED
@@ -40,7 +40,7 @@ module Beaker
|
|
40
40
|
@my_logger.remove_destination(STDOUT)
|
41
41
|
perf = Perf.new( hosts, @options )
|
42
42
|
expect( perf ).to be_a_kind_of Perf
|
43
|
-
expect(@my_io.string).to match(/Setup perf on host: myHost
|
43
|
+
expect(@my_io.string).to match(/Setup perf on host: myHost*\nSetup perf on host: myOtherHost/)
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'creates a new Perf object with multiple hosts, :collect_perf_data = true, SLES' do
|
@@ -50,7 +50,7 @@ module Beaker
|
|
50
50
|
@my_logger.remove_destination(STDOUT)
|
51
51
|
perf = Perf.new( hosts, @options )
|
52
52
|
expect( perf ).to be_a_kind_of Perf
|
53
|
-
expect(@my_io.string).to match(/Setup perf on host:
|
53
|
+
expect(@my_io.string).to match(/Setup perf on host: myHost\nSetup perf on host: myOtherHost/)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -73,7 +73,7 @@ module Beaker
|
|
73
73
|
perf = Perf.new( @hosts, @options )
|
74
74
|
expect( perf ).to be_a_kind_of Perf
|
75
75
|
perf.print_perf_info
|
76
|
-
expect(@my_io.string).to match(/Setup perf on host:
|
76
|
+
expect(@my_io.string).to match(/Setup perf on host: myHost\nSetup perf on host: myOtherHost\nPerf \(sysstat\) not supported on host: myOtherHost\nGetting perf data for host: myHost\nGetting perf data for host: myOtherHost\nPerf \(sysstat\) not supported on host: myOtherHost/)
|
77
77
|
end
|
78
78
|
|
79
79
|
it "Does the Right Thing on non-Linux hosts" do
|
@@ -82,7 +82,7 @@ module Beaker
|
|
82
82
|
perf = Perf.new( @hosts, @options )
|
83
83
|
expect( perf ).to be_a_kind_of Perf
|
84
84
|
perf.print_perf_info
|
85
|
-
expect(@my_io.string).to match(/Setup perf on host:
|
85
|
+
expect(@my_io.string).to match(/Setup perf on host: myHost\nPerf \(sysstat\) not supported on host: myHost\nSetup perf on host: myOtherHost\nPerf \(sysstat\) not supported on host: myOtherHost\nGetting perf data for host: myHost\nPerf \(sysstat\) not supported on host: myHost\nGetting perf data for host: myOtherHost\nPerf \(sysstat\) not supported on host: myOtherHost/)
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -113,7 +113,7 @@ module Beaker
|
|
113
113
|
end
|
114
114
|
|
115
115
|
describe '#request_terminal_for' do
|
116
|
-
it 'fails correctly by
|
116
|
+
it 'fails correctly by raising Net::SSH::Exception' do
|
117
117
|
mock_ssh = Object.new
|
118
118
|
expect( Net::SSH ).to receive( :start ).with( ip, user, ssh_opts) { mock_ssh }
|
119
119
|
connection.connect
|
@@ -121,8 +121,7 @@ module Beaker
|
|
121
121
|
mock_channel = Object.new
|
122
122
|
allow( mock_channel ).to receive( :request_pty ).and_yield(nil, false)
|
123
123
|
|
124
|
-
expect
|
125
|
-
connection.request_terminal_for mock_channel, 'ls'
|
124
|
+
expect{ connection.request_terminal_for mock_channel, 'ls' }.to raise_error Net::SSH::Exception
|
126
125
|
end
|
127
126
|
end
|
128
127
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beaker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.26.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppetlabs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|