beaker 2.15.1 → 2.16.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.
@@ -45,6 +45,22 @@ module PSWindows::Exec
45
45
  ip
46
46
  end
47
47
 
48
+ # Attempt to ping the provided target hostname
49
+ # @param [String] target The hostname to ping
50
+ # @param [Integer] attempts Amount of times to attempt ping before giving up
51
+ # @return [Boolean] true of ping successful, overwise false
52
+ def ping target, attempts=5
53
+ try = 0
54
+ while try < attempts do
55
+ result = exec(Beaker::Command.new("ping -n 1 #{target}"), :accept_all_exit_codes => true)
56
+ if result.exit_code == 0
57
+ return true
58
+ end
59
+ try+=1
60
+ end
61
+ result.exit_code == 0
62
+ end
63
+
48
64
  # Create the provided directory structure on the host
49
65
  # @param [String] dir The directory structure to create on the host
50
66
  # @return [Boolean] True, if directory construction succeeded, otherwise False
@@ -53,6 +53,22 @@ module Unix::Exec
53
53
  execute("mv #{orig} #{dest}")
54
54
  end
55
55
 
56
+ # Attempt to ping the provided target hostname
57
+ # @param [String] target The hostname to ping
58
+ # @param [Integer] attempts Amount of times to attempt ping before giving up
59
+ # @return [Boolean] true of ping successful, overwise false
60
+ def ping target, attempts=5
61
+ try = 0
62
+ while try < attempts do
63
+ result = exec(Beaker::Command.new("ping -c 1 #{target}"), :accept_all_exit_codes => true)
64
+ if result.exit_code == 0
65
+ return true
66
+ end
67
+ try+=1
68
+ end
69
+ result.exit_code == 0
70
+ end
71
+
56
72
  # Converts the provided environment file to a new shell script in /etc/profile.d, then sources that file.
57
73
  # This is for sles based hosts.
58
74
  # @param [String] env_file The ssh environment file to read from
@@ -61,6 +61,8 @@ module Unix::Pkg
61
61
  case self['platform']
62
62
  when /sles-/
63
63
  execute("zypper --non-interactive in #{name}", opts)
64
+ when /el-4/
65
+ @logger.debug("Package installation not supported on rhel4")
64
66
  when /cisco|fedora|centos|eos|el-/
65
67
  if version
66
68
  name = "#{name}-#{version}"
@@ -30,4 +30,21 @@ module Windows::Exec
30
30
  end
31
31
  ip
32
32
  end
33
+
34
+ # Attempt to ping the provided target hostname
35
+ # @param [String] target The hostname to ping
36
+ # @param [Integer] attempts Amount of times to attempt ping before giving up
37
+ # @return [Boolean] true of ping successful, overwise false
38
+ def ping target, attempts=5
39
+ try = 0
40
+ while try < attempts do
41
+ result = exec(Beaker::Command.new("ping -n 1 #{target}"), :accept_all_exit_codes => true)
42
+ if result.exit_code == 0
43
+ return true
44
+ end
45
+ try+=1
46
+ end
47
+ result.exit_code == 0
48
+ end
49
+
33
50
  end
@@ -103,7 +103,7 @@ module Beaker
103
103
  check_and_install_packages_if_needed(host, PSWINDOWS_PACKAGES)
104
104
  when host['platform'] =~ /freebsd/
105
105
  check_and_install_packages_if_needed(host, FREEBSD_PACKAGES)
106
- when host['platform'] !~ /debian|aix|solaris|windows|sles-|osx-|cumulus/
106
+ when host['platform'] !~ /debian|aix|solaris|windows|sles-|osx-|cumulus|f5-/
107
107
  check_and_install_packages_if_needed(host, UNIX_PACKAGES)
108
108
  end
109
109
  end
@@ -11,6 +11,7 @@ module Beaker
11
11
  # vendor API.
12
12
  class AwsSdk < Beaker::Hypervisor
13
13
  ZOMBIE = 3 #anything older than 3 hours is considered a zombie
14
+ PING_SECURITY_GROUP_NAME = 'beaker-ping'
14
15
 
15
16
  # Initialize AwsSdk hypervisor driver
16
17
  #
@@ -287,6 +288,8 @@ module Beaker
287
288
  end
288
289
 
289
290
  security_group = ensure_group(vpc || region, Beaker::EC2Helper.amiports(host))
291
+ #check if ping is enabled
292
+ ping_security_group = ensure_ping_group(vpc || region)
290
293
 
291
294
  msg = "aws-sdk: launching %p on %p using %p/%p%s" %
292
295
  [host.name, amitype, amisize, image_type,
@@ -297,7 +300,7 @@ module Beaker
297
300
  :image_id => image_id,
298
301
  :monitoring_enabled => true,
299
302
  :key_pair => ensure_key_pair(region),
300
- :security_groups => [security_group],
303
+ :security_groups => [security_group, ping_security_group],
301
304
  :instance_type => amisize,
302
305
  :disable_api_termination => false,
303
306
  :instance_initiated_shutdown_behavior => "terminate",
@@ -522,13 +525,48 @@ module Beaker
522
525
  # @api private
523
526
  def enable_root(host)
524
527
  if host['user'] != 'root'
525
- copy_ssh_to_root(host, @options)
526
- enable_root_login(host, @options)
527
- host['user'] = 'root'
528
+ if host['platform'] =~ /f5-/
529
+ enable_root_f5(host)
530
+ else
531
+ copy_ssh_to_root(host, @options)
532
+ enable_root_login(host, @options)
533
+ host['user'] = 'root'
534
+ end
528
535
  host.close
529
536
  end
530
537
  end
531
538
 
539
+ # Enables root access for a host on an f5 platform
540
+ # @note This method does not support other platforms
541
+ #
542
+ # @return nil
543
+ # @api private
544
+ def enable_root_f5(host)
545
+ for tries in 1..10
546
+ begin
547
+ #This command is problematic as the F5 is not always done loading
548
+ if host.exec(Command.new("modify sys db systemauth.disablerootlogin value false"), :acceptable_exit_codes => [0,1]).exit_code == 0 \
549
+ and host.exec(Command.new("modify sys global-settings gui-setup disabled"), :acceptable_exit_codes => [0,1]).exit_code == 0 \
550
+ and host.exec(Command.new("save sys config"), :acceptable_exit_codes => [0,1]).exit_code == 0
551
+ backoff_sleep(tries)
552
+ break
553
+ elsif tries == 10
554
+ raise "Instance was unable to be configured"
555
+ end
556
+ rescue Beaker::Host::CommandFailure => e
557
+ @logger.debug("Instance not yet configured (#{e})")
558
+ end
559
+ backoff_sleep(tries)
560
+ end
561
+ host['user'] = 'root'
562
+ host.close
563
+ sha256 = Digest::SHA256.new
564
+ password = sha256.hexdigest((1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&'))
565
+ host['ssh'] = {:password => password}
566
+ host.exec(Command.new("echo -e '#{password}\\n#{password}' | tmsh modify auth password admin"))
567
+ @logger.notify("f5: Configured admin password to be #{password}")
568
+ end
569
+
532
570
  # Set the hostname of all instances to be the hostname defined in the
533
571
  # beaker configuration.
534
572
  #
@@ -629,6 +667,25 @@ module Beaker
629
667
  "Beaker-#{Zlib.crc32(ports.inspect)}"
630
668
  end
631
669
 
670
+ # Return an existing group, or create new one
671
+ #
672
+ # Accepts a VPC as input for checking & creation.
673
+ #
674
+ # @param vpc [AWS::EC2::VPC] the AWS vpc control object
675
+ # @return [AWS::EC2::SecurityGroup] created security group
676
+ # @api private
677
+ def ensure_ping_group(vpc)
678
+ @logger.notify("aws-sdk: Ensure security group exists that enables ping, create if not")
679
+
680
+ group = vpc.security_groups.filter('group-name', PING_SECURITY_GROUP_NAME).first
681
+
682
+ if group.nil?
683
+ group = create_ping_group(vpc)
684
+ end
685
+
686
+ group
687
+ end
688
+
632
689
  # Return an existing group, or create new one
633
690
  #
634
691
  # Accepts a VPC as input for checking & creation.
@@ -650,6 +707,23 @@ module Beaker
650
707
  group
651
708
  end
652
709
 
710
+ # Create a new ping enabled security group
711
+ #
712
+ # Accepts a region or VPC for group creation.
713
+ #
714
+ # @param rv [AWS::EC2::Region, AWS::EC2::VPC] the AWS region or vpc control object
715
+ # @return [AWS::EC2::SecurityGroup] created security group
716
+ # @api private
717
+ def create_ping_group(rv)
718
+ @logger.notify("aws-sdk: Creating group #{PING_SECURITY_GROUP_NAME}")
719
+ group = rv.security_groups.create(PING_SECURITY_GROUP_NAME,
720
+ :description => "Custom Beaker security group to enable ping")
721
+
722
+ group.allow_ping
723
+
724
+ group
725
+ end
726
+
653
727
  # Create a new security group
654
728
  #
655
729
  # Accepts a region or VPC for group creation.
@@ -22,7 +22,33 @@
22
22
 
23
23
  <div class="container-fluid">
24
24
  <div class="page-header">
25
- <h1>Beaker <small>Puppet Labs Automated Acceptance Testing System</small></h1>
25
+ <div class="row">
26
+ <div class="col-md-8">
27
+ <h1>Beaker <small>Puppet Labs Automated Acceptance Testing System</small></h1>
28
+ </div>
29
+ <xsl:variable name="page_active"><xsl:value-of select="meta_test_info/@page_active"/></xsl:variable>
30
+ <xsl:choose>
31
+ <xsl:when test="$page_active != 'no-links'">
32
+ <div class="col-md-2 pull-right">
33
+ <br />
34
+ <ol class="breadcrumb text-center" style="margin-bottom: 0px; margin-top: 20px;">
35
+ <xsl:variable name="link_url"><xsl:value-of select="meta_test_info/@link_url"/></xsl:variable>
36
+ <xsl:choose>
37
+ <xsl:when test="$page_active = 'execution'">
38
+ <li class="active">execution order</li>
39
+ <li><a href="{$link_url}">performance order</a></li>
40
+ </xsl:when>
41
+ <xsl:otherwise>
42
+ <li><a href="{$link_url}">execution order</a></li>
43
+ <li class="active">performance order</li>
44
+ </xsl:otherwise>
45
+ </xsl:choose>
46
+ </ol>
47
+ </div>
48
+ </xsl:when>
49
+ </xsl:choose>
50
+
51
+ </div>
26
52
  </div>
27
53
 
28
54
  <!-- calculate overall stats for this run -->
@@ -230,6 +230,12 @@ module Beaker
230
230
  opts.on '--exclude-tag TAGS', 'Run the set of tests that do not contain ANY of the provided single or command separated list of tags' do |value|
231
231
  @cmd_options[:tag_excludes] = value
232
232
  end
233
+
234
+ opts.on '--xml-time-order',
235
+ 'Output an additional JUnit XML file, sorted by execution time' do |bool|
236
+ @cmd_options[:xml_time_enabled] = bool
237
+ end
238
+
233
239
  end
234
240
 
235
241
  end
@@ -23,6 +23,9 @@ module Beaker
23
23
  :consoleport => ['BEAKER_CONSOLEPORT', 'consoleport'],
24
24
  :is_pe => ['BEAKER_IS_PE', 'IS_PE'],
25
25
  :pe_dir => ['BEAKER_PE_DIR', 'pe_dist_dir'],
26
+ :puppet_agent_version => ['BEAKER_PUPPET_AGENT_VERSION'],
27
+ :puppet_agent_sha => ['BEAKER_PUPPET_AGENT_SHA'],
28
+ :puppet_collection => ['BEAKER_PUPPET_COLLECTION'],
26
29
  :pe_version_file => ['BEAKER_PE_VERSION_FILE', 'pe_version_file'],
27
30
  :pe_ver => ['BEAKER_PE_VER', 'pe_ver'],
28
31
  :forge_host => ['BEAKER_FORGE_HOST', 'forge_host'],
@@ -138,6 +141,8 @@ module Beaker
138
141
  :project_root => File.expand_path(File.join(File.dirname(__FILE__), "../")),
139
142
  :xml_dir => 'junit',
140
143
  :xml_file => 'beaker_junit.xml',
144
+ :xml_time => 'beaker_times.xml',
145
+ :xml_time_enabled => false,
141
146
  :xml_stylesheet => 'junit.xsl',
142
147
  :default_log_prefix => 'beaker_logs',
143
148
  :log_dir => 'log',
@@ -3,7 +3,7 @@ module Beaker
3
3
  # all String methods while adding several platform-specific use cases.
4
4
  class Platform < String
5
5
  # Supported platforms
6
- PLATFORMS = /^(cisco|freebsd|osx|centos|fedora|debian|oracle|redhat|scientific|sles|ubuntu|windows|solaris|aix|el|eos|cumulus)\-.+\-.+$/
6
+ PLATFORMS = /^(cisco|freebsd|osx|centos|fedora|debian|oracle|redhat|scientific|sles|ubuntu|windows|solaris|aix|el|eos|cumulus|f5)\-.+\-.+$/
7
7
 
8
8
  # Platform version numbers vs. codenames conversion hash
9
9
  PLATFORM_VERSION_CODES =
@@ -21,6 +21,11 @@ module Beaker
21
21
  "precise" => "1204",
22
22
  "lucid" => "1004",
23
23
  },
24
+ :osx => { "yosemite" => "10.10",
25
+ "mavericks" => "10.9",
26
+ "1010" => "10.10",
27
+ "109" => "10.9"
28
+ }
24
29
  }
25
30
 
26
31
  # A string with the name of the platform.
@@ -148,12 +148,35 @@ module Beaker
148
148
  @logger.notify " Test Case #{test_case.path} #{test_reported}"
149
149
  end
150
150
 
151
- def write_junit_xml(xml_file)
151
+ # Writes Junit XML of this {TestSuiteResult}
152
+ #
153
+ # @param [String] xml_file Path to the XML file (from Beaker's running directory)
154
+ # @param [String] file_to_link Path to the paired file that should be linked
155
+ # from this one (this is relative to the XML
156
+ # file itself, so it would just be the different
157
+ # file name if they're in the same directory)
158
+ # @param [Boolean] time_sort Whether the test results should be output in
159
+ # order of time spent in the test, or in the
160
+ # order of test execution (default)
161
+ #
162
+ # @return nil
163
+ # @api private
164
+ def write_junit_xml(xml_file, file_to_link = nil, time_sort = false)
152
165
  stylesheet = File.join(@options[:project_root], @options[:xml_stylesheet])
153
166
 
154
167
  begin
155
168
  LoggerJunit.write_xml(xml_file, stylesheet) do |doc, suites|
156
169
 
170
+ meta_info = Nokogiri::XML::Node.new('meta_test_info', doc)
171
+ unless file_to_link.nil?
172
+ meta_info['page_active'] = time_sort ? 'performance' : 'execution'
173
+ meta_info['link_url'] = file_to_link
174
+ else
175
+ meta_info['page_active'] = 'no-links'
176
+ meta_info['link_url'] = ''
177
+ end
178
+ suites.add_child(meta_info)
179
+
157
180
  suite = Nokogiri::XML::Node.new('testsuite', doc)
158
181
  suite['name'] = @name
159
182
  suite['tests'] = test_count
@@ -172,7 +195,9 @@ module Beaker
172
195
  end
173
196
  suite.add_child(properties)
174
197
 
175
- @test_cases.each do |test|
198
+ test_cases_to_report = @test_cases
199
+ test_cases_to_report = @test_cases.sort { |x,y| y.runtime <=> x.runtime } if time_sort
200
+ test_cases_to_report.each do |test|
176
201
  item = Nokogiri::XML::Node.new('testcase', doc)
177
202
  item['classname'] = File.dirname(test.path)
178
203
  item['name'] = File.basename(test.path)
@@ -309,8 +334,15 @@ module Beaker
309
334
  # of the suite – or, at least, making them highly confusing for anyone who
310
335
  # has not studied the implementation in detail. --daniel 2011-03-14
311
336
  @test_suite_results.summarize( Logger.new(log_path("#{name}-summary.txt", @options[:log_dated_dir]), STDOUT) )
312
- @test_suite_results.write_junit_xml( log_path(@options[:xml_file], @options[:xml_dated_dir]) )
313
337
 
338
+ junit_file_log = log_path(@options[:xml_file], @options[:xml_dated_dir])
339
+ if @options[:xml_time_enabled]
340
+ junit_file_time = log_path(@options[:xml_time], @options[:xml_dated_dir])
341
+ @test_suite_results.write_junit_xml( junit_file_log, @options[:xml_time] )
342
+ @test_suite_results.write_junit_xml( junit_file_time, @options[:xml_file], true )
343
+ else
344
+ @test_suite_results.write_junit_xml( junit_file_log )
345
+ end
314
346
  #All done with this run, remove run log
315
347
  @logger.remove_destination(run_log)
316
348
 
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '2.15.1'
3
+ STRING = '2.16.0'
4
4
  end
5
5
  end
@@ -3,12 +3,51 @@ require 'spec_helper'
3
3
  module Beaker
4
4
  describe Answers do
5
5
  let( :basic_hosts ) { make_hosts( { 'pe_ver' => @ver } ) }
6
- let( :options ) { Beaker::Options::Presets.new.presets }
6
+ let( :options ) { @options || Beaker::Options::Presets.new.presets }
7
7
  let( :hosts ) { basic_hosts[0]['roles'] = ['master', 'database', 'dashboard']
8
8
  basic_hosts[1]['platform'] = 'windows'
9
9
  basic_hosts }
10
10
  let( :answers ) { Beaker::Answers.create(@ver, hosts, options) }
11
11
 
12
+ after :each do
13
+ ENV.delete('q_puppet_cloud_install')
14
+ end
15
+
16
+ it 'uses options[:answers] if they are set (override q_puppet_cloud_install for 3.8' do
17
+ @ver = '3.8'
18
+ options[:answers] = Beaker::Options::OptionsHash.new
19
+ options[:answers]['q_puppet_cloud_install'] = 'n'
20
+ opts = answers.instance_variable_get(:@options)
21
+ @answers = answers.answers
22
+ # confirm that the answers were correctly added to the answers object
23
+ expect(opts).to be_a_kind_of Beaker::Options::OptionsHash
24
+ expect(opts[:answers]['q_puppet_cloud_install']).to be == 'n'
25
+ expect(opts[:answers][:q_puppet_cloud_install]).to be == 'n'
26
+ hosts.each do |host|
27
+ if @answers[host.name]
28
+ expect( @answers[host.name][:q_puppet_cloud_install] ).to be == 'n'
29
+ end
30
+ end
31
+ end
32
+
33
+ it 'uses ENV[:q_*] if they are set (override q_puppet_cloud_install for 3.8' do
34
+ @ver = '3.8'
35
+ ENV['q_puppet_cloud_install'] = 'n'
36
+ @options = Beaker::Options::Parser.new.parse_args([])
37
+
38
+ opts = answers.instance_variable_get(:@options)
39
+ @answers = answers.answers
40
+ # confirm that the answers were correctly added to the answers object
41
+ expect(opts).to be_a_kind_of Beaker::Options::OptionsHash
42
+ expect(opts[:answers]['q_puppet_cloud_install']).to be == 'n'
43
+ expect(opts[:answers][:q_puppet_cloud_install]).to be == 'n'
44
+ hosts.each do |host|
45
+ if @answers[host.name]
46
+ expect( @answers[host.name][:q_puppet_cloud_install] ).to be == 'n'
47
+ end
48
+ end
49
+ end
50
+
12
51
  it 'generates 3.4 answers for 4.0 hosts' do
13
52
  @ver = '4.0'
14
53
  expect( answers ).to be_a_kind_of Version34
@@ -208,7 +247,7 @@ module Beaker
208
247
  it 'should add answers to the host objects' do
209
248
  answers = @answers
210
249
  hosts.each do |host|
211
- expect( host[:answers] ).to be === answers[host.name]
250
+ expect( host[:answers] ).to be === @answers[host.name]
212
251
  end
213
252
  end
214
253
  end
@@ -459,9 +498,7 @@ module Beaker
459
498
 
460
499
  def test_answer_customization(answer_key, value_to_set)
461
500
  @ver = '3.0'
462
- if not options[:answers]
463
- options[:answers] = {}
464
- end
501
+ options[:answers] ||= Beaker::Options::OptionsHash.new
465
502
  options[:answers][answer_key] = value_to_set
466
503
  host_answers = answers.answers['vm1']
467
504
  expect( host_answers[answer_key] ).to be === value_to_set