beaker 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.simplecov +14 -0
- data/DOCUMENTING.md +167 -0
- data/Gemfile +3 -0
- data/LICENSE +17 -0
- data/README.md +332 -0
- data/Rakefile +121 -0
- data/beaker.gemspec +42 -0
- data/beaker.rb +10 -0
- data/bin/beaker +9 -0
- data/lib/beaker.rb +36 -0
- data/lib/beaker/answers.rb +29 -0
- data/lib/beaker/answers/version28.rb +104 -0
- data/lib/beaker/answers/version30.rb +194 -0
- data/lib/beaker/cli.rb +113 -0
- data/lib/beaker/command.rb +241 -0
- data/lib/beaker/command_factory.rb +21 -0
- data/lib/beaker/dsl.rb +85 -0
- data/lib/beaker/dsl/assertions.rb +87 -0
- data/lib/beaker/dsl/helpers.rb +625 -0
- data/lib/beaker/dsl/install_utils.rb +299 -0
- data/lib/beaker/dsl/outcomes.rb +99 -0
- data/lib/beaker/dsl/roles.rb +97 -0
- data/lib/beaker/dsl/structure.rb +63 -0
- data/lib/beaker/dsl/wrappers.rb +100 -0
- data/lib/beaker/host.rb +193 -0
- data/lib/beaker/host/aix.rb +15 -0
- data/lib/beaker/host/aix/file.rb +16 -0
- data/lib/beaker/host/aix/group.rb +35 -0
- data/lib/beaker/host/aix/user.rb +32 -0
- data/lib/beaker/host/unix.rb +54 -0
- data/lib/beaker/host/unix/exec.rb +15 -0
- data/lib/beaker/host/unix/file.rb +16 -0
- data/lib/beaker/host/unix/group.rb +40 -0
- data/lib/beaker/host/unix/pkg.rb +22 -0
- data/lib/beaker/host/unix/user.rb +32 -0
- data/lib/beaker/host/windows.rb +44 -0
- data/lib/beaker/host/windows/exec.rb +18 -0
- data/lib/beaker/host/windows/file.rb +15 -0
- data/lib/beaker/host/windows/group.rb +36 -0
- data/lib/beaker/host/windows/pkg.rb +26 -0
- data/lib/beaker/host/windows/user.rb +32 -0
- data/lib/beaker/hypervisor.rb +37 -0
- data/lib/beaker/hypervisor/aixer.rb +52 -0
- data/lib/beaker/hypervisor/blimper.rb +123 -0
- data/lib/beaker/hypervisor/fusion.rb +56 -0
- data/lib/beaker/hypervisor/solaris.rb +65 -0
- data/lib/beaker/hypervisor/vagrant.rb +118 -0
- data/lib/beaker/hypervisor/vcloud.rb +175 -0
- data/lib/beaker/hypervisor/vsphere.rb +80 -0
- data/lib/beaker/hypervisor/vsphere_helper.rb +200 -0
- data/lib/beaker/logger.rb +167 -0
- data/lib/beaker/network_manager.rb +73 -0
- data/lib/beaker/options_parsing.rb +323 -0
- data/lib/beaker/result.rb +55 -0
- data/lib/beaker/shared.rb +15 -0
- data/lib/beaker/shared/error_handler.rb +17 -0
- data/lib/beaker/shared/host_handler.rb +46 -0
- data/lib/beaker/shared/repetition.rb +28 -0
- data/lib/beaker/ssh_connection.rb +198 -0
- data/lib/beaker/test_case.rb +225 -0
- data/lib/beaker/test_config.rb +148 -0
- data/lib/beaker/test_suite.rb +288 -0
- data/lib/beaker/utils.rb +7 -0
- data/lib/beaker/utils/ntp_control.rb +42 -0
- data/lib/beaker/utils/repo_control.rb +92 -0
- data/lib/beaker/utils/setup_helper.rb +77 -0
- data/lib/beaker/utils/validator.rb +27 -0
- data/spec/beaker/command_spec.rb +94 -0
- data/spec/beaker/dsl/assertions_spec.rb +104 -0
- data/spec/beaker/dsl/helpers_spec.rb +230 -0
- data/spec/beaker/dsl/install_utils_spec.rb +70 -0
- data/spec/beaker/dsl/outcomes_spec.rb +43 -0
- data/spec/beaker/dsl/roles_spec.rb +86 -0
- data/spec/beaker/dsl/structure_spec.rb +60 -0
- data/spec/beaker/dsl/wrappers_spec.rb +52 -0
- data/spec/beaker/host_spec.rb +95 -0
- data/spec/beaker/logger_spec.rb +117 -0
- data/spec/beaker/options_parsing_spec.rb +37 -0
- data/spec/beaker/puppet_command_spec.rb +128 -0
- data/spec/beaker/ssh_connection_spec.rb +39 -0
- data/spec/beaker/test_case_spec.rb +6 -0
- data/spec/beaker/test_suite_spec.rb +44 -0
- data/spec/mocks_and_helpers.rb +34 -0
- data/spec/spec_helper.rb +15 -0
- metadata +359 -0
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Beaker
|
5
|
+
# Config was taken by Ruby.
|
6
|
+
class TestConfig
|
7
|
+
|
8
|
+
attr_accessor :logger
|
9
|
+
def initialize(config_file, options)
|
10
|
+
@options = options
|
11
|
+
@logger = options[:logger]
|
12
|
+
@config = load_file(config_file)
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
@config[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def ssh_defaults
|
20
|
+
{
|
21
|
+
:config => false,
|
22
|
+
:paranoid => false,
|
23
|
+
:timeout => 300,
|
24
|
+
:auth_methods => ["publickey"],
|
25
|
+
:keys => [@options[:keyfile]],
|
26
|
+
:port => 22,
|
27
|
+
:user_known_hosts_file => "#{ENV['HOME']}/.ssh/known_hosts",
|
28
|
+
:forward_agent => true
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_file(config_file)
|
33
|
+
if config_file.is_a? Hash
|
34
|
+
config = config_file
|
35
|
+
else
|
36
|
+
config = YAML.load_file(config_file)
|
37
|
+
|
38
|
+
# Make sure the roles array is present for all hosts
|
39
|
+
config['HOSTS'].each_key do |host|
|
40
|
+
config['HOSTS'][host]['roles'] ||= []
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Merge some useful date into the config hash
|
45
|
+
config['CONFIG'] ||= {}
|
46
|
+
consoleport = ENV['consoleport'] || config['CONFIG']['consoleport'] || 443
|
47
|
+
config['CONFIG']['consoleport'] = consoleport.to_i
|
48
|
+
config['CONFIG']['ssh'] = ssh_defaults.merge(config['CONFIG']['ssh'] || {})
|
49
|
+
config['CONFIG']['modules'] = @options[:modules] || []
|
50
|
+
|
51
|
+
if is_pe?
|
52
|
+
config['CONFIG']['pe_dir'] = puppet_enterprise_dir
|
53
|
+
config['CONFIG']['pe_ver'] = puppet_enterprise_version
|
54
|
+
config['CONFIG']['pe_ver_win'] = puppet_enterprise_version_win
|
55
|
+
else
|
56
|
+
config['CONFIG']['puppet_ver'] = @options[:puppet]
|
57
|
+
config['CONFIG']['facter_ver'] = @options[:facter]
|
58
|
+
config['CONFIG']['hiera_ver'] = @options[:hiera]
|
59
|
+
config['CONFIG']['hiera_puppet_ver'] = @options[:hiera_puppet]
|
60
|
+
end
|
61
|
+
# need to load expect versions of PE binaries
|
62
|
+
config
|
63
|
+
end
|
64
|
+
|
65
|
+
def is_pe?
|
66
|
+
@is_pe ||= @options[:type] =~ /pe/ ? true : false
|
67
|
+
unless ENV['IS_PE'].nil?
|
68
|
+
@is_pe ||= ENV['IS_PE'] == 'true'
|
69
|
+
end
|
70
|
+
@is_pe
|
71
|
+
end
|
72
|
+
|
73
|
+
def puppet_enterprise_dir
|
74
|
+
@pe_dir ||= ENV['pe_dist_dir'] || '/opt/enterprise/dists'
|
75
|
+
end
|
76
|
+
|
77
|
+
def load_pe_version
|
78
|
+
dist_dir = puppet_enterprise_dir
|
79
|
+
version_file = ENV['pe_version_file'] || 'LATEST'
|
80
|
+
version = ""
|
81
|
+
begin
|
82
|
+
open("#{dist_dir}/#{version_file}") do |file|
|
83
|
+
while line = file.gets
|
84
|
+
if /(\w.*)/ =~ line then
|
85
|
+
version = $1.strip
|
86
|
+
@logger.debug "Found LATEST: Puppet Enterprise Version #{version}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
rescue
|
91
|
+
version = 'unknown'
|
92
|
+
end
|
93
|
+
return version
|
94
|
+
end
|
95
|
+
|
96
|
+
def puppet_enterprise_version
|
97
|
+
@pe_ver ||= load_pe_version if is_pe?
|
98
|
+
end
|
99
|
+
|
100
|
+
def load_pe_version_win
|
101
|
+
dist_dir = puppet_enterprise_dir
|
102
|
+
version_file = ENV['pe_version_file'] || 'LATEST-win'
|
103
|
+
version = ""
|
104
|
+
begin
|
105
|
+
open("#{dist_dir}/#{version_file}") do |file|
|
106
|
+
while line = file.gets
|
107
|
+
if /(\w.*)/ =~ line then
|
108
|
+
version=$1.strip
|
109
|
+
@logger.debug "Found LATEST: Puppet Enterprise Windows Version #{version}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
rescue
|
114
|
+
version = 'unknown'
|
115
|
+
end
|
116
|
+
return version
|
117
|
+
end
|
118
|
+
|
119
|
+
def puppet_enterprise_version_win
|
120
|
+
@pe_ver_win ||= load_pe_version_win if is_pe?
|
121
|
+
end
|
122
|
+
|
123
|
+
# Print out test configuration
|
124
|
+
def dump
|
125
|
+
# Access "platform" for each host
|
126
|
+
@config["HOSTS"].each_key do|host|
|
127
|
+
@logger.notify "Platform for #{host} #{@config["HOSTS"][host]['platform']}"
|
128
|
+
end
|
129
|
+
|
130
|
+
# Access "roles" for each host
|
131
|
+
@config["HOSTS"].each_key do|host|
|
132
|
+
@config["HOSTS"][host]['roles'].each do |role|
|
133
|
+
@logger.notify "Role for #{host} #{role}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Print out Ruby versions
|
138
|
+
@config["HOSTS"].each_key do|host|
|
139
|
+
@logger.notify "Ruby version for #{host} #{@config["HOSTS"][host][:ruby_ver]}"
|
140
|
+
end
|
141
|
+
|
142
|
+
# Access @config keys/values
|
143
|
+
@config["CONFIG"].each_key do|cfg|
|
144
|
+
@logger.notify "Config Key|Val: #{cfg} #{@config["CONFIG"][cfg].inspect}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,288 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'rexml/document'
|
3
|
+
require 'fileutils'
|
4
|
+
%w(test_case logger).each do |lib|
|
5
|
+
begin
|
6
|
+
require "beaker/#{lib}"
|
7
|
+
rescue LoadError
|
8
|
+
require File.expand_path(File.join(File.dirname(__FILE__), lib))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Beaker
|
13
|
+
# This Class is in need of some cleaning up beyond what can be quickly done.
|
14
|
+
# Things to keep in mind:
|
15
|
+
# * Global State Change
|
16
|
+
# * File Creation Relative to CWD -- Should be a config option
|
17
|
+
# * Better Method Documentation
|
18
|
+
class TestSuite
|
19
|
+
attr_reader :name, :options, :config, :fail_mode
|
20
|
+
|
21
|
+
def initialize(name, hosts, options, config, fail_mode = nil)
|
22
|
+
@name = name.gsub(/\s+/, '-')
|
23
|
+
@hosts = hosts
|
24
|
+
@run = false
|
25
|
+
@options = options
|
26
|
+
@config = config
|
27
|
+
@fail_mode = @options[:fail_mode] || fail_mode
|
28
|
+
@logger = options[:logger]
|
29
|
+
|
30
|
+
@test_cases = []
|
31
|
+
@test_files = []
|
32
|
+
|
33
|
+
options[:tests].each do |root|
|
34
|
+
if File.file? root then
|
35
|
+
@test_files << root
|
36
|
+
else
|
37
|
+
@test_files += Dir.glob(
|
38
|
+
File.join(root, "**/*.rb")
|
39
|
+
).select { |f| File.file?(f) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
report_and_raise(@logger, RuntimeError.new("#{@name}: no test files found..."), "TestSuite: initialize") if @test_files.empty?
|
43
|
+
|
44
|
+
@test_files = @test_files.sort
|
45
|
+
rescue => e
|
46
|
+
report_and_raise(@logger, e, "TestSuite: initialize")
|
47
|
+
end
|
48
|
+
|
49
|
+
def run
|
50
|
+
@run = true
|
51
|
+
@start_time = Time.now
|
52
|
+
|
53
|
+
configure_logging
|
54
|
+
|
55
|
+
@test_files.each do |test_file|
|
56
|
+
@logger.notify
|
57
|
+
@logger.notify "Begin #{test_file}"
|
58
|
+
start = Time.now
|
59
|
+
test_case = TestCase.new(@hosts, @logger, config, options, test_file).run_test
|
60
|
+
duration = Time.now - start
|
61
|
+
@test_cases << test_case
|
62
|
+
|
63
|
+
state = test_case.test_status == :skip ? 'skipp' : test_case.test_status
|
64
|
+
msg = "#{test_file} #{state}ed in %.2f seconds" % duration.to_f
|
65
|
+
case test_case.test_status
|
66
|
+
when :pass
|
67
|
+
@logger.success msg
|
68
|
+
when :skip
|
69
|
+
@logger.debug msg
|
70
|
+
when :fail
|
71
|
+
@logger.error msg
|
72
|
+
break if fail_mode #all failure modes cause us to kick out early on failure
|
73
|
+
when :error
|
74
|
+
@logger.warn msg
|
75
|
+
break if fail_mode #all failure modes cause use to kick out early on error
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# REVISIT: This changes global state, breaking logging in any future runs
|
80
|
+
# of the suite – or, at least, making them highly confusing for anyone who
|
81
|
+
# has not studied the implementation in detail. --daniel 2011-03-14
|
82
|
+
summarize
|
83
|
+
write_junit_xml if options[:xml]
|
84
|
+
|
85
|
+
# Allow chaining operations...
|
86
|
+
return self
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_and_raise_on_failure
|
90
|
+
begin
|
91
|
+
run
|
92
|
+
return self if success?
|
93
|
+
rescue => e
|
94
|
+
#failed during run
|
95
|
+
report_and_raise(@logger, e, "TestSuite :run_and_raise_on_failure")
|
96
|
+
else
|
97
|
+
#failed during test
|
98
|
+
report_and_raise(@logger, RuntimeError.new("Failed while running the #{name} suite"), "TestSuite: report_and_raise_on_failure")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def fail_without_test_run
|
103
|
+
report_and_raise(@logger, RuntimeError.new("#{@name}: you have not run the tests yet"), "TestSuite: fail_without_test_run") unless @run
|
104
|
+
end
|
105
|
+
|
106
|
+
def success?
|
107
|
+
fail_without_test_run
|
108
|
+
sum_failed == 0
|
109
|
+
end
|
110
|
+
|
111
|
+
def failed?
|
112
|
+
!success?
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_count
|
116
|
+
@test_count ||= @test_cases.length
|
117
|
+
end
|
118
|
+
|
119
|
+
def passed_tests
|
120
|
+
@passed_tests ||= @test_cases.select { |c| c.test_status == :pass }.length
|
121
|
+
end
|
122
|
+
|
123
|
+
def errored_tests
|
124
|
+
@errored_tests ||= @test_cases.select { |c| c.test_status == :error }.length
|
125
|
+
end
|
126
|
+
|
127
|
+
def failed_tests
|
128
|
+
@failed_tests ||= @test_cases.select { |c| c.test_status == :fail }.length
|
129
|
+
end
|
130
|
+
|
131
|
+
def skipped_tests
|
132
|
+
@skipped_tests ||= @test_cases.select { |c| c.test_status == :skip }.length
|
133
|
+
end
|
134
|
+
|
135
|
+
def pending_tests
|
136
|
+
@pending_tests ||= @test_cases.select {|c| c.test_status == :pending}.length
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def sum_failed
|
142
|
+
@sum_failed ||= failed_tests + errored_tests
|
143
|
+
end
|
144
|
+
|
145
|
+
def write_junit_xml
|
146
|
+
# This should be a configuration option
|
147
|
+
File.directory?('junit') or FileUtils.mkdir('junit')
|
148
|
+
|
149
|
+
begin
|
150
|
+
doc = REXML::Document.new
|
151
|
+
doc.add(REXML::XMLDecl.new(1.0))
|
152
|
+
|
153
|
+
suite = REXML::Element.new('testsuite', doc)
|
154
|
+
suite.add_attribute('name', name)
|
155
|
+
suite.add_attribute('tests', test_count)
|
156
|
+
suite.add_attribute('errors', errored_tests)
|
157
|
+
suite.add_attribute('failures', failed_tests)
|
158
|
+
suite.add_attribute('skip', skipped_tests)
|
159
|
+
suite.add_attribute('pending', pending_tests)
|
160
|
+
|
161
|
+
@test_cases.each do |test|
|
162
|
+
item = REXML::Element.new('testcase', suite)
|
163
|
+
item.add_attribute('classname', File.dirname(test.path))
|
164
|
+
item.add_attribute('name', File.basename(test.path))
|
165
|
+
item.add_attribute('time', test.runtime)
|
166
|
+
|
167
|
+
# Did we fail? If so, report that.
|
168
|
+
# We need to remove the escape character from colorized text, the
|
169
|
+
# substitution of other entities is handled well by Rexml
|
170
|
+
if test.test_status == :fail || test.test_status == :error then
|
171
|
+
status = REXML::Element.new('failure', item)
|
172
|
+
status.add_attribute('type', test.test_status.to_s)
|
173
|
+
if test.exception then
|
174
|
+
status.add_attribute('message', test.exception.to_s.gsub(/\e/, ''))
|
175
|
+
status.text = test.exception.backtrace.join("\n")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
if test.stdout then
|
180
|
+
REXML::Element.new('system-out', item).text =
|
181
|
+
test.stdout.gsub(/\e/, '')
|
182
|
+
end
|
183
|
+
|
184
|
+
if test.stderr then
|
185
|
+
text = REXML::Element.new('system-err', item)
|
186
|
+
text.text = test.stderr.gsub(/\e/, '')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# junit/name.xml will be created in a directory relative to the CWD
|
191
|
+
# -- JLS 2/12
|
192
|
+
File.open("junit/#{name}.xml", 'w') { |fh| doc.write(fh) }
|
193
|
+
rescue Exception => e
|
194
|
+
@logger.error "failure in XML output:\n#{e.to_s}\n" + e.backtrace.join("\n")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def summarize
|
199
|
+
fail_without_test_run
|
200
|
+
|
201
|
+
summary_logger = Logger.new(log_path("#{name}-summary.txt"), STDOUT)
|
202
|
+
|
203
|
+
summary_logger.notify <<-HEREDOC
|
204
|
+
Test Suite: #{name} @ #{@start_time}
|
205
|
+
|
206
|
+
- Host Configuration Summary -
|
207
|
+
HEREDOC
|
208
|
+
|
209
|
+
config.dump
|
210
|
+
|
211
|
+
elapsed_time = @test_cases.inject(0.0) {|r, t| r + t.runtime.to_f }
|
212
|
+
average_test_time = elapsed_time / test_count
|
213
|
+
|
214
|
+
summary_logger.notify %Q[
|
215
|
+
|
216
|
+
- Test Case Summary for suite '#{name}' -
|
217
|
+
Total Suite Time: %.2f seconds
|
218
|
+
Average Test Time: %.2f seconds
|
219
|
+
Attempted: #{test_count}
|
220
|
+
Passed: #{passed_tests}
|
221
|
+
Failed: #{failed_tests}
|
222
|
+
Errored: #{errored_tests}
|
223
|
+
Skipped: #{skipped_tests}
|
224
|
+
Pending: #{pending_tests}
|
225
|
+
|
226
|
+
- Specific Test Case Status -
|
227
|
+
] % [elapsed_time, average_test_time]
|
228
|
+
|
229
|
+
grouped_summary = @test_cases.group_by{|test_case| test_case.test_status }
|
230
|
+
|
231
|
+
summary_logger.notify "Failed Tests Cases:"
|
232
|
+
(grouped_summary[:fail] || []).each do |test_case|
|
233
|
+
print_test_failure(test_case)
|
234
|
+
end
|
235
|
+
|
236
|
+
summary_logger.notify "Errored Tests Cases:"
|
237
|
+
(grouped_summary[:error] || []).each do |test_case|
|
238
|
+
print_test_failure(test_case)
|
239
|
+
end
|
240
|
+
|
241
|
+
summary_logger.notify "Skipped Tests Cases:"
|
242
|
+
(grouped_summary[:skip] || []).each do |test_case|
|
243
|
+
print_test_failure(test_case)
|
244
|
+
end
|
245
|
+
|
246
|
+
summary_logger.notify "Pending Tests Cases:"
|
247
|
+
(grouped_summary[:pending] || []).each do |test_case|
|
248
|
+
print_test_failure(test_case)
|
249
|
+
end
|
250
|
+
|
251
|
+
summary_logger.notify("\n\n")
|
252
|
+
end
|
253
|
+
|
254
|
+
def print_test_failure(test_case)
|
255
|
+
test_reported = if test_case.exception
|
256
|
+
"reported: #{test_case.exception.inspect}"
|
257
|
+
else
|
258
|
+
test_case.test_status
|
259
|
+
end
|
260
|
+
@logger.notify " Test Case #{test_case.path} #{test_reported}"
|
261
|
+
end
|
262
|
+
|
263
|
+
def log_path(name)
|
264
|
+
@@log_dir ||= File.join("log", @start_time.strftime("%F_%T"))
|
265
|
+
unless File.directory?(@@log_dir) then
|
266
|
+
FileUtils.mkdir_p(@@log_dir)
|
267
|
+
FileUtils.cp(options[:config],(File.join(@@log_dir,"config.yml")))
|
268
|
+
|
269
|
+
latest = File.join("log", "latest")
|
270
|
+
if !File.exist?(latest) or File.symlink?(latest) then
|
271
|
+
File.delete(latest) if File.exist?(latest)
|
272
|
+
File.symlink(File.basename(@@log_dir), latest)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
File.join('log', 'latest', name)
|
277
|
+
end
|
278
|
+
|
279
|
+
# Setup log dir
|
280
|
+
def configure_logging
|
281
|
+
@logger.add_destination(log_path("#{@name}-run.log"))
|
282
|
+
#
|
283
|
+
# This is an awful hack to maintain backward compatibility until tests
|
284
|
+
# are ported to use logger.
|
285
|
+
Beaker.const_set(:Log, @logger) unless defined?( Log )
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
data/lib/beaker/utils.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Beaker
|
2
|
+
module Utils
|
3
|
+
class NTPControl
|
4
|
+
NTPSERVER = 'pool.ntp.org'
|
5
|
+
def initialize(options, hosts)
|
6
|
+
@options = options.dup
|
7
|
+
@hosts = hosts
|
8
|
+
@logger = options[:logger]
|
9
|
+
end
|
10
|
+
|
11
|
+
def timesync
|
12
|
+
@logger.notify "Update system time sync"
|
13
|
+
@logger.notify "run ntpdate against NTP pool systems"
|
14
|
+
@hosts.each do |host|
|
15
|
+
success=FALSE
|
16
|
+
if host['platform'].include? 'solaris-10'
|
17
|
+
host.exec(Command.new("sleep 10 && ntpdate -w #{NTPSERVER}"))
|
18
|
+
elsif host['platform'].include? 'windows'
|
19
|
+
# The exit code of 5 is for Windows 2008 systems where the w32tm /register command
|
20
|
+
# is not actually necessary.
|
21
|
+
host.exec(Command.new("w32tm /register"), :acceptable_exit_codes => [0,5])
|
22
|
+
host.exec(Command.new("net start w32time"), :acceptable_exit_codes => [0,2])
|
23
|
+
host.exec(Command.new("w32tm /config /manualpeerlist:#{NTPSERVER} /syncfromflags:manual /update"))
|
24
|
+
host.exec(Command.new("w32tm /resync"))
|
25
|
+
else
|
26
|
+
count=0
|
27
|
+
until success do
|
28
|
+
count+=1
|
29
|
+
raise "ntp time sync failed after #{count} tries" and break if count > 3
|
30
|
+
if host.exec(Command.new("ntpdate -t 20 #{NTPSERVER}")).exit_code == 0
|
31
|
+
success=TRUE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
@logger.notify "NTP date succeeded after #{count} tries"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
rescue => e
|
38
|
+
report_and_raise(@logger, e, "timesync (--ntp)")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|