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 +3 -0
- data/.nodeset.yml +7 -0
- data/Gemfile +1 -0
- data/README.md +89 -22
- data/Rakefile +5 -0
- data/examples/.nodeset.yml +3 -3
- data/examples/spec/system/test1_spec.rb +2 -2
- data/lib/rspec-system/node_set.rb +3 -0
- data/lib/rspec-system/node_set/base.rb +74 -0
- data/lib/rspec-system/node_set/vagrant.rb +0 -77
- data/lib/rspec-system/node_set/vsphere.rb +196 -0
- data/lib/rspec-system/spec_helper.rb +17 -3
- data/resources/kwalify-schemas/nodeset_schema.yml +1 -0
- data/resources/prefabs.yml +16 -0
- data/rspec-system.gemspec +4 -2
- metadata +36 -4
data/.gitignore
CHANGED
data/.nodeset.yml
CHANGED
data/Gemfile
CHANGED
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
|
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`
|
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
|
51
|
+
Also consult the examples in the `examples` directory in the source of this library for more details.
|
52
52
|
|
53
|
-
For
|
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
|
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
|
-
|
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* -
|
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=
|
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
|
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
|
-
|
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
|
-
|
175
|
-
|
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
|
-
|
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
|
-
|
181
|
-
rake spec:system
|
226
|
+
#### Jenkins and the VSphere provider
|
182
227
|
|
183
|
-
|
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
data/examples/.nodeset.yml
CHANGED
@@ -2,10 +2,10 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe "test1" do
|
4
4
|
it 'run test1 - part1' do
|
5
|
-
|
5
|
+
system_run("cat /etc/resolv.conf")
|
6
6
|
end
|
7
7
|
|
8
8
|
it 'run test1 - part2' do
|
9
|
-
|
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
|
-
|
70
|
-
|
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
|
-
|
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
|
data/resources/prefabs.yml
CHANGED
@@ -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.
|
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/
|
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.
|
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-
|
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/
|
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:
|