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 +8 -8
- data/beaker.gemspec +18 -18
- data/lib/beaker/cli.rb +16 -0
- data/lib/beaker/dsl/helpers.rb +53 -13
- data/lib/beaker/host.rb +9 -15
- data/lib/beaker/host/unix/file.rb +4 -0
- data/lib/beaker/hypervisor/vagrant.rb +42 -31
- data/lib/beaker/hypervisor/vcloud.rb +22 -12
- data/lib/beaker/network_manager.rb +15 -9
- data/lib/beaker/options/command_line_parser.rb +4 -0
- data/lib/beaker/options/parser.rb +1 -1
- data/lib/beaker/test_case.rb +11 -1
- data/spec/beaker/dsl/helpers_spec.rb +33 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +35 -12
- data/spec/beaker/options/command_line_parser_spec.rb +2 -2
- metadata +57 -43
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ODg5ZjNlOGYzYmRlZWViOTc4OWQzYjViYmEzZTdkMDNmZDYzODUxZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Mjg2YmJhNDE1OTdlMWE4OTg1YTVkOGVhNTYzMjg1ZGNlYzlmYzdhOQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MmIwNzlmODFjYjNhMjNkNDU4NTZkOTY1MDdjMTUxODM3YTEyZmMxZGFhNmNj
|
10
|
+
ZjgwYTNkYjU3MzQ5Yjk2NTY5OWYxYThmZDZlNjk5Mjg4NWIwYjcyY2E1OGI2
|
11
|
+
YWY3NTVjYzU5YzEzZTIyOWJmNjZmNTFjOGQ1NjJkODQ2OTU5YWY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZGFjYzQ0NWRiYzViYjNkNDRlY2JiM2RjM2U2ZDM1MjBmNTYzYzliYTJhMDFk
|
14
|
+
Y2U5ODlkMmUyYjRmZjc3MDU5NzAxMTc3YmFhZGEwZmFmYWY2MGQxMjRlZTIx
|
15
|
+
M2RhZDdlYThiMmU3MzI5MzVkODBhYWIzMTMxM2IzOWM1YTExYTk=
|
data/beaker.gemspec
CHANGED
@@ -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.
|
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
|
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
|
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 '
|
38
|
-
|
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'
|
41
|
-
|
42
|
-
s.add_runtime_dependency '
|
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
|
data/lib/beaker/cli.rb
CHANGED
@@ -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
|
data/lib/beaker/dsl/helpers.rb
CHANGED
@@ -449,7 +449,11 @@ module Beaker
|
|
449
449
|
if host.is_pe?
|
450
450
|
bounce_service( host, 'pe-httpd' )
|
451
451
|
else
|
452
|
-
|
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.
|
491
|
-
|
492
|
-
|
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
|
data/lib/beaker/host.rb
CHANGED
@@ -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
|
-
|
71
|
-
|
72
|
-
|
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?
|
@@ -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
|
-
|
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
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 #{
|
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
|
data/lib/beaker/test_case.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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.
|
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-
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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:
|
196
|
+
name: fission
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
184
198
|
requirements:
|
185
|
-
- -
|
199
|
+
- - ~>
|
186
200
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
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:
|
208
|
+
version: '0.4'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
|
-
name:
|
210
|
+
name: nokogiri
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
198
212
|
requirements:
|
199
|
-
- -
|
213
|
+
- - '='
|
200
214
|
- !ruby/object:Gem::Version
|
201
|
-
version:
|
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:
|
222
|
+
version: 1.5.10
|
209
223
|
- !ruby/object:Gem::Dependency
|
210
|
-
name:
|
224
|
+
name: mime-types
|
211
225
|
requirement: !ruby/object:Gem::Requirement
|
212
226
|
requirements:
|
213
|
-
- -
|
227
|
+
- - ~>
|
214
228
|
- !ruby/object:Gem::Version
|
215
|
-
version: '
|
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: '
|
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:
|
406
|
+
version: 1.3.1
|
393
407
|
requirements: []
|
394
408
|
rubyforge_project:
|
395
409
|
rubygems_version: 2.0.6
|