beaker 1.0.0 → 1.0.1.pre

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZWQyZDI5MDhjOTdlYjFmMWM0NmMyNzVjYWYyZTMxMjZkNjViMTk1Mg==
4
+ ODg5ZjNlOGYzYmRlZWViOTc4OWQzYjViYmEzZTdkMDNmZDYzODUxZA==
5
5
  data.tar.gz: !binary |-
6
- ODYxMGI2Y2E3NDc3NTViMzBhYjRhMGNlNDkxNDljMmYyMDcwNmZjYw==
6
+ Mjg2YmJhNDE1OTdlMWE4OTg1YTVkOGVhNTYzMjg1ZGNlYzlmYzdhOQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YmViMDgxMTgwZjQ3NDk5M2NhZDkwYzAwMDA0MDNlMGE4NDA1NDI4YjM4ZTkw
10
- NTFhMDBhMTczMzZmMTgzMmE2YmIxNzlhMDY3MzAyMGVkY2YyMGVmMmU0Njdh
11
- ZThlYWE5NzY2MDZiZTg1ZTk1OTZhZmFiZDcwZTk3ZDdlOGJiYjA=
9
+ MmIwNzlmODFjYjNhMjNkNDU4NTZkOTY1MDdjMTUxODM3YTEyZmMxZGFhNmNj
10
+ ZjgwYTNkYjU3MzQ5Yjk2NTY5OWYxYThmZDZlNjk5Mjg4NWIwYjcyY2E1OGI2
11
+ YWY3NTVjYzU5YzEzZTIyOWJmNjZmNTFjOGQ1NjJkODQ2OTU5YWY=
12
12
  data.tar.gz: !binary |-
13
- ZDFiODE1ZjRlNjkzNDE5ODA4NmUxYmU3MmExZTQ4NDA4MTNjYzg3NjY1MmI3
14
- YWNhYmJmZDcyNjM3ZGRiNDJlOGFmYzNmNTI1YjY5NWIwNDAyMzJhNjMwYjVk
15
- MzUyMmI2YWQ3ODFjNWMyOTRkNjJmOTUwNjBmMDgwMzY5NmI5Mjg=
13
+ ZGFjYzQ0NWRiYzViYjNkNDRlY2JiM2RjM2U2ZDM1MjBmNTYzYzliYTJhMDFk
14
+ Y2U5ODlkMmUyYjRmZjc3MDU5NzAxMTc3YmFhZGEwZmFmYWY2MGQxMjRlZTIx
15
+ M2RhZDdlYThiMmU3MzI5MzVkODBhYWIzMTMxM2IzOWM1YTExYTk=
@@ -1,12 +1,8 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require 'rbconfig'
4
- ruby_conf = defined?(RbConfig) ? RbConfig::CONFIG : Config::CONFIG
5
- less_than_one_nine = ruby_conf['MAJOR'].to_i == 1 && ruby_conf['MINOR'].to_i < 9
6
2
 
7
3
  Gem::Specification.new do |s|
8
4
  s.name = "beaker"
9
- s.version = '1.0.0'
5
+ s.version = '1.0.1.pre'
10
6
  s.authors = ["Puppetlabs"]
11
7
  s.email = ["delivery@puppetlabs.com"]
12
8
  s.homepage = "https://github.com/puppetlabs/beaker"
@@ -23,24 +19,28 @@ Gem::Specification.new do |s|
23
19
  s.add_development_dependency 'rspec', '~> 2.14.0'
24
20
  s.add_development_dependency 'fakefs', '0.4'
25
21
  s.add_development_dependency 'rake'
26
- s.add_development_dependency 'simplecov' unless less_than_one_nine
22
+ s.add_development_dependency 'simplecov' unless RUBY_VERSION < '1.9'
27
23
 
28
24
  # Documentation dependencies
29
25
  s.add_development_dependency 'yard'
30
- s.add_development_dependency 'markdown' unless less_than_one_nine
26
+ s.add_development_dependency 'markdown' unless RUBY_VERSION < '1.9'
31
27
  s.add_development_dependency 'thin'
32
28
 
33
29
  # Run time dependencies
34
- s.add_runtime_dependency 'json'
35
- s.add_runtime_dependency 'net-ssh'
36
- s.add_runtime_dependency 'net-scp'
37
- s.add_runtime_dependency 'rbvmomi'
38
- s.add_runtime_dependency 'blimpy'
30
+ s.add_runtime_dependency 'json', '~> 1.8'
31
+ s.add_runtime_dependency 'net-ssh', '~> 2.6'
32
+ s.add_runtime_dependency 'net-scp', '~> 1.1'
33
+ s.add_runtime_dependency 'inifile', '~> 2.0'
34
+
35
+ # Optional provisioner specific support
36
+ s.add_runtime_dependency 'rbvmomi', '~> 1.6'
37
+ s.add_runtime_dependency 'blimpy', '~> 0.6'
38
+ s.add_runtime_dependency 'fission', '~> 0.4'
39
+
40
+ # These are transitive dependencies that we include or pin to because...
41
+ # Ruby 1.8 compatibility
39
42
  s.add_runtime_dependency 'nokogiri', '1.5.10'
40
- s.add_runtime_dependency 'mime-types', '1.25' if RUBY_VERSION < "1.9"
41
- s.add_runtime_dependency 'fission' if RUBY_PLATFORM =~ /darwin/i
42
- s.add_runtime_dependency 'inifile'
43
- #unf is an 'optional' fog dependency, but it warns when it is missing
44
- # see https://github.com/fog/fog/pull/2320/commits
45
- s.add_runtime_dependency 'unf'
43
+ s.add_runtime_dependency 'mime-types', '~> 1.25' # 2.0 won't install on 1.8
44
+ # So fog doesn't always complain of unmet AWS dependencies
45
+ s.add_runtime_dependency 'unf', '~> 0.1'
46
46
  end
@@ -1,5 +1,15 @@
1
1
  module Beaker
2
2
  class CLI
3
+ GEMSPEC = File.join(File.expand_path(File.dirname(__FILE__)), "../../beaker.gemspec")
4
+ VERSION_STRING =
5
+ " wWWWw
6
+ |o o|
7
+ | O | %s!
8
+ |(\")|
9
+ / \\X/ \\
10
+ | V |
11
+ | | | "
12
+
3
13
  def initialize
4
14
  @options_parser = Beaker::Options::Parser.new
5
15
  @options = @options_parser.parse_args
@@ -10,6 +20,12 @@ module Beaker
10
20
  @logger.notify(@options_parser.usage)
11
21
  exit
12
22
  end
23
+ if @options[:version]
24
+ require 'rubygems' unless defined?(Gem)
25
+ spec = Gem::Specification::load(GEMSPEC)
26
+ @logger.notify(VERSION_STRING % spec.version)
27
+ exit
28
+ end
13
29
  @logger.notify(@options.dump)
14
30
 
15
31
  #add additional paths to the LOAD_PATH
@@ -449,7 +449,11 @@ module Beaker
449
449
  if host.is_pe?
450
450
  bounce_service( host, 'pe-httpd' )
451
451
  else
452
- stop_puppet_from_source_on( host ) if puppet_master_started
452
+ if puppet_master_started
453
+ stop_puppet_from_source_on( host )
454
+ else
455
+ dump_puppet_log(host)
456
+ end
453
457
  end
454
458
 
455
459
  rescue Exception => teardown_exception
@@ -474,22 +478,43 @@ module Beaker
474
478
  # @!visibility private
475
479
  def restore_puppet_conf_from_backup( host, backup_file )
476
480
  puppetpath = host['puppetpath']
481
+ puppet_conf = File.join(puppetpath, "puppet.conf")
482
+
483
+ if backup_file
484
+ host.exec( Command.new( "if [ -f '#{backup_file}' ]; then " +
485
+ "cat '#{backup_file}' > " +
486
+ "'#{puppet_conf}'; " +
487
+ "rm -f '#{backup_file}'; " +
488
+ "fi" ) )
489
+ else
490
+ host.exec( Command.new( "rm -f '#{puppet_conf}'" ))
491
+ end
477
492
 
478
- host.exec( Command.new( "if [ -f '#{backup_file}' ]; then " +
479
- "cat '#{backup_file}' > " +
480
- "'#{puppetpath}/puppet.conf'; " +
481
- "rm -f '#{backup_file}'; " +
482
- "fi" ) )
483
493
  end
484
494
 
495
+ # Back up the given file in the current_dir to the new_dir
496
+ #
485
497
  # @!visibility private
498
+ #
499
+ # @param host [Beaker::Host] The target host
500
+ # @param current_dir [String] The directory containing the file to back up
501
+ # @param new_dir [String] The directory to copy the file to
502
+ # @param filename [String] The file to back up. Defaults to 'puppet.conf'
503
+ #
504
+ # @return [String, nil] The path to the file if the file exists, nil if it
505
+ # doesn't exist.
486
506
  def backup_the_file host, current_dir, new_dir, filename = 'puppet.conf'
507
+
487
508
  old_location = current_dir + '/' + filename
488
509
  new_location = new_dir + '/' + filename + '.bak'
489
510
 
490
- host.exec( Command.new( "cp #{old_location} #{new_location}" ) )
491
-
492
- return new_location
511
+ if host.file_exist? old_location
512
+ host.exec( Command.new( "cp #{old_location} #{new_location}" ) )
513
+ return new_location
514
+ else
515
+ logger.warn "Could not backup file '#{old_location}': no such file"
516
+ nil
517
+ end
493
518
  end
494
519
 
495
520
  # @!visibility private
@@ -498,7 +523,6 @@ module Beaker
498
523
 
499
524
  logger.debug 'Waiting for the puppet master to start'
500
525
  unless port_open_within?( host, 8140, 10 )
501
- dump_puppet_log(host)
502
526
  raise Beaker::DSL::FailTest, 'Puppet master did not start in a timely fashion'
503
527
  end
504
528
  logger.debug 'The puppet master has started'
@@ -515,9 +539,6 @@ module Beaker
515
539
  sleep 1
516
540
  end
517
541
  end
518
- rescue RuntimeError => e
519
- dump_puppet_log host
520
- raise e
521
542
  end
522
543
 
523
544
  # @!visibility private
@@ -834,6 +855,25 @@ module Beaker
834
855
  sign_certificate_for(default)
835
856
  end
836
857
 
858
+ # Get a facter fact from a provided host
859
+ #
860
+ # @param [Host] host The host to query the fact for
861
+ # @param [String] name The name of the fact to query for
862
+ # @!macro common_opts
863
+ #
864
+ # @returns String The value of the fact 'name' on the provided host
865
+ # @raise [FailTest] Raises an exception if call to facter fails
866
+ def fact_on(host, name, opts = {})
867
+ result = on host, facter(name, opts)
868
+ result.stdout.chomp if result.stdout
869
+ end
870
+
871
+ # Get a facter fact from the default host
872
+ # @see #fact_on
873
+ def fact(name, opts = {})
874
+ fact_on(default, name, opts)
875
+ end
876
+
837
877
  end
838
878
  end
839
879
  end
@@ -1,4 +1,5 @@
1
1
  require 'socket'
2
+ require 'timeout'
2
3
 
3
4
  %w(command ssh_connection).each do |lib|
4
5
  begin
@@ -12,6 +13,8 @@ module Beaker
12
13
  class Host
13
14
  SELECT_TIMEOUT = 30
14
15
 
16
+ class CommandFailure < StandardError; end
17
+
15
18
  # This class providers array syntax for using puppet --configprint on a host
16
19
  class PuppetConfigReader
17
20
  def initialize(host, command)
@@ -63,23 +66,14 @@ module Beaker
63
66
  end
64
67
 
65
68
  def port_open? port
66
- s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
67
- sa = Socket.sockaddr_in(port, reachable_name)
68
-
69
69
  begin
70
- s.connect_nonblock(sa)
71
- rescue Errno::EINPROGRESS
72
- if IO.select(nil, [s], nil, SELECT_TIMEOUT)
73
- begin
74
- s.connect_nonblock(sa)
75
- rescue Errno::EISCONN
76
- return true
77
- rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
78
- return false
79
- end
70
+ Timeout.timeout SELECT_TIMEOUT do
71
+ TCPSocket.new(reachable_name, port).close
72
+ return true
80
73
  end
74
+ rescue Errno::ECONNREFUSED, Timeout::Error
75
+ return false
81
76
  end
82
- return false
83
77
  end
84
78
 
85
79
  def up?
@@ -171,7 +165,7 @@ module Beaker
171
165
  # is it necessary to break execution??
172
166
  unless result.exit_code_in?(Array(options[:acceptable_exit_codes] || 0))
173
167
  limit = 10
174
- raise "Host '#{self}' exited with #{result.exit_code} running:\n #{cmdline}\nLast #{limit} lines of output were:\n#{result.formatted_output(limit)}"
168
+ raise CommandFailure, "Host '#{self}' exited with #{result.exit_code} running:\n #{cmdline}\nLast #{limit} lines of output were:\n#{result.formatted_output(limit)}"
175
169
  end
176
170
  end
177
171
  # Danger, so we have to return this result?
@@ -13,4 +13,8 @@ module Unix::File
13
13
  paths.split(':')
14
14
  end
15
15
 
16
+ def file_exist?(path)
17
+ result = exec(Beaker::Command.new("test -e #{path}"), :acceptable_exit_codes => [0, 1])
18
+ result.exit_code == 0
19
+ end
16
20
  end
@@ -1,6 +1,6 @@
1
1
  require 'open3'
2
2
 
3
- module Beaker
3
+ module Beaker
4
4
  class Vagrant < Beaker::Hypervisor
5
5
 
6
6
  # Return a random mac address
@@ -13,7 +13,7 @@ module Beaker
13
13
  def rand_chunk
14
14
  (2 + rand(252)).to_s #don't want a 0, 1, or a 255
15
15
  end
16
-
16
+
17
17
  def randip
18
18
  "10.255.#{rand_chunk}.#{rand_chunk}"
19
19
  end
@@ -21,25 +21,24 @@ module Beaker
21
21
  def make_vfile hosts
22
22
  #HACK HACK HACK - add checks here to ensure that we have box + box_url
23
23
  #generate the VagrantFile
24
- vagrant_file = "Vagrant.configure(\"2\") do |c|\n"
24
+ v_file = "Vagrant.configure(\"2\") do |c|\n"
25
25
  hosts.each do |host|
26
26
  host['ip'] ||= randip #use the existing ip, otherwise default to a random ip
27
- vagrant_file << " c.vm.define '#{host.name}' do |v|\n"
28
- vagrant_file << " v.vm.hostname = '#{host.name}'\n"
29
- vagrant_file << " v.vm.box = '#{host['box']}'\n"
30
- vagrant_file << " v.vm.box_url = '#{host['box_url']}'\n" unless host['box_url'].nil?
31
- vagrant_file << " v.vm.base_mac = '#{randmac}'\n"
32
- vagrant_file << " v.vm.network :private_network, ip: \"#{host['ip'].to_s}\", :netmask => \"255.255.0.0\"\n"
33
- vagrant_file << " end\n"
27
+ v_file << " c.vm.define '#{host.name}' do |v|\n"
28
+ v_file << " v.vm.hostname = '#{host.name}'\n"
29
+ v_file << " v.vm.box = '#{host['box']}'\n"
30
+ v_file << " v.vm.box_url = '#{host['box_url']}'\n" unless host['box_url'].nil?
31
+ v_file << " v.vm.base_mac = '#{randmac}'\n"
32
+ v_file << " v.vm.network :private_network, ip: \"#{host['ip'].to_s}\", :netmask => \"255.255.0.0\"\n"
33
+ v_file << " end\n"
34
34
  @logger.debug "created Vagrantfile for VagrantHost #{host.name}"
35
35
  end
36
- vagrant_file << " c.vm.provider :virtualbox do |vb|\n"
37
- vagrant_file << " vb.customize [\"modifyvm\", :id, \"--memory\", \"1024\"]\n"
38
- vagrant_file << " end\n"
39
- vagrant_file << "end\n"
40
- FileUtils.mkdir_p(@vagrant_path)
41
- File.open(File.expand_path(File.join(@vagrant_path, "Vagrantfile")), 'w') do |f|
42
- f.write(vagrant_file)
36
+ v_file << " c.vm.provider :virtualbox do |vb|\n"
37
+ v_file << " vb.customize [\"modifyvm\", :id, \"--memory\", \"1024\"]\n"
38
+ v_file << " end\n"
39
+ v_file << "end\n"
40
+ File.open(@vagrant_file, 'w') do |f|
41
+ f.write(v_file)
43
42
  end
44
43
  end
45
44
 
@@ -66,13 +65,16 @@ module Beaker
66
65
  def set_ssh_config host, user
67
66
  f = Tempfile.new("#{host.name}")
68
67
  ssh_config = Dir.chdir(@vagrant_path) do
69
- stdin, stdout = Open3.popen3('vagrant', 'ssh-config', host.name)
68
+ stdin, stdout, stderr, wait_thr = Open3.popen3('vagrant', 'ssh-config', host.name)
69
+ if not wait_thr.value.success?
70
+ raise "Failed to 'vagrant ssh-config' for #{host.name}"
71
+ end
70
72
  stdout.read
71
73
  end
72
74
  #replace hostname with ip
73
- ssh_config = ssh_config.gsub(/#{host.name}/, host['ip'])
74
- #set the user
75
- ssh_config = ssh_config.gsub(/User vagrant/, "User #{user}")
75
+ ssh_config = ssh_config.gsub(/#{host.name}/, host['ip']) unless not host['ip']
76
+ #set the user
77
+ ssh_config = ssh_config.gsub(/User vagrant/, "User #{user}")
76
78
  f.write(ssh_config)
77
79
  f.rewind
78
80
  host['ssh'] = {:config => f.path()}
@@ -86,32 +88,37 @@ module Beaker
86
88
  @logger = options[:logger]
87
89
  @temp_files = []
88
90
  @vagrant_hosts = vagrant_hosts
89
- @vagrant_path = File.expand_path(File.join(File.basename(__FILE__), '..', 'vagrant_files', options[:hosts_file]))
91
+ @vagrant_path = File.expand_path(File.join(File.basename(__FILE__), '..', 'vagrant_files', File.basename(options[:hosts_file])))
92
+ FileUtils.mkdir_p(@vagrant_path)
93
+ @vagrant_file = File.expand_path(File.join(@vagrant_path, "Vagrantfile"))
90
94
 
91
95
  end
92
96
 
93
97
  def provision
94
- make_vfile @vagrant_hosts
98
+ if @options[:provision]
99
+ #setting up new vagrant hosts
100
+ #make sure that any old boxes are dead dead dead
101
+ vagrant_cmd("destroy --force") if File.file?(@vagrant_file)
95
102
 
96
- #stop anything currently running, that way vagrant up will re-do networking on existing boxes
97
- vagrant_cmd("halt")
98
- vagrant_cmd("up")
103
+ make_vfile @vagrant_hosts
99
104
 
105
+ vagrant_cmd("up")
106
+ end
100
107
  @logger.debug "configure vagrant boxes (set ssh-config, switch to root user, hack etc/hosts)"
101
108
  @vagrant_hosts.each do |host|
102
109
  default_user = host['user']
103
-
110
+
104
111
  set_ssh_config host, 'vagrant'
105
-
112
+
106
113
  copy_ssh_to_root host
107
114
  #shut down connection, will reconnect on next exec
108
- host.close
115
+ host.close
109
116
 
110
117
  set_ssh_config host, default_user
111
-
112
118
  end
113
119
 
114
120
  hack_etc_hosts @vagrant_hosts
121
+
115
122
  end
116
123
 
117
124
  def cleanup
@@ -121,11 +128,15 @@ module Beaker
121
128
  end
122
129
  @logger.notify "Destroying vagrant boxes"
123
130
  vagrant_cmd("destroy --force")
131
+ FileUtils.rm_rf(@vagrant_path)
124
132
  end
125
133
 
126
134
  def vagrant_cmd(args)
127
135
  Dir.chdir(@vagrant_path) do
128
- system("vagrant #{args}")
136
+ run = system("vagrant #{args}")
137
+ if not run
138
+ raise "Failed to execute vagrant_cmd ( #{args} )"
139
+ end
129
140
  end
130
141
  end
131
142
 
@@ -157,17 +157,19 @@ module Beaker
157
157
  def cleanup
158
158
  @logger.notify "Destroying vCloud boxes"
159
159
  connect_to_vsphere
160
- begin
161
- vm_names = @vcloud_hosts.map {|h| h['vmhostname'] }.compact
162
- if @vcloud_hosts.length != vm_names.length
163
- @logger.warn "Some hosts did not have vmhostname set correctly! This likely means VM provisioning was not successful"
164
- end
165
- vms = @vsphere_helper.find_vms vm_names
160
+
161
+ vm_names = @vcloud_hosts.map {|h| h['vmhostname'] }.compact
162
+ if @vcloud_hosts.length != vm_names.length
163
+ @logger.warn "Some hosts did not have vmhostname set correctly! This likely means VM provisioning was not successful"
164
+ end
165
+ vms = @vsphere_helper.find_vms vm_names
166
+ begin
166
167
  vm_names.each do |name|
167
168
  unless vm = vms[name]
168
- raise "Couldn't find VM #{name} in vSphere!"
169
+ @logger.warn "Unable to cleanup #{name}, couldn't find VM #{name} in vSphere!"
170
+ next
169
171
  end
170
-
172
+
171
173
  if vm.runtime.powerState == 'poweredOn'
172
174
  @logger.notify "Shutting down #{vm.name}"
173
175
  duration = run_and_report_duration do
@@ -175,16 +177,24 @@ module Beaker
175
177
  end
176
178
  @logger.notify "Spent %.2f seconds halting #{vm.name}" % duration
177
179
  end
178
-
180
+
179
181
  duration = run_and_report_duration do
180
182
  vm.Destroy_Task
181
183
  end
182
184
  @logger.notify "Spent %.2f seconds destroying #{vm.name}" % duration
185
+
186
+ end
187
+ rescue RbVmomi::Fault => ex
188
+ if ex.fault.is_a?(RbVmomi::VIM::ManagedObjectNotFound)
189
+ #it's already gone, don't bother trying to delete it
190
+ name = vms.key(ex.fault.obj)
191
+ vms.delete(name)
192
+ vm_names.delete(name)
193
+ @logger.warn "Unable to destroy #{name}, it was not found in vSphere"
194
+ retry
183
195
  end
184
- rescue => e
185
- @vsphere_helper.close
186
- report_and_raise(@logger, e, "Vcloud.cleanup")
187
196
  end
197
+ @vsphere_helper.close
188
198
  end
189
199
 
190
200
  end
@@ -10,6 +10,17 @@ module Beaker
10
10
  class NetworkManager
11
11
  HYPERVISOR_TYPES = ['solaris', 'blimpy', 'vsphere', 'fusion', 'aix', 'vcloud', 'vagrant']
12
12
 
13
+ def provision? options, host
14
+ #provision this box
15
+ # - only if we are running with --provision
16
+ # - only if we have a hypervisor
17
+ # - only if either the specific hosts has no specification or has 'provision' in its config
18
+ # - always if it is a vagrant box (vagrant boxes are always provisioned as they always need ssh key hacking)
19
+ command_line_says = options[:provision]
20
+ host_says = host['hypervisor'] && (host.has_key?('provision') ? host['provision'] : true)
21
+ (command_line_says && host_says) or (host['hypervisor'] =~/vagrant/)
22
+ end
23
+
13
24
  def initialize(options, logger)
14
25
  @logger = logger
15
26
  @options = options
@@ -21,16 +32,11 @@ module Beaker
21
32
  def provision
22
33
  #sort hosts into those to be provisioned and those to use non-provisioned
23
34
  @options['HOSTS'].each_key do |name|
24
- host_info = @options['HOSTS'][name]
25
- #check to see if this host has a hypervisor
26
- hypervisor = host_info['hypervisor']
27
- #provision this box
28
- # - only if we are running with --provision
29
- # - only if we have a hypervisor
30
- # - only if either the specific hosts has no specification or has 'provision' in its config
31
- if @options[:provision] && hypervisor && (host_info.has_key?('provision') ? host_info['provision'] : true) #obey config file provision, defaults to provisioning vms
35
+ host = @options['HOSTS'][name]
36
+ hypervisor = host['hypervisor']
37
+ if provision?(@options, host)
32
38
  raise "Invalid hypervisor: #{hypervisor} (#{name})" unless HYPERVISOR_TYPES.include? hypervisor
33
- @logger.debug "Hypervisor for #{name} is #{host_info['hypervisor'] || 'default' }, and I'm going to use #{hypervisor}"
39
+ @logger.debug "Hypervisor for #{name} is #{hypervisor}"
34
40
  @virtual_machines[hypervisor] = [] unless @virtual_machines[hypervisor]
35
41
  @virtual_machines[hypervisor] << name
36
42
  else #this is a non-provisioned machine, deal with it without hypervisors
@@ -157,6 +157,10 @@ module Beaker
157
157
  @cmd_options[:add_el_extras] = true
158
158
  end
159
159
 
160
+ opts.on('--version', 'Report currently running version of beaker' ) do
161
+ @cmd_options[:version] = true
162
+ end
163
+
160
164
  opts.on '-c', '--config FILE',
161
165
  'DEPRECATED use --hosts' do |file|
162
166
  @cmd_options[:hosts_file] = file
@@ -151,7 +151,7 @@ module Beaker
151
151
  # overwrite defaults with command line and file options
152
152
  @options = @options.merge(cmd_line_and_file_options)
153
153
 
154
- if not @options[:help]
154
+ if not @options[:help] and not @options[:version]
155
155
  #read the hosts file that contains the node configuration and hypervisor info
156
156
  hosts_options = Beaker::Options::HostsFileParser.parse_hosts_file(@options[:hosts_file])
157
157
  # merge in host file vars
@@ -10,7 +10,18 @@ require 'tempfile'
10
10
  require 'benchmark'
11
11
  require 'stringio'
12
12
  require 'rbconfig'
13
+ #include test/unit, but do not allow it to autorun on exit
13
14
  require 'test/unit'
15
+ if defined?(Test::Unit::AutoRunner.need_auto_run?)
16
+ # For test-unit gem >= 2.4.9
17
+ Test::Unit::AutoRunner.need_auto_run = false
18
+ elsif defined?(Test::Unit.run?)
19
+ # For test-unit gem < 2.4.9
20
+ Test::Unit.run = true
21
+ elsif defined?(Test::Unit::Runner)
22
+ # For test/unit bundled in Ruby >= 1.9.3
23
+ Test::Unit::Runner.module_eval("@@stop_auto_run = true")
24
+ end
14
25
 
15
26
  module Beaker
16
27
  # This class represents a single test case. A test case is necessarily
@@ -29,7 +40,6 @@ module Beaker
29
40
  rb_config_class = defined?(RbConfig) ? RbConfig : Config
30
41
  if rb_config_class::CONFIG['MAJOR'].to_i == 1 &&
31
42
  rb_config_class::CONFIG['MINOR'].to_i == 8 then
32
- Test::Unit.run = true
33
43
  # The Exception raised by Ruby's STDLIB's test framework (Ruby 1.8)
34
44
  TEST_EXCEPTION_CLASS = Test::Unit::AssertionFailedError
35
45
  else
@@ -524,6 +524,7 @@ describe ClassMixedWithDSLHelpers do
524
524
  def stub_host_and_subject_to_allow_the_default_testdir_argument_to_be_created
525
525
  subject.instance_variable_set(:@path, test_case_path)
526
526
  host.stub(:tmpdir).and_return(tmpdir_path)
527
+ host.stub(:file_exist?).and_return(true)
527
528
  end
528
529
 
529
530
  before do
@@ -535,6 +536,13 @@ describe ClassMixedWithDSLHelpers do
535
536
  expect { subject.with_puppet_running_on(host, '--foo --bar') }.to raise_error(ArgumentError, /conf_opts must be a Hash. You provided a String: '--foo --bar'/)
536
537
  end
537
538
 
539
+ it 'raises the early_exception if backup_the_file fails' do
540
+ subject.should_receive(:backup_the_file).and_raise(RuntimeError.new('puppet conf backup failed'))
541
+ expect {
542
+ subject.with_puppet_running_on(host, {})
543
+ }.to raise_error(RuntimeError, /puppet conf backup failed/)
544
+ end
545
+
538
546
  describe "with valid arguments" do
539
547
  before do
540
548
  Tempfile.should_receive(:open).with('beaker')
@@ -623,6 +631,12 @@ describe ClassMixedWithDSLHelpers do
623
631
  subject.with_puppet_running_on(host, {})
624
632
  expect(host).to execute_commands_matching(/cat '#{backup_location}' > '#{original_location}'/).once
625
633
  end
634
+
635
+ it "doesn't restore a non-existent file" do
636
+ subject.stub(:backup_the_file)
637
+ subject.with_puppet_running_on(host, {})
638
+ expect(host).to execute_commands_matching(/rm -f '#{original_location}'/)
639
+ end
626
640
  end
627
641
 
628
642
  describe 'handling failures' do
@@ -662,4 +676,23 @@ describe ClassMixedWithDSLHelpers do
662
676
 
663
677
  end
664
678
  end
679
+
680
+ describe '#fact_on' do
681
+ it 'retreives a fact on host(s)' do
682
+ subject.should_receive(:facter).with('osfamily',{}).once
683
+ subject.should_receive(:on).and_return(result)
684
+
685
+ subject.fact_on('host','osfamily')
686
+ end
687
+ end
688
+
689
+ describe '#fact' do
690
+ it 'delegates to #fact_on with the default host' do
691
+ subject.stub(:hosts).and_return(hosts)
692
+ subject.should_receive(:fact_on).with(master,"osfamily",{}).once
693
+
694
+ subject.fact('osfamily')
695
+ end
696
+ end
697
+
665
698
  end
@@ -66,8 +66,12 @@ module Beaker
66
66
  PasswordAuthentication no
67
67
  IdentityFile /home/root/.vagrant.d/insecure_private_key
68
68
  IdentitiesOnly yes")
69
+ wait_thr = OpenStruct.new
70
+ state = mock( 'state' )
71
+ state.stub( :success? ).and_return( true )
72
+ wait_thr.value = state
69
73
 
70
- Open3.stub( :popen3 ).with( 'vagrant', 'ssh-config', host.name ).and_return( [ "", out ])
74
+ Open3.stub( :popen3 ).with( 'vagrant', 'ssh-config', host.name ).and_return( [ "", out, "", wait_thr ])
71
75
 
72
76
  file = double( 'file' )
73
77
  file.stub( :path ).and_return( '/path/sshconfig' )
@@ -82,22 +86,41 @@ module Beaker
82
86
 
83
87
  end
84
88
 
85
- it "can provision a set of hosts" do
89
+ describe "provisioning and cleanup" do
90
+
91
+ before :each do
92
+ FakeFS.activate!
93
+ vagrant.should_receive( :vagrant_cmd ).with( "up" ).once
94
+ @hosts.each do |host|
95
+ host_prev_name = host['user']
96
+ vagrant.should_receive( :set_ssh_config ).with( host, 'vagrant' ).once
97
+ vagrant.should_receive( :copy_ssh_to_root ).with( host ).once
98
+ vagrant.should_receive( :set_ssh_config ).with( host, host_prev_name ).once
99
+ end
100
+ vagrant.should_receive( :hack_etc_hosts ).with( @hosts ).once
101
+ end
86
102
 
87
- vagrant.should_receive( :make_vfile ).with( @hosts ).once
103
+ it "can provision a set of hosts" do
104
+ vagrant.should_receive( :make_vfile ).with( @hosts ).once
105
+ vagrant.should_receive( :vagrant_cmd ).with( "destroy --force" ).never
106
+ vagrant.provision
107
+ end
88
108
 
89
- vagrant.should_receive( :vagrant_cmd ).with( "halt" ).once
90
- vagrant.should_receive( :vagrant_cmd ).with( "up" ).once
91
- @hosts.each do |host|
92
- host_prev_name = host['user']
93
- vagrant.should_receive( :set_ssh_config ).with( host, 'vagrant' ).once
94
- vagrant.should_receive( :copy_ssh_to_root ).with( host ).once
95
- vagrant.should_receive( :set_ssh_config ).with( host, host_prev_name ).once
109
+ it "destroys an existing set of hosts before provisioning" do
110
+ vagrant.make_vfile(@hosts)
111
+ vagrant.should_receive(:vagrant_cmd).with("destroy --force").once
112
+ vagrant.provision
96
113
  end
97
- vagrant.should_receive( :hack_etc_hosts ).with( @hosts ).once
98
114
 
115
+ it "can cleanup" do
116
+ vagrant.should_receive( :vagrant_cmd ).with( "destroy --force" ).once
117
+ FileUtils.should_receive( :rm_rf ).once
118
+
119
+ vagrant.provision
120
+ vagrant.cleanup
121
+
122
+ end
99
123
 
100
- vagrant.provision
101
124
  end
102
125
 
103
126
  end
@@ -6,14 +6,14 @@ module Beaker
6
6
 
7
7
  let(:parser) {Beaker::Options::CommandLineParser.new}
8
8
  let(:test_opts) {["-h", "vcloud.cfg", "--debug", "--tests", "test.rb", "--help"]}
9
- let(:full_opts) {["--hosts", "host.cfg", "--options", "opts_file", "--type", "pe", "--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", "--root-keys", "--keyfile", "../.ssh/id_rsa", "--install", "gitrepopath", "-m", "module", "-q", "--no-xml", "--dry-run", "--no-ntp", "--repo-proxy", "--add-el-extras", "--config", "anotherfile.cfg", "--fail-mode", "fast", "--no-color"]}
9
+ let(:full_opts) {["--hosts", "host.cfg", "--options", "opts_file", "--type", "pe", "--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", "--root-keys", "--keyfile", "../.ssh/id_rsa", "--install", "gitrepopath", "-m", "module", "-q", "--no-xml", "--dry-run", "--no-ntp", "--repo-proxy", "--add-el-extras", "--config", "anotherfile.cfg", "--fail-mode", "fast", "--no-color", "--version"]}
10
10
 
11
11
  it "can correctly read command line input" do
12
12
  expect(parser.parse!(test_opts)).to be === {:hosts_file=>"vcloud.cfg", :debug=>true, :tests=>"test.rb", :help=>true}
13
13
  end
14
14
 
15
15
  it "supports all our command line options" do
16
- expect(parser.parse!(full_opts)).to be === {:hosts_file=>"anotherfile.cfg", :options_file=>"opts_file", :type=>"pe", :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=>true, :root_keys=>true, :keyfile=>"../.ssh/id_rsa", :install=>"gitrepopath", :modules=>"module", :quiet=>true, :xml=>false, :dry_run=>true, :timesync=>false, :repo_proxy=>true, :add_el_extras=>true, :fail_mode=>"fast", :color=>false}
16
+ expect(parser.parse!(full_opts)).to be === {:hosts_file=>"anotherfile.cfg", :options_file=>"opts_file", :type=>"pe", :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=>true, :root_keys=>true, :keyfile=>"../.ssh/id_rsa", :install=>"gitrepopath", :modules=>"module", :quiet=>true, :xml=>false, :dry_run=>true, :timesync=>false, :repo_proxy=>true, :add_el_extras=>true, :fail_mode=>"fast", :color=>false, :version=>true}
17
17
  end
18
18
 
19
19
  it "can produce a usage description" do
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: 1.0.0
4
+ version: 1.0.1.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppetlabs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-12 00:00:00.000000000 Z
11
+ date: 2013-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -112,128 +112,142 @@ dependencies:
112
112
  name: json
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ! '>='
115
+ - - ~>
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: '1.8'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ! '>='
122
+ - - ~>
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: '1.8'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: net-ssh
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ! '>='
129
+ - - ~>
130
130
  - !ruby/object:Gem::Version
131
- version: '0'
131
+ version: '2.6'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ! '>='
136
+ - - ~>
137
137
  - !ruby/object:Gem::Version
138
- version: '0'
138
+ version: '2.6'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: net-scp
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ! '>='
143
+ - - ~>
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: '1.1'
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ! '>='
150
+ - - ~>
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: '1.1'
153
+ - !ruby/object:Gem::Dependency
154
+ name: inifile
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ~>
158
+ - !ruby/object:Gem::Version
159
+ version: '2.0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: '2.0'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: rbvmomi
155
169
  requirement: !ruby/object:Gem::Requirement
156
170
  requirements:
157
- - - ! '>='
171
+ - - ~>
158
172
  - !ruby/object:Gem::Version
159
- version: '0'
173
+ version: '1.6'
160
174
  type: :runtime
161
175
  prerelease: false
162
176
  version_requirements: !ruby/object:Gem::Requirement
163
177
  requirements:
164
- - - ! '>='
178
+ - - ~>
165
179
  - !ruby/object:Gem::Version
166
- version: '0'
180
+ version: '1.6'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: blimpy
169
183
  requirement: !ruby/object:Gem::Requirement
170
184
  requirements:
171
- - - ! '>='
185
+ - - ~>
172
186
  - !ruby/object:Gem::Version
173
- version: '0'
187
+ version: '0.6'
174
188
  type: :runtime
175
189
  prerelease: false
176
190
  version_requirements: !ruby/object:Gem::Requirement
177
191
  requirements:
178
- - - ! '>='
192
+ - - ~>
179
193
  - !ruby/object:Gem::Version
180
- version: '0'
194
+ version: '0.6'
181
195
  - !ruby/object:Gem::Dependency
182
- name: nokogiri
196
+ name: fission
183
197
  requirement: !ruby/object:Gem::Requirement
184
198
  requirements:
185
- - - '='
199
+ - - ~>
186
200
  - !ruby/object:Gem::Version
187
- version: 1.5.10
201
+ version: '0.4'
188
202
  type: :runtime
189
203
  prerelease: false
190
204
  version_requirements: !ruby/object:Gem::Requirement
191
205
  requirements:
192
- - - '='
206
+ - - ~>
193
207
  - !ruby/object:Gem::Version
194
- version: 1.5.10
208
+ version: '0.4'
195
209
  - !ruby/object:Gem::Dependency
196
- name: fission
210
+ name: nokogiri
197
211
  requirement: !ruby/object:Gem::Requirement
198
212
  requirements:
199
- - - ! '>='
213
+ - - '='
200
214
  - !ruby/object:Gem::Version
201
- version: '0'
215
+ version: 1.5.10
202
216
  type: :runtime
203
217
  prerelease: false
204
218
  version_requirements: !ruby/object:Gem::Requirement
205
219
  requirements:
206
- - - ! '>='
220
+ - - '='
207
221
  - !ruby/object:Gem::Version
208
- version: '0'
222
+ version: 1.5.10
209
223
  - !ruby/object:Gem::Dependency
210
- name: inifile
224
+ name: mime-types
211
225
  requirement: !ruby/object:Gem::Requirement
212
226
  requirements:
213
- - - ! '>='
227
+ - - ~>
214
228
  - !ruby/object:Gem::Version
215
- version: '0'
229
+ version: '1.25'
216
230
  type: :runtime
217
231
  prerelease: false
218
232
  version_requirements: !ruby/object:Gem::Requirement
219
233
  requirements:
220
- - - ! '>='
234
+ - - ~>
221
235
  - !ruby/object:Gem::Version
222
- version: '0'
236
+ version: '1.25'
223
237
  - !ruby/object:Gem::Dependency
224
238
  name: unf
225
239
  requirement: !ruby/object:Gem::Requirement
226
240
  requirements:
227
- - - ! '>='
241
+ - - ~>
228
242
  - !ruby/object:Gem::Version
229
- version: '0'
243
+ version: '0.1'
230
244
  type: :runtime
231
245
  prerelease: false
232
246
  version_requirements: !ruby/object:Gem::Requirement
233
247
  requirements:
234
- - - ! '>='
248
+ - - ~>
235
249
  - !ruby/object:Gem::Version
236
- version: '0'
250
+ version: '0.1'
237
251
  description: Puppetlabs accceptance testing harness
238
252
  email:
239
253
  - delivery@puppetlabs.com
@@ -387,9 +401,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
387
401
  version: '0'
388
402
  required_rubygems_version: !ruby/object:Gem::Requirement
389
403
  requirements:
390
- - - ! '>='
404
+ - - ! '>'
391
405
  - !ruby/object:Gem::Version
392
- version: '0'
406
+ version: 1.3.1
393
407
  requirements: []
394
408
  rubyforge_project:
395
409
  rubygems_version: 2.0.6