beaker 2.15.1 → 2.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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