beaker 1.7.0 → 1.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.
@@ -205,6 +205,7 @@ module Beaker
205
205
  else
206
206
  the_answers[h.name] = host_answers(h, master_certname, master, database, dashboard, options)
207
207
  end
208
+ h[:answers] = the_answers[h.name]
208
209
  end
209
210
  return the_answers
210
211
  end
@@ -21,7 +21,9 @@ module Beaker
21
21
  # awesome.
22
22
  the_answers[dashboard.name][:q_upgrade_with_unknown_disk_space] = 'y'
23
23
  end
24
-
24
+ hosts.each do |h|
25
+ h[:answers] = the_answers[h.name]
26
+ end
25
27
  return the_answers
26
28
  end
27
29
  end
@@ -70,7 +70,10 @@ module Beaker
70
70
  # @raise [FailTest] Raises an exception if *command* obviously fails.
71
71
  def on(host, command, opts = {}, &block)
72
72
  unless command.is_a? Command
73
- cmd_opts = opts[:environment] ? { 'ENV' => opts.delete(:environment) } : Hash.new
73
+ cmd_opts = {}
74
+ if opts[:environment]
75
+ cmd_opts['ENV'] = opts[:environment]
76
+ end
74
77
  command = Command.new(command.to_s, [], cmd_opts)
75
78
  end
76
79
  if host.is_a? String or host.is_a? Symbol
@@ -82,7 +85,16 @@ module Beaker
82
85
  @result = host.exec(command, opts)
83
86
 
84
87
  # Also, let additional checking be performed by the caller.
85
- yield self if block_given?
88
+ if block_given?
89
+ case block.arity
90
+ #block with arity of 0, just hand back yourself
91
+ when 0
92
+ yield self
93
+ #block with arity of 1 or greater, hand back the result object
94
+ else
95
+ yield @result
96
+ end
97
+ end
86
98
 
87
99
  return @result
88
100
  end
@@ -453,7 +465,8 @@ module Beaker
453
465
  # @api dsl
454
466
  def with_puppet_running_on host, conf_opts, testdir = host.tmpdir(File.basename(@path)), &block
455
467
  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)
456
- cmdline_args = conf_opts.delete(:__commandline_args__)
468
+ cmdline_args = conf_opts[:__commandline_args__]
469
+ conf_opts = conf_opts.reject { |k,v| k == :__commandline_args__ }
457
470
 
458
471
  begin
459
472
  backup_file = backup_the_file(host, host['puppetpath'], testdir, 'puppet.conf')
@@ -486,6 +499,14 @@ module Beaker
486
499
  end
487
500
 
488
501
  rescue Exception => teardown_exception
502
+ begin
503
+ if !host.is_pe?
504
+ dump_puppet_log(host)
505
+ end
506
+ rescue Exception => dumping_exception
507
+ logger.error("Raised during attempt to dump puppet logs: #{dumping_exception}")
508
+ end
509
+
489
510
  if original_exception
490
511
  logger.error("Raised during attempt to teardown with_puppet_running_on: #{teardown_exception}\n---\n")
491
512
  raise original_exception
@@ -453,10 +453,10 @@ module Beaker
453
453
  hosts.each do |host|
454
454
  host['pe_dir'] ||= options[:pe_dir]
455
455
  if host['platform'] =~ /windows/
456
- host['pe_ver'] = host['pe_ver'] ||
456
+ host['pe_ver'] = host['pe_ver'] || options['pe_ver'] ||
457
457
  Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir], options[:pe_version_file_win])
458
458
  else
459
- host['pe_ver'] = host['pe_ver'] ||
459
+ host['pe_ver'] = host['pe_ver'] || options['pe_ver'] ||
460
460
  Beaker::Options::PEVersionScraper.load_pe_version(host[:pe_dir], options[:pe_version_file])
461
461
  end
462
462
  end
@@ -478,9 +478,11 @@ module Beaker
478
478
  hosts.each do |host|
479
479
  host['pe_dir'] = host['pe_upgrade_dir'] || path
480
480
  if host['platform'] =~ /windows/
481
- host['pe_ver'] = host['pe_upgrade_ver'] || Options::PEVersionScraper.load_pe_version(host['pe_dir'], options[:pe_version_file_win])
481
+ host['pe_ver'] = host['pe_upgrade_ver'] || options['pe_upgrade_ver'] ||
482
+ Options::PEVersionScraper.load_pe_version(host['pe_dir'], options[:pe_version_file_win])
482
483
  else
483
- host['pe_ver'] = host['pe_upgrade_ver'] || Options::PEVersionScraper.load_pe_version(host['pe_dir'], options[:pe_version_file])
484
+ host['pe_ver'] = host['pe_upgrade_ver'] || options['pe_upgrade_ver'] ||
485
+ Options::PEVersionScraper.load_pe_version(host['pe_dir'], options[:pe_version_file])
484
486
  end
485
487
  if version_is_less(host['pe_ver'], '3.0')
486
488
  host['pe_installer'] ||= 'puppet-enterprise-upgrader'
@@ -180,8 +180,7 @@ module Beaker
180
180
  # exit codes at the host level and then raising...
181
181
  # is it necessary to break execution??
182
182
  unless result.exit_code_in?(Array(options[:acceptable_exit_codes] || 0))
183
- limit = 10
184
- raise CommandFailure, "Host '#{self}' exited with #{result.exit_code} running:\n #{cmdline}\nLast #{limit} lines of output were:\n#{result.formatted_output(limit)}"
183
+ raise CommandFailure, "Host '#{self}' exited with #{result.exit_code} running:\n #{cmdline}\nLast #{@options[:trace_limit]} lines of output were:\n#{result.formatted_output(@options[:trace_limit])}"
185
184
  end
186
185
  end
187
186
  # Danger, so we have to return this result?
@@ -11,6 +11,10 @@ module Beaker
11
11
  @logger = options[:logger]
12
12
  @options = options
13
13
  @fusion_hosts = fusion_hosts
14
+ #check preconditions for fusion
15
+ @fusion_hosts.each do |host|
16
+ raise "You must specify a snapshot for Fusion instances, no snapshot defined for #{host.name}!" unless host["snapshot"]
17
+ end
14
18
  @fission = Fission::VM
15
19
  end
16
20
 
@@ -23,10 +27,14 @@ module Beaker
23
27
  vm = @fission.new vm_name
24
28
  raise "Could not find VM '#{vm_name}' for #{host.name}!" unless vm.exists?
25
29
 
26
- available_snapshots = vm.snapshots.data.sort.join(", ")
30
+ vm_snapshots = vm.snapshots.data
31
+ if vm_snapshots.nil? or vm_snapshots.empty?
32
+ raise "No snapshots available for VM #{host.name} (vmname: '#{vm_name}')"
33
+ end
34
+
35
+ available_snapshots = vm_snapshots.sort.join(", ")
27
36
  @logger.notify "Available snapshots for #{host.name}: #{available_snapshots}"
28
37
  snap_name = host["snapshot"]
29
- raise "No snapshot specified for #{host.name}" unless snap_name
30
38
  raise "Could not find snapshot '#{snap_name}' for host #{host.name}!" unless vm.snapshots.data.include? snap_name
31
39
 
32
40
  @logger.notify "Reverting #{host.name} to snapshot '#{snap_name}'"
@@ -55,6 +55,9 @@ module Beaker
55
55
  start = Time.now
56
56
  try = 1
57
57
  @vcloud_hosts.each_with_index do |h, i|
58
+ if not h['template']
59
+ raise ArgumentError, "You must specify a template name for #{h}"
60
+ end
58
61
  if h['template'] =~ /\//
59
62
  templatefolders = h['template'].split('/')
60
63
  h['template'] = templatefolders.pop
@@ -5,14 +5,12 @@ module Beaker
5
5
  #An Object that parses, merges and normalizes all supported Beaker options and arguments
6
6
  class Parser
7
7
  GITREPO = 'git://github.com/puppetlabs'
8
- #These options can have the form of arg1,arg2 or [arg] or just arg,
8
+ #These options can have the form of arg1,arg2 or [arg] or just arg,
9
9
  #should default to []
10
10
  LONG_OPTS = [:helper, :load_path, :tests, :pre_suite, :post_suite, :install, :modules]
11
11
  #These options expand out into an array of .rb files
12
12
  RB_FILE_OPTS = [:tests, :pre_suite, :post_suite]
13
13
 
14
- PLATFORMS = /^(centos|fedora|debian|oracle|redhat|scientific|sles|ubuntu|windows|solaris|aix|el)\-.+\-.+$/
15
-
16
14
  PARSE_ERROR = if RUBY_VERSION > '1.8.7'; then Psych::SyntaxError; else ArgumentError; end
17
15
 
18
16
  #The OptionsHash of all parsed options
@@ -41,7 +39,7 @@ module Beaker
41
39
  # or can become an array of multiple values by splitting arg over ','. If argument is already an
42
40
  # array that array is returned untouched.
43
41
  # @example
44
- # split_arg([1, 2, 3]) == [1, 2, 3]
42
+ # split_arg([1, 2, 3]) == [1, 2, 3]
45
43
  # split_arg(1) == [1]
46
44
  # split_arg("1,2") == ["1", "2"]
47
45
  # split_arg(nil) == []
@@ -71,9 +69,9 @@ module Beaker
71
69
  files = []
72
70
  if not paths.empty?
73
71
  paths.each do |root|
74
- if File.file? root then
72
+ if File.file?(root)
75
73
  files << root
76
- else
74
+ elsif File.directory?(root) #expand and explore
77
75
  discover_files = Dir.glob(
78
76
  File.join(root, "**/*.rb")
79
77
  ).select { |f| File.file?(f) }
@@ -81,6 +79,8 @@ module Beaker
81
79
  parser_error "empty directory used as an option (#{root})!"
82
80
  end
83
81
  files += discover_files.sort
82
+ else #not a file, not a directory, not nothin'
83
+ parser_error "#{root} used as a file option but is not a file or directory!"
84
84
  end
85
85
  end
86
86
  end
@@ -93,9 +93,9 @@ module Beaker
93
93
  #Converts array of paths into array of fully qualified git repo URLS with expanded keywords
94
94
  #
95
95
  #Supports the following keywords
96
- # PUPPET
96
+ # PUPPET
97
97
  # FACTER
98
- # HIERA
98
+ # HIERA
99
99
  # HIERA-PUPPET
100
100
  #@example
101
101
  # opts = ["PUPPET/3.1"]
@@ -142,7 +142,7 @@ module Beaker
142
142
  #NOTE on argument precedence:
143
143
  #
144
144
  # Will use env, then hosts/config file, then command line, then file options
145
- #
145
+ #
146
146
  @options = Beaker::Options::Presets.presets
147
147
  cmd_line_options = @command_line_parser.parse!(args)
148
148
  file_options = Beaker::Options::OptionsFileParser.parse_options_file(cmd_line_options[:options_file])
@@ -150,7 +150,7 @@ module Beaker
150
150
  # overwrite file options with command line options
151
151
  cmd_line_and_file_options = file_options.merge(cmd_line_options)
152
152
  # merge command line and file options with defaults
153
- # overwrite defaults with command line and file options
153
+ # overwrite defaults with command line and file options
154
154
  @options = @options.merge(cmd_line_and_file_options)
155
155
 
156
156
  if not @options[:help] and not @options[:version]
@@ -206,9 +206,7 @@ module Beaker
206
206
  if not @options['HOSTS'][name]['platform']
207
207
  parser_error "Host #{name} does not have a platform specified"
208
208
  else
209
- if not @options['HOSTS'][name]['platform'] =~ PLATFORMS
210
- parser_error "Host #{name} is on unsupported platform #{@options['HOSTS'][name]['platform']}"
211
- end
209
+ @options['HOSTS'][name]['platform'] = Platform.new(@options['HOSTS'][name]['platform'])
212
210
  end
213
211
  end
214
212
 
@@ -231,8 +229,8 @@ module Beaker
231
229
  else
232
230
  @options[opt] = []
233
231
  end
234
- end
235
-
232
+ end
233
+
236
234
  #check for valid type
237
235
  if @options[:type] !~ /(pe)|(git)|(foss)/
238
236
  parser_error "--type must be one of pe, git, or foss, not '#{@options[:type]}'"
@@ -240,7 +238,7 @@ module Beaker
240
238
 
241
239
  #check for valid fail mode
242
240
  if @options[:fail_mode] !~ /stop|fast|slow/
243
- parser_error "--fail-mode must be one of fast or slow, not '#{@options[:fail_mode]}'"
241
+ parser_error "--fail-mode must be one of fast or slow, not '#{@options[:fail_mode]}'"
244
242
  end
245
243
 
246
244
  #check for valid preserve_hosts option
@@ -249,8 +247,8 @@ module Beaker
249
247
  end
250
248
 
251
249
  #check for config files necessary for different hypervisors
252
- hypervisors = []
253
- @options[:HOSTS].each_key do |name|
250
+ hypervisors = []
251
+ @options[:HOSTS].each_key do |name|
254
252
  hypervisors << @options[:HOSTS][name][:hypervisor].to_s
255
253
  end
256
254
  hypervisors.uniq!
@@ -266,7 +264,7 @@ module Beaker
266
264
  #check that roles of hosts make sense
267
265
  # - must be one and only one master
268
266
  roles = []
269
- @options[:HOSTS].each_key do |name|
267
+ @options[:HOSTS].each_key do |name|
270
268
  roles << @options[:HOSTS][name][:roles]
271
269
  end
272
270
  master = 0
@@ -299,8 +297,8 @@ module Beaker
299
297
  # @api private
300
298
  def test_host_roles(host_name, host_hash)
301
299
  host_roles = host_hash[:roles]
302
- if (host_roles - ['agent']).size != 0
303
- parser_error "#{host_hash[:platform].to_s} box '#{host_name}' can only have role 'agent', has roles #{host_roles.to_s}"
300
+ if !(host_roles & ['master', 'database', 'dashboard']).empty?
301
+ parser_error "#{host_hash[:platform].to_s} box '#{host_name}' may not have roles 'master', 'dashboard', or 'database'; it has roles #{host_roles.to_s}"
304
302
  end
305
303
  end
306
304
 
@@ -8,7 +8,7 @@ module Beaker
8
8
  #
9
9
  # Currently supports:
10
10
  #
11
- # consoleport, IS_PE, pe_dist_dir, pe_version_file, pe_version_file_win
11
+ # consoleport, IS_PE, pe_dist_dir, pe_version_file, pe_version_file_win, pe_ver
12
12
  #
13
13
  # @return [OptionsHash] The supported environment variables in an OptionsHash,
14
14
  # empty or nil environment variables are removed from the OptionsHash
@@ -20,6 +20,7 @@ module Beaker
20
20
  :pe_dir => ENV['pe_dist_dir'],
21
21
  :pe_version_file => ENV['pe_version_file'],
22
22
  :pe_version_file_win => ENV['pe_version_file'],
23
+ :pe_ver => ENV['pe_ver']
23
24
  }.delete_if {|key, value| value.nil? or value.empty? })
24
25
  end
25
26
 
@@ -30,6 +31,7 @@ module Beaker
30
31
  h = Beaker::Options::OptionsHash.new
31
32
  h.merge({
32
33
  :log_level => 'verbose',
34
+ :trace_limit => 10,
33
35
  :hosts_file => 'sample.cfg',
34
36
  :options_file => nil,
35
37
  :type => 'pe',
@@ -0,0 +1,59 @@
1
+ module Beaker
2
+ class Platform < String
3
+ #supported platforms
4
+ PLATFORMS = /^(centos|fedora|debian|oracle|redhat|scientific|sles|ubuntu|windows|solaris|aix|el)\-.+\-.+$/
5
+
6
+ PLATFORM_VERSION_CODES =
7
+ { :debian => { "wheezy" => "7",
8
+ "squeeze" => "6",
9
+ },
10
+ :ubuntu => { "trusty" => "1404",
11
+ "saucy" => "1310",
12
+ "raring" => "1304",
13
+ "quantal" => "1210",
14
+ "precise" => "1204",
15
+ },
16
+ }
17
+
18
+ def initialize(name)
19
+ if name !~ PLATFORMS
20
+ raise ArgumentError, "Unsupported platform name #{name}"
21
+ end
22
+ super
23
+ end
24
+
25
+ def with_version_codename
26
+ name, version, extra = self.split('-', 3)
27
+ PLATFORM_VERSION_CODES.each_key do |platform|
28
+ if name =~ /#{platform}/
29
+ PLATFORM_VERSION_CODES[platform].each do |version_codename, version_number|
30
+ #remove '.' from version number
31
+ if version.delete('.') =~ /#{version_number}/
32
+ version = version_codename
33
+ break
34
+ end
35
+ end
36
+ break
37
+ end
38
+ end
39
+ [name, version, extra].join('-')
40
+ end
41
+
42
+ def with_version_number
43
+ name, version, extra = self.split('-', 3)
44
+ PLATFORM_VERSION_CODES.each_key do |platform|
45
+ if name =~ /#{platform}/
46
+ PLATFORM_VERSION_CODES[platform].each do |version_codename, version_number|
47
+ if version =~ /#{version_codename}/
48
+ version = version_number
49
+ break
50
+ end
51
+ end
52
+ break
53
+ end
54
+ end
55
+ [name, version, extra].join('-')
56
+ end
57
+
58
+ end
59
+ end
@@ -174,6 +174,7 @@ module Beaker
174
174
  # Net::Scp always returns 0, so just set the return code to 0.
175
175
  result.exit_code = 0
176
176
 
177
+ result.finalize!
177
178
  return result
178
179
  end
179
180
 
@@ -192,6 +193,7 @@ module Beaker
192
193
  # Net::Scp always returns 0, so just set the return code to 0.
193
194
  result.exit_code = 0
194
195
 
196
+ result.finalize!
195
197
  result
196
198
  end
197
199
  end
@@ -2,6 +2,8 @@ module Beaker
2
2
  module Utils
3
3
  class NTPControl
4
4
  NTPSERVER = 'pool.ntp.org'
5
+ SLEEPWAIT = 5
6
+ TRIES = 5
5
7
  def initialize(options, hosts)
6
8
  @options = options.dup
7
9
  @hosts = hosts
@@ -12,31 +14,44 @@ module Beaker
12
14
  @logger.notify "Update system time sync"
13
15
  @logger.notify "run ntpdate against NTP pool systems"
14
16
  @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'
17
+ if host['platform'].include? 'windows'
19
18
  # The exit code of 5 is for Windows 2008 systems where the w32tm /register command
20
19
  # is not actually necessary.
21
20
  host.exec(Command.new("w32tm /register"), :acceptable_exit_codes => [0,5])
22
21
  host.exec(Command.new("net start w32time"), :acceptable_exit_codes => [0,2])
23
22
  host.exec(Command.new("w32tm /config /manualpeerlist:#{NTPSERVER} /syncfromflags:manual /update"))
24
23
  host.exec(Command.new("w32tm /resync"))
24
+ @logger.notify "NTP date succeeded on #{host}"
25
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
26
+ case
27
+ when host['platform'] =~ /solaris-10/
28
+ ntp_command = "sleep 10 && ntpdate -w #{NTPSERVER}"
29
+ when host['platform'] =~ /sles-/
30
+ ntp_command = "sntp #{NTPSERVER}"
31
+ else
32
+ ntp_command = "ntpdate -t 20 #{NTPSERVER}"
33
+ end
34
+ success=false
35
+ try = 0
36
+ until try >= TRIES do
37
+ try += 1
38
+ if host.exec(Command.new(ntp_command), :acceptable_exit_codes => (0..255)).exit_code == 0
39
+ success=true
40
+ break
32
41
  end
42
+ sleep SLEEPWAIT
43
+ end
44
+ if success
45
+ @logger.notify "NTP date succeeded on #{host} after #{try} tries"
46
+ else
47
+ raise "NTP date was not successful after #{try} tries"
33
48
  end
34
- @logger.notify "NTP date succeeded after #{count} tries"
35
49
  end
36
50
  end
37
51
  rescue => e
38
52
  report_and_raise(@logger, e, "timesync (--ntp)")
39
53
  end
54
+
40
55
  end
41
56
  end
42
57
  end