rspec-system 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,6 @@ Gemfile.lock
3
3
  .*.swp
4
4
  doc/
5
5
  .yardoc
6
+ vendor/
7
+ .bundle
8
+ spec/reports/
data/.nodeset.yml CHANGED
@@ -53,3 +53,10 @@ sets:
53
53
  nodes:
54
54
  "main":
55
55
  prefab: 'sles-11sp1-x64'
56
+ 'centos-64-x64-multi':
57
+ default_node: 'first'
58
+ nodes:
59
+ "first":
60
+ prefab: 'centos-64-x64'
61
+ "second":
62
+ prefab: 'centos-64-x64'
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gemspec
5
5
  group :development, :test do
6
6
  gem 'rake'
7
7
  gem 'mocha', :require => 'mocha/api'
8
+ gem 'ci_reporter'
8
9
  end
9
10
 
10
11
  group :development do
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  The goal here is to provide facilities to aid in the launching of tests nodes, copying of test content to such nodes, and executing commands on such nodes to be tested with standard rspec assertions within the standard rspec test format.
6
6
 
7
- *Note:* This library is fairly alpha at the moment, and the interface may change at without warning. That said, if you're good at ruby and have an opinion, I'd appreciate patches and improvements to move this further torwards stability.
7
+ *Note:* This library is fairly new at the moment, so your mileage may vary. That said, if you're good at ruby and have an opinion, I'd appreciate patches and improvements to move this further torwards stability.
8
8
 
9
9
  ### Gem installation
10
10
 
@@ -20,7 +20,7 @@ However it is usually recommended to include it in your `Gemfile` and let bundle
20
20
 
21
21
  Then installing with:
22
22
 
23
- bundle install
23
+ bundle install --path vendor
24
24
 
25
25
  ### Writing tests
26
26
 
@@ -36,7 +36,7 @@ Start by creating a helper file in `spec/spec_helper_system.rb` containing somet
36
36
  end
37
37
  end
38
38
 
39
- Create the directory `spec/system` in your project, make sure your unit tests go into `spec/unit` or somesuch so you can isolate them easily during test time. Add files with the spec prefix ie. `mytests_spec.rb` and make sure they always include the line `require 'spec_helper_system'` eg.:
39
+ Create the directory `spec/system` in your project, its recommended to make sure your unit tests go into `spec/unit` instead so you can isolate them easily during test time. Add files with the spec prefix ie. `mytests_spec.rb` and make sure they always include the line `require 'spec_helper_system'` eg.:
40
40
 
41
41
  require 'spec_helper_system'
42
42
 
@@ -48,18 +48,18 @@ Create the directory `spec/system` in your project, make sure your unit tests go
48
48
  end
49
49
  end
50
50
 
51
- Also consult the example in `example` in the source of this library for more details.
51
+ Also consult the examples in the `examples` directory in the source of this library for more details.
52
52
 
53
- For you reference, here are the list of custom rspec configuration items that can be overriden in your `spec_helper_system.rb` file:
53
+ For your reference, here are the list of custom rspec configuration items that can be overriden in your `spec_helper_system.rb` file:
54
54
 
55
55
  * *system_setup_block* - this accepts a proc that is called after node setup, but before every test (ie. before suite). The goal of this option is to provide a good place for node setup independant of tests.
56
56
  * *system_tmp* - For some of our activity, we require a temporary file area. By default we just a random temporary path, so you normally do not need to set this.
57
57
 
58
- Currently to get the nice formatting rspec-system specific formatter its recommended to use the Rake task, so the following to your `Rakefile`:
58
+ Currently to get the nice formatting rspec-system specific formatter its recommended to use the Rake task, so add the following to your `Rakefile`:
59
59
 
60
60
  require 'rspec-system/rake_task'
61
61
 
62
- That will setup the rake task `rake spec:system`.
62
+ That will setup the `spec:system` rake task.
63
63
 
64
64
  ### Creating a nodeset file
65
65
 
@@ -98,21 +98,62 @@ For this reason there are various `provider_specific` settings that apply to dif
98
98
 
99
99
  ### Running tests
100
100
 
101
- Run the system tests with:
101
+ There are two providers at the moment you can use to launch your nodes for testing:
102
+
103
+ * Vagrant: for the local desktop to run during development and debugging mainly
104
+ * VSphere: for CI systems such as Jenkins
105
+
106
+ Although both systems can be used for either purpose, if you so desire.
107
+
108
+ #### Vagrant Provider
109
+
110
+ This is the default provider, as all the products for this provider are free, most people should be able to run it.
111
+
112
+ Make sure you have already installed:
113
+
114
+ * VirtualBox 4.2.10+
115
+ * Vagrant 1.2.x+
116
+
117
+ Once these are ready, you can Run the system tests with:
102
118
 
103
119
  rake spec:system
104
120
 
121
+ The VM's should be downloaded from the internet, started and tests should run.
122
+
105
123
  Instead of switches, we use a number of environment variables to modify the behaviour of running tests. This is more inline with the way testing frameworks like Jenkins work, and should be pretty easy for command line users as well:
106
124
 
107
- * *RSPEC_VIRTUAL_ENV* - the type of virtual environment to run (currently `vagrant` is the only option). I'm undecided about this variable, so assume it might change in the future.
125
+ * *RSPEC_VIRTUAL_ENV* - set this to `vagrant` if you wish, for now `vagrant` is the default so this is optional.
108
126
  * *RSPEC_SET* - the set to use when running tests (defaults to the `default_set` setting in the projects `.nodeset.yml` file). This string must align with the entries under `sets` in your `.nodeset.yml`.
109
127
 
110
128
  So if you wanted to run an alternate nodeset you could use:
111
129
 
112
- RSPEC_SET=nodeset2 rake spec:system
130
+ RSPEC_SET=fedora18 rake spec:system
113
131
 
114
132
  In Jenkins you should be able to use RSPEC\_SET in a test matrix, thus obtaining quite a nice integration and visual display of nodesets in Jenkins.
115
133
 
134
+ #### VSphere Provider
135
+
136
+ *Note:* this provider requires some templates to be created in a globally accessable folder somewhere in your VSphere system, in the near future the site: <http://puppet-vagrant-boxes.puppetlabs.com> should provide you with deployable OVF files for this purpose, and I'll provide you with better docs on how to load these ;-). Look at prefabs.yml for the names of the templates that we expect.
137
+
138
+ This provider will launch nodes using VMWare VSphere API's and use those for running tests. This provider is really aimed at the users who want to use this library within their own CI system for example, as apposed to developers who wish to run tests locally themselves.
139
+
140
+ This provider has a lot more options for setup, in the form of environment variables:
141
+
142
+ * *RSPEC_VIRTUAL_ENV* - set this to 'vsphere' to use this provider
143
+ * *RSPEC_SET* - same as the vagrant provider, this defines the 'set' to launch.
144
+ * *RSPEC_VSPHERE_HOST* - hostname of your vsphere api
145
+ * *RSPEC_VSPHERE_USER* - username to authenticate with
146
+ * *RSPEC_VSPHERE_PASS* - password to authenticate with
147
+ * *RSPEC_VSPHERE_DEST_DIR* - destination path to launch vm's
148
+ * *RSPEC_VSPHERE_TEMPLATE_DIR* - path to where you deployed the templates from the OVF files described above
149
+ * *RSPEC_VSPHERE_RPOOL* - name of resource pool to use
150
+
151
+ Set these variables, and run the usual rake command:
152
+
153
+ rake spec:system
154
+
155
+ In Jenkins, set the authentication variables above using environment variable injection. I recommend using the private environment variables feature for user & pass however so these do not get displayed in the console output. As with the vagrant provider however, turn RSPEC\_SET into a test matrix, containing all the sets you want to test against.
156
+
116
157
  ### Plugins to rspec-system
117
158
 
118
159
  Right now we have two types of plugins, the framework is in a state of flux as to how one writes these things but here we go.
@@ -121,13 +162,13 @@ Right now we have two types of plugins, the framework is in a state of flux as t
121
162
 
122
163
  Libraries that provide test helpers, and setup helpers for testing development on the software in question.
123
164
 
124
- * rspec-system-puppet <http://rubygems.org/gems/rspec-system-puppet>
165
+ * [rspec-system-puppet](http://rubygems.org/gems/rspec-system-puppet)
125
166
 
126
167
  #### Node providers
127
168
 
128
- A node provider should provide the ability to launch nodes (or if they are already launched provide information to get to them), run commands on nodes, transfer files and shutdown nodes.
169
+ A node provider should provide the ability to launch nodes (or if they are already launched provide information to get to them), run commands on nodes, transfer files and shutdown nodes. That is, abstractions around other virtualisation, cloud or system tools.
129
170
 
130
- That is, abstractions around other virtualisation, cloud or system tools. Right now we only have one of these for Vagrant using VirtualBox specifically and its in core.
171
+ Right now the two options are: vagrant & vsphere and these are installed with core. In the future we probably want to split these out to plugins, but the plugin system isn't quite ready for that yet.
131
172
 
132
173
  #### The Future of Plugins
133
174
 
@@ -145,13 +186,13 @@ I want to start an eco-system of plugins for rspec-system, but do it in a sane w
145
186
  * other config management tools - for the purposes of testing modules against them, or using them for test setup provisioners like I've mentioned before with Puppet.
146
187
  * others I'm sure ...
147
188
 
148
- These could be shipped as external gems, and plugged in to the rspec-system framework somehow. Ideas on how to do this properly are very welcome, if you bring code as well :-).
189
+ These could be shipped as external gems, and plugged in to the rspec-system framework somehow. Ideas on how to do this properly are very welcome, especially if you bring code as well :-).
149
190
 
150
191
  ### CI Integration
151
192
 
152
193
  So currently I've only integrated this with Jenkins. If you have luck doing it on other CI platforms, feel free to add to this documentation.
153
194
 
154
- #### Jenkins
195
+ #### Jenkins and the Vagrant provider
155
196
 
156
197
  My setup was:
157
198
 
@@ -171,13 +212,39 @@ The setup for a job is basically:
171
212
  * Use touchstone with a filter of RSPEC_SET=='centos-64-x64' so you don't chew up cycles running a whole batch of broken builds
172
213
  * Create an execute shell job like so:
173
214
 
174
- #!/bin/bash
175
- set +e
215
+ #!/bin/bash
216
+ set +e
217
+
218
+ [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
219
+ rvm use ruby-2.0.0@some_unique_name_here --create
220
+
221
+ bundle update
222
+ rake spec:system
176
223
 
177
- [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
178
- rvm use ruby-2.0.0@some_unique_name_here --create
224
+ I went quite complex and had Github pull request integration working with this, and quite a few other nice features. If you need help setting it up get in touch.
179
225
 
180
- bundle update
181
- rake spec:system
226
+ #### Jenkins and the VSphere provider
182
227
 
183
- I went quite complex and had Github pull request integration working with this, and quite a few other nice features. If you need help setting it up get in touch.
228
+ My setup was:
229
+
230
+ * Debian 7
231
+ * Jenkins 1.510
232
+ * VSphere 5.1 'cloud'
233
+
234
+ The setup for a job is basically:
235
+
236
+ * Create new matrix build
237
+ * Specify VCS settings etc. as per normal
238
+ * Create a user defined axis called 'RSPEC\_SET' and add your nodesets in there: fedora-18-x64, centos-64-x64 etc.
239
+ * Use the enviornment injection facility to add all the other RSPEC\_VSPHERE vars as above
240
+ * Use touchstone with a filter of RSPEC\_SET=='centos-64-x64' so you don't chew up cycles running a whole batch of broken builds
241
+ * Create an execute shell job like so:
242
+
243
+ #!/bin/bash
244
+ set +e
245
+ [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
246
+ rvm use ruby-2.0.0
247
+ bundle install --vendor
248
+ bundle exec rake spec:system
249
+
250
+ Basically the results were quite nice, as apposed to the 'vagrant' provider I was able to achieve running parallel jobs using my matrix setup.
data/Rakefile CHANGED
@@ -6,6 +6,11 @@ Bundler.require :default
6
6
  require 'rspec/core/rake_task'
7
7
  require 'rspec-system/rake_task'
8
8
 
9
+ begin
10
+ require 'ci/reporter/rake/rspec'
11
+ rescue LoadError
12
+ end
13
+
9
14
  RSpec::Core::RakeTask.new(:spec) do |t|
10
15
  t.pattern = "spec/unit/**/*_spec.rb"
11
16
  end
@@ -1,7 +1,7 @@
1
1
  ---
2
- default_set: 'centos-58-x64'
2
+ default_set: 'centos-59-x64'
3
3
  sets:
4
- 'centos-58-x64':
4
+ 'centos-59-x64':
5
5
  nodes:
6
6
  "main":
7
- prefab: 'centos-58-x64'
7
+ prefab: 'centos-59-x64'
@@ -2,10 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  describe "test1" do
4
4
  it 'run test1 - part1' do
5
- run_on('main', "cat /etc/resolv.conf")
5
+ system_run("cat /etc/resolv.conf")
6
6
  end
7
7
 
8
8
  it 'run test1 - part2' do
9
- run_on('main', "cat /etc/issue")
9
+ system_run("cat /etc/issue")
10
10
  end
11
11
  end
@@ -9,6 +9,8 @@ module RSpecSystem
9
9
  case(virtual_env)
10
10
  when 'vagrant'
11
11
  RSpecSystem::NodeSet::Vagrant.new(setname, config)
12
+ when 'vsphere'
13
+ RSpecSystem::NodeSet::Vsphere.new(setname, config)
12
14
  else
13
15
  raise "Unsupported virtual environment #{virtual_env}"
14
16
  end
@@ -18,3 +20,4 @@ end
18
20
 
19
21
  require 'rspec-system/node_set/base'
20
22
  require 'rspec-system/node_set/vagrant'
23
+ require 'rspec-system/node_set/vsphere'
@@ -60,5 +60,79 @@ module RSpecSystem
60
60
  return nodes[dn]
61
61
  end
62
62
  end
63
+
64
+ # Return a random string of chars, used for temp dir creation
65
+ #
66
+ # @return [String] string of 50 random characters A-Z and a-z
67
+ def random_string(length = 50)
68
+ o = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten
69
+ (0...length).map{ o[rand(o.length)] }.join
70
+ end
71
+
72
+ # Generates a random string for use in remote transfers.
73
+ #
74
+ # @return [String] a random path
75
+ # @todo Very Linux dependant, probably need to consider OS X and Windows at
76
+ # least.
77
+ def tmppath
78
+ '/tmp/' + random_string
79
+ end
80
+
81
+ # Execute command via SSH.
82
+ #
83
+ # A special version of exec! from Net::SSH that returns exit code and exit
84
+ # signal as well. This method is blocking.
85
+ #
86
+ # @param ssh [Net::SSH::Connection::Session] an active ssh session
87
+ # @param command [String] command to execute
88
+ # @return [Hash] a hash of results
89
+ def ssh_exec!(ssh, command)
90
+ r = {
91
+ :stdout => '',
92
+ :stderr => '',
93
+ :exit_code => nil,
94
+ :exit_signal => nil,
95
+ }
96
+ ssh.open_channel do |channel|
97
+ channel.exec(command) do |ch, success|
98
+ unless success
99
+ abort "FAILED: couldn't execute command (ssh.channel.exec)"
100
+ end
101
+ channel.on_data do |ch,data|
102
+ d = data
103
+ print d
104
+ r[:stdout]+=d
105
+ end
106
+
107
+ channel.on_extended_data do |ch,type,data|
108
+ d = data
109
+ print d
110
+ r[:stderr]+=d
111
+ end
112
+
113
+ channel.on_request("exit-status") do |ch,data|
114
+ c = data.read_long
115
+ puts "Exit code: #{c}"
116
+ r[:exit_code] = c
117
+ end
118
+
119
+ channel.on_request("exit-signal") do |ch, data|
120
+ s = data.read_string
121
+ puts "Exit signal: #{s}"
122
+ r[:exit_signal] = s
123
+ end
124
+ end
125
+ end
126
+ ssh.loop
127
+
128
+ r
129
+ end
130
+
131
+ # Return a random mac address
132
+ #
133
+ # @return [String] a random mac address
134
+ def randmac
135
+ "080027" + (1..3).map{"%0.2X"%rand(256)}.join
136
+ end
63
137
  end
64
138
  end
@@ -178,82 +178,5 @@ module RSpecSystem
178
178
  nil
179
179
  end
180
180
 
181
- # Return a random string of chars, used for temp dir creation
182
- #
183
- # @api private
184
- # @return [String] string of 50 random characters A-Z and a-z
185
- def random_string
186
- o = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten
187
- (0...50).map{ o[rand(o.length)] }.join
188
- end
189
-
190
- # Generates a random string for use in remote transfers.
191
- #
192
- # @api private
193
- # @return [String] a random path
194
- # @todo Very Linux dependant, probably need to consider OS X and Windows at
195
- # least.
196
- def tmppath
197
- '/tmp/' + random_string
198
- end
199
-
200
- # Return a random mac address
201
- #
202
- # @api private
203
- # @return [String] a random mac address
204
- def randmac
205
- "080027" + (1..3).map{"%0.2X"%rand(256)}.join
206
- end
207
-
208
- # Execute command via SSH.
209
- #
210
- # A special version of exec! from Net::SSH that returns exit code and exit
211
- # signal as well. This method is blocking.
212
- #
213
- # @api private
214
- # @param ssh [Net::SSH::Connection::Session] an active ssh session
215
- # @param command [String] command to execute
216
- # @return [Hash] a hash of results
217
- def ssh_exec!(ssh, command)
218
- r = {
219
- :stdout => '',
220
- :stderr => '',
221
- :exit_code => nil,
222
- :exit_signal => nil,
223
- }
224
- ssh.open_channel do |channel|
225
- channel.exec(command) do |ch, success|
226
- unless success
227
- abort "FAILED: couldn't execute command (ssh.channel.exec)"
228
- end
229
- channel.on_data do |ch,data|
230
- d = data
231
- print d
232
- r[:stdout]+=d
233
- end
234
-
235
- channel.on_extended_data do |ch,type,data|
236
- d = data
237
- print d
238
- r[:stderr]+=d
239
- end
240
-
241
- channel.on_request("exit-status") do |ch,data|
242
- c = data.read_long
243
- puts "Exit code: #{c}"
244
- r[:exit_code] = c
245
- end
246
-
247
- channel.on_request("exit-signal") do |ch, data|
248
- s = data.read_string
249
- puts "Exit signal: #{s}"
250
- r[:exit_signal] = s
251
- end
252
- end
253
- end
254
- ssh.loop
255
-
256
- r
257
- end
258
181
  end
259
182
  end
@@ -0,0 +1,196 @@
1
+ require 'fileutils'
2
+ require 'systemu'
3
+ require 'net/ssh'
4
+ require 'net/scp'
5
+ require 'rbvmomi'
6
+
7
+ module RSpecSystem
8
+ # A NodeSet implementation for VSphere
9
+ class NodeSet::Vsphere < RSpecSystem::NodeSet::Base
10
+ include RSpecSystem::Log
11
+
12
+ ENV_TYPE = 'vsphere'
13
+
14
+ # Creates a new instance of RSpecSystem::NodeSet::Vsphere
15
+ #
16
+ # @param setname [String] name of the set to instantiate
17
+ # @param config [Hash] nodeset configuration hash
18
+ def initialize(setname, config)
19
+ super
20
+ @vim = RbVmomi::VIM.connect(
21
+ :host => ENV["RSPEC_VSPHERE_HOST"],
22
+ :user => ENV["RSPEC_VSPHERE_USER"],
23
+ :password => ENV["RSPEC_VSPHERE_PASS"],
24
+ :ssl => true,
25
+ :insecure => true
26
+ )
27
+
28
+ # Initialize node storage if not already
29
+ RSpec.configuration.rspec_storage[:nodes] ||= {}
30
+ end
31
+
32
+ # @!group NodeSet Methods
33
+
34
+ # Setup the NodeSet by starting all nodes.
35
+ #
36
+ # @return [void]
37
+ def setup
38
+ log.info "[Vsphere#setup] Setup begins"
39
+
40
+ dest_dir = ENV['RSPEC_VSPHERE_DEST_DIR']
41
+ template_dir = ENV['RSPEC_VSPHERE_TEMPLATE_DIR']
42
+
43
+ si = @vim.serviceInstance
44
+ dc = si.find_datacenter
45
+
46
+ rp = dc.find_compute_resource('general').resourcePool.find(ENV["RSPEC_VSPHERE_RPOOL"])
47
+ relocateSpec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => rp)
48
+ spec = RbVmomi::VIM.VirtualMachineCloneSpec(
49
+ :location => relocateSpec,
50
+ :powerOn => true,
51
+ :template => false
52
+ )
53
+
54
+ vm_folder = dc.vmFolder
55
+ vm_newfolder = vm_folder.find(dest_dir)
56
+
57
+ log.info "[Vsphere#setup] launching instances one by one"
58
+ nodes.each do |k,v|
59
+ ps = v.provider_specifics['vsphere']
60
+
61
+ raise 'No provider specifics for this prefab' if ps.nil?
62
+
63
+ template = ps['template']
64
+
65
+ raise "No template specified for this prefab" if template.nil?
66
+
67
+ log.info "[Vsphere#setup] launching instance #{k} with template #{template}"
68
+
69
+ vm = vm_folder.find(ENV['RSPEC_VSPHERE_TEMPLATE_DIR']).find(template)
70
+
71
+ raise "No template found" if vm.nil?
72
+
73
+ vm_name = "rspec-system-#{k}-#{random_string(10)}"
74
+
75
+ log.info "[Vsphere#setup] Cloning new vm #{vm_name} in folder #{dest_dir}"
76
+
77
+ vm.CloneVM_Task(
78
+ :folder => vm_newfolder,
79
+ :name => vm_name,
80
+ :spec => spec
81
+ ).wait_for_completion
82
+
83
+ log.info "[Vsphere#setup] Cloning complete"
84
+
85
+ newvm = vm_newfolder.find(vm_name)
86
+ guest_info = newvm.guest
87
+
88
+ timeout(60) do
89
+ while(newvm.guest.guestState != 'running') do
90
+ sleep 2
91
+ puts "#{k}> Waiting for vm to run ..."
92
+ end
93
+ end
94
+
95
+ timeout(60) do
96
+ while(newvm.guest.ipAddress == nil) do
97
+ sleep 2
98
+ puts "#{k}> Waiting for ip address ..."
99
+ end
100
+ end
101
+
102
+ ipaddress = newvm.guest.ipAddress
103
+
104
+ log.info "[Vsphere#setup] establishing Net::SSH channel with #{k}"
105
+ chan = Net::SSH.start(ipaddress, 'vagrant', :password => 'vagrant')
106
+
107
+ RSpec.configuration.rspec_storage[:nodes][k] = {
108
+ :ipaddress => ipaddress,
109
+ :ssh => chan,
110
+ :vm => newvm
111
+ }
112
+ log.info "[Vsphere#setup] Node launched: #{k}"
113
+ end
114
+
115
+ log.info("[Vsphere#setup] setup complete")
116
+
117
+ nil
118
+ end
119
+
120
+ # Shutdown the NodeSet by shutting down all nodes.
121
+ #
122
+ # @return [void]
123
+ def teardown
124
+ nodes.each do |k,v|
125
+ storage = RSpec.configuration.rspec_storage[:nodes][k]
126
+
127
+ if storage.nil?
128
+ log.info "[Vsphere#teardown] No entry for node #{k}, no teardown necessary"
129
+ next
130
+ end
131
+
132
+ log.info "[Vsphere#teardown] closing ssh channel to #{k}"
133
+ ssh = storage[:ssh]
134
+ ssh.close unless ssh.closed?
135
+
136
+ log.info "[Vsphere#teardown] destroy instance #{k}"
137
+ vm = storage[:vm]
138
+ if vm == nil
139
+ puts "No vm object"
140
+ next
141
+ end
142
+ vm.PowerOffVM_Task.wait_for_completion
143
+ vm.Destroy_Task.wait_for_completion
144
+ end
145
+
146
+ nil
147
+ end
148
+
149
+ # Run a command on a host in the NodeSet.
150
+ #
151
+ # @param opts [Hash] options
152
+ # @return [Hash] a hash containing :exit_code, :stdout and :stderr
153
+ def run(opts)
154
+ dest = opts[:n].name
155
+ cmd = opts[:c]
156
+
157
+ ssh = RSpec.configuration.rspec_storage[:nodes][dest][:ssh]
158
+ puts "-----------------"
159
+ puts "#{dest}$ #{cmd}"
160
+ result = ssh_exec!(ssh, "cd /tmp && sudo sh -c '#{cmd}'")
161
+ puts "-----------------"
162
+ result
163
+ end
164
+
165
+ # Transfer files to a host in the NodeSet.
166
+ #
167
+ # @param opts [Hash] options
168
+ # @return [Boolean] returns true if command succeeded, false otherwise
169
+ # @todo This is damn ugly, because we ssh in as vagrant, we copy to a temp
170
+ # path then move it later. Its slow and brittle and we need a better
171
+ # solution. Its also very Linux-centrix in its use of temp dirs.
172
+ def rcp(opts)
173
+ #log.debug("[Vagrant@rcp] called with #{opts.inspect}")
174
+
175
+ dest = opts[:d].name
176
+ source = opts[:sp]
177
+ dest_path = opts[:dp]
178
+
179
+ # Grab a remote path for temp transfer
180
+ tmpdest = tmppath
181
+
182
+ # Do the copy and print out results for debugging
183
+ ssh = RSpec.configuration.rspec_storage[:nodes][dest][:ssh]
184
+ ssh.scp.upload! source.to_s, tmpdest.to_s, :recursive => true
185
+
186
+ # Now we move the file into their final destination
187
+ result = run(:n => opts[:d], :c => "mv #{tmpdest} #{dest_path}")
188
+ if result[:exit_code] == 0
189
+ return true
190
+ else
191
+ return false
192
+ end
193
+ end
194
+
195
+ end
196
+ end
@@ -16,6 +16,7 @@ RSpec.configure do |c|
16
16
  c.add_setting :system_setup_block
17
17
  # Storage for ssh channels
18
18
  c.add_setting :ssh_channels, :default => {}
19
+ c.add_setting :rspec_storage, :default => {}
19
20
 
20
21
  def nodeset
21
22
  Pathname.new(File.join(File.basename(__FILE__), '..', '.nodeset.yml'))
@@ -66,11 +67,24 @@ RSpec.configure do |c|
66
67
  c.system_tmp = Dir.mktmpdir
67
68
 
68
69
  c.before :suite do
69
- start_nodes
70
- call_custom_setup_block
70
+ # Before Suite exceptions get captured it seems
71
+ begin
72
+ start_nodes
73
+ call_custom_setup_block
74
+ rescue => ex
75
+ puts ex.inspect + " in"
76
+ puts ex.backtrace.join("\n ")
77
+ exit(1)
78
+ end
71
79
  end
72
80
 
73
81
  c.after :suite do
74
- stop_nodes
82
+ # After Suite exceptions get captured it seems
83
+ begin
84
+ stop_nodes
85
+ rescue => ex
86
+ puts ex.inspect + " in"
87
+ puts ex.backtrace.join("\n ")
88
+ end
75
89
  end
76
90
  end
@@ -7,6 +7,7 @@ mapping:
7
7
  =:
8
8
  type: map
9
9
  mapping:
10
+ default_node: { type: str }
10
11
  nodes:
11
12
  type: map
12
13
  mapping:
@@ -45,6 +45,8 @@
45
45
  vagrant:
46
46
  box: 'centos-59-x64-vbox4210-nocm'
47
47
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box'
48
+ vsphere:
49
+ template: 'centos-59-x64-vs51-nocm'
48
50
  'centos-63-x64':
49
51
  description: "Vagrant images obtained from http://puppet-vagrant-boxes.puppetlabs.com"
50
52
  facts:
@@ -84,6 +86,8 @@
84
86
  vagrant:
85
87
  box: 'centos-64-x64-vbox4210-nocm'
86
88
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box'
89
+ vsphere:
90
+ template: 'centos-64-x64-vs51-nocm'
87
91
  'fedora-18-x64':
88
92
  description: ""
89
93
  facts:
@@ -101,6 +105,8 @@
101
105
  vagrant:
102
106
  box: 'fedora-18-x64-vbox4210-nocm'
103
107
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box'
108
+ vsphere:
109
+ template: 'fedora-18-x64-vs51-nocm'
104
110
  'debian-606-x64':
105
111
  description: "Vagrant images obtained from http://puppet-vagrant-boxes.puppetlabs.com"
106
112
  facts:
@@ -142,6 +148,8 @@
142
148
  vagrant:
143
149
  box: 'debian-607-x64-vbox4210-nocm'
144
150
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box'
151
+ vsphere:
152
+ template: 'debian-607-x64-vs51-nocm'
145
153
  'debian-70rc1-x64':
146
154
  description: ""
147
155
  facts:
@@ -164,6 +172,8 @@
164
172
  vagrant:
165
173
  box: 'debian-70rc1-x64-vbox4210-nocm'
166
174
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box'
175
+ vsphere:
176
+ template: 'debian-70rc1-x64-vs51-nocm'
167
177
  'ubuntu-server-1004-x64':
168
178
  description: ''
169
179
  facts:
@@ -208,6 +218,8 @@
208
218
  vagrant:
209
219
  box: 'ubuntu-server-10044-x64-vbox4210-nocm'
210
220
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box'
221
+ vsphere:
222
+ template: 'ubuntu-server-10044-x64-vs51-nocm'
211
223
  'ubuntu-server-1204-x64':
212
224
  description: ''
213
225
  facts:
@@ -252,6 +264,8 @@
252
264
  vagrant:
253
265
  box: 'ubuntu-server-12042-x64-vbox4210-nocm'
254
266
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box'
267
+ vsphere:
268
+ template: 'ubuntu-server-12042-x64-vs51-nocm'
255
269
  'sles-11sp1-x64':
256
270
  description: ''
257
271
  facts:
@@ -269,3 +283,5 @@
269
283
  vagrant:
270
284
  box: 'sles-11sp1-x64-vbox4210-nocm'
271
285
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box'
286
+ vsphere:
287
+ template: 'sles-11sp1-x64-vs51-nocm'
data/rspec-system.gemspec CHANGED
@@ -2,10 +2,10 @@
2
2
  Gem::Specification.new do |s|
3
3
  # Metadata
4
4
  s.name = "rspec-system"
5
- s.version = "1.0.0"
5
+ s.version = "1.1.0"
6
6
  s.authors = ["Ken Barber"]
7
7
  s.email = ["ken@bob.sh"]
8
- s.homepage = "https://github.com/kbarber/rspec-system"
8
+ s.homepage = "https://github.com/puppetlabs/rspec-system"
9
9
  s.summary = "System testing with rspec"
10
10
 
11
11
  # Manifest
@@ -20,4 +20,6 @@ Gem::Specification.new do |s|
20
20
  s.add_runtime_dependency "kwalify"
21
21
  s.add_runtime_dependency "systemu"
22
22
  s.add_runtime_dependency "net-ssh", '~>2.6'
23
+ s.add_runtime_dependency "net-scp"
24
+ s.add_runtime_dependency "rbvmomi"
23
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-system
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-21 00:00:00.000000000 Z
12
+ date: 2013-05-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -75,6 +75,38 @@ dependencies:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
77
  version: '2.6'
78
+ - !ruby/object:Gem::Dependency
79
+ name: net-scp
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rbvmomi
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
78
110
  description:
79
111
  email:
80
112
  - ken@bob.sh
@@ -107,6 +139,7 @@ files:
107
139
  - lib/rspec-system/node_set.rb
108
140
  - lib/rspec-system/node_set/base.rb
109
141
  - lib/rspec-system/node_set/vagrant.rb
142
+ - lib/rspec-system/node_set/vsphere.rb
110
143
  - lib/rspec-system/prefab.rb
111
144
  - lib/rspec-system/rake_task.rb
112
145
  - lib/rspec-system/spec_helper.rb
@@ -123,7 +156,7 @@ files:
123
156
  - spec/system/system_run_spec.rb
124
157
  - spec/unit/kwalify-schemas/nodeset_schema_spec.rb
125
158
  - spec/unit/kwalify-schemas/prefabs_schema_spec.rb
126
- homepage: https://github.com/kbarber/rspec-system
159
+ homepage: https://github.com/puppetlabs/rspec-system
127
160
  licenses: []
128
161
  post_install_message:
129
162
  rdoc_options: []
@@ -153,4 +186,3 @@ test_files:
153
186
  - spec/system/system_run_spec.rb
154
187
  - spec/unit/kwalify-schemas/nodeset_schema_spec.rb
155
188
  - spec/unit/kwalify-schemas/prefabs_schema_spec.rb
156
- has_rdoc: