rspec-system 2.5.1 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 53c1e505cedc7e77105136f17ffce867f00fc007
4
+ data.tar.gz: 3bfff0443416ff446e1cdd14c5fb12c9eec6121e
5
+ SHA512:
6
+ metadata.gz: c1da1f38adcf52f28afffd07ad06694e82b73afd17ae678786e5e4e166ea045d1f08951f22a0e9bbdba5b407c54f07e6c02c8a281a1c2535b476c8ea9b827634
7
+ data.tar.gz: 1e4fab285717d34a3e585bf172af018d1ddb9936c71c5e8859f997850746714acdd11c015775a52ad3db9bde2053390b2c50cae2dd203697644fe4773e658aeb
@@ -1,3 +1,27 @@
1
+ 2.6.0
2
+ =====
3
+
4
+ This is a feature release that improves a number of areas:
5
+
6
+ * Split out vagrant commonalities into a vagrant_base class
7
+ * Add support for vagrant-vmware_fusion
8
+ * Fix vagrant so we log in as root, not log in as vagrant and sudo
9
+ * Break out steps in providers: launch, connect, configure
10
+ * Generalise the SSH connection routines
11
+ * Provide a series of global configuration steps, like ntp sync, hostname
12
+ fixups etc.
13
+ * Deprecated the internal_helpers module, its better to avoid global
14
+ methods anyway
15
+ * Switched to using RS_ as the prefix for environment variables
16
+
17
+ #### Detailed Changes
18
+
19
+ * Refactor with some new features (Ken Barber)
20
+ * fix multi-node sample in readme (Pall Valmundsson)
21
+ * remove unnecessary if statment (Johan Haals)
22
+
23
+ -------------------------------
24
+
1
25
  2.5.1
2
26
  =====
3
27
 
data/README.md CHANGED
@@ -123,8 +123,8 @@ In your `.nodeset.yml` file you will need to define multiple nodes:
123
123
  ---
124
124
  sets:
125
125
  'centos-59-x64-multinode':
126
+ default_node: 'first.mydomain.vm'
126
127
  nodes:
127
- default_node: 'first.mydomain.vm':
128
128
  'first.mydomain.vm':
129
129
  prefab: 'centos-59-x64'
130
130
  'second.mydomain.vm':
@@ -203,7 +203,7 @@ To define custom prefabs place a `.prefabs.yml` file in your project's root dire
203
203
  kernel: Linux
204
204
  rubyversion: "1.8.7"
205
205
  provider_specifics:
206
- vagrant:
206
+ vagrant_virtualbox:
207
207
  box: 'scientific-64-x64-vb4210-nocm'
208
208
  box_url: 'http://example.com/path/to/scientific-64-x64-vb4210-nocm.box'
209
209
 
@@ -216,7 +216,7 @@ For example, to use a different box for CentOS 6.4 x64, you can override the `bo
216
216
  ---
217
217
  'centos-64-x64':
218
218
  provider_specifics:
219
- vagrant:
219
+ vagrant_virtualbox:
220
220
  box: 'centos-64-x64-vbox4210'
221
221
  box_url: 'http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210.box'
222
222
 
@@ -229,7 +229,25 @@ There are two providers at the moment you can use to launch your nodes for testi
229
229
 
230
230
  Although both systems can be used for either purpose, if you so desire.
231
231
 
232
- #### Vagrant Provider
232
+ 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:
233
+
234
+ * *RS_PROVIDER* - defines the nodeset provider, for now `vagrant_virtualbox` is the default.
235
+ * *RS_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`.
236
+ * *RS_DESTROY* - set this to `no` if you do not want your nodes to be destroyed before or after a test completes. May be useful during initial testing of rspec tests to allow inspection of the node.
237
+ * *RS_TMP* - This patch is used for various temporary content. Default is the directory `.rspec_system` in your projects root.
238
+ * *RS_SSH_TRIES* - Number of attempts to connect to a node using SSH. Defaults to 10.
239
+ * *RS_SSH_SLEEP* - Number of seconds between attempts. Defaults to 4.
240
+ * *RS_SSH_TIMEOUT* - Timeout for attempting SSH connectivity. Defaults to 60.
241
+
242
+ So if you wanted to run an alternate nodeset you could use:
243
+
244
+ RS_SET=fedora18 bundle exec rake spec:system
245
+
246
+ In Jenkins you should be able to use RS\_SET in a test matrix, thus obtaining quite a nice integration and visual display of nodesets in Jenkins.
247
+
248
+ #### Vagrant Virtualbox
249
+
250
+ RS_PROVIDER='vagrant_virtualbox'
233
251
 
234
252
  This is the default provider, as all the products for this provider are free, most people should be able to run it.
235
253
 
@@ -244,57 +262,49 @@ Once these are ready, you can Run the system tests with:
244
262
 
245
263
  The VM's should be downloaded from the internet, started and tests should run.
246
264
 
247
- 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:
265
+ #### Vagrant VMware Fusion
248
266
 
249
- * *RSPEC_VIRTUAL_ENV* - set this to `vagrant` if you wish, for now `vagrant` is the default so this is optional.
250
- * *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`.
251
- * *RSPEC_DESTROY* - set this to `no` if you do not want the VM to be destroyed before or after a test completes. May be useful during initial testing of rspec tests to allow inspection of the VM.
252
- * *RSPEC_SYSTEM_TMP* - Sets the path to create vagrant_projects directory containing each Nodeset's Vagrantfile. Default is the directory `.rspec_system` in your projects root.
267
+ RS_PROVIDER='vagrant_vmware_fusion'
253
268
 
254
- So if you wanted to run an alternate nodeset you could use:
269
+ Make sure you have already installed:
255
270
 
256
- RSPEC_SET=fedora18 bundle exec rake spec:system
271
+ * VirtualBox 4.2.10+
272
+ * VMware Fusion 5.0.3+
257
273
 
258
- 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.
274
+ Once these are ready, you can Run the system tests with:
259
275
 
260
- To set the location of the Nodeset's Vagrantfile to `/tmp/vagrant_projects/centos-64-x64` you could use:
276
+ RS_PROVIDER='vagrant_vmware_fusion' bundle exec rake spec:system
261
277
 
262
- RSPEC_SET=centos-64-x64 RSPEC_SYSTEM_TMP=/tmp rake spec:system
278
+ The VM's should be downloaded from the internet, started and tests should run.
263
279
 
264
- #### VSphere Provider
280
+ #### VSphere
265
281
 
266
- *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.
282
+ RS_PROVIDER='vsphere'
267
283
 
268
284
  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.
269
285
 
270
286
  This provider has a lot more options for setup, in the form of environment variables:
271
287
 
272
- * *RSPEC_VIRTUAL_ENV* - set this to 'vsphere' to use this provider
273
- * *RSPEC_SET* - same as the vagrant provider, this defines the 'set' to launch.
274
- * *RSPEC_DESTROY* - same as the vagrant provider, defines if the VM should be destroyed before and after a test.
275
- * *RSPEC_VSPHERE_HOST* - hostname of your vsphere api
276
- * *RSPEC_VSPHERE_USER* - username to authenticate with
277
- * *RSPEC_VSPHERE_PASS* - password to authenticate with
278
- * *RSPEC_VSPHERE_DEST_DIR* - destination path to launch vm's
279
- * *RSPEC_VSPHERE_TEMPLATE_DIR* - path to where you deployed the templates from the OVF files described above
280
- * *RSPEC_VSPHERE_RPOOL* - name of resource pool to use
281
- * *RSPEC_VSPHERE_CLUSTER* - name of the cluster to use
282
- * *RSPEC_VSPHERE_SSH_KEYS* - path to private key for authentication. Multiple paths may be provided using a colon separator.
283
- * *RSPEC_VSPHERE_DATACENTER* - optional name of VSphere data centre
284
- * *RSPEC_VSPHERE_NODE_TIMEOUT* - amount of seconds before trying to relaunch a node. Defaults to 1200.
285
- * *RSPEC_VSPHERE_NODE_TRIES* - amount of attempts to relaunch a node. Defaults to 10.
286
- * *RSPEC_VSPHERE_NODE_SLEEP* - amount of seconds to sleep for before trying again. Defaults to a random number between 30 and 90.
287
- * *RSPEC_VSPHERE_SSH_TIMEOUT* - amount of seconds before retrying to SSH into a node. Default to 60.
288
- * *RSPEC_VSPHERE_SSH_TRIES* - amount of attempts to SSH into a node. Defaults to 10.
289
- * *RSPEC_VSPHERE_SSH_SLEEP* - amount of seconds to sleep before trying to SSH again. Defaults to 4.
290
- * *RSPEC_VSPHERE_CONNECT_TIMEOUT* - amount of seconds before retrying to connect to the VSphere API. Defaults to 60.
291
- * *RSPEC_VSPHERE_CONNECT_TRIES* - amount of attempts to connect to the VSphere API. Defaults to 10.
292
-
293
- Set these variables, and run the usual rake command:
288
+ * *RS_VSPHERE_HOST* - hostname of your vsphere api
289
+ * *RS_VSPHERE_USER* - username to authenticate with
290
+ * *RS_VSPHERE_PASS* - password to authenticate with
291
+ * *RS_VSPHERE_DEST_DIR* - destination path to launch vm's
292
+ * *RS_VSPHERE_TEMPLATE_DIR* - path to where you deployed the templates from the OVF files described above
293
+ * *RS_VSPHERE_RPOOL* - name of resource pool to use
294
+ * *RS_VSPHERE_CLUSTER* - name of the cluster to use
295
+ * *RS_VSPHERE_SSH_KEYS* - path to private key for authentication. Multiple paths may be provided using a colon separator.
296
+ * *RS_VSPHERE_DATACENTER* - optional name of VSphere data centre
297
+ * *RS_VSPHERE_NODE_TIMEOUT* - amount of seconds before trying to relaunch a node. Defaults to 1200.
298
+ * *RS_VSPHERE_NODE_TRIES* - amount of attempts to relaunch a node. Defaults to 10.
299
+ * *RS_VSPHERE_NODE_SLEEP* - amount of seconds to sleep for before trying again. Defaults to a random number between 30 and 90.
300
+ * *RS_VSPHERE_CONNECT_TIMEOUT* - amount of seconds before retrying to connect to the VSphere API. Defaults to 60.
301
+ * *RS_VSPHERE_CONNECT_TRIES* - amount of attempts to connect to the VSphere API. Defaults to 10.
294
302
 
295
- bundle exec rake spec:system
303
+ Set these variables, and run the usual rake command specifying the provider:
304
+
305
+ RS_PROVIDER='vsphere' bundle exec rake spec:system
296
306
 
297
- 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.
307
+ 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 RS\_SET into a test matrix, containing all the sets you want to test against.
298
308
 
299
309
  ### Plugins to rspec-system
300
310
 
@@ -311,15 +321,20 @@ Libraries that provide test helpers, and setup helpers for testing development o
311
321
 
312
322
  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.
313
323
 
314
- 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.
324
+ Right now the options are:
325
+
326
+ * vagrant\_virtualbox
327
+ * vagrant\_vmware\_fusion
328
+ * vsphere
329
+
330
+ ... 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.
315
331
 
316
332
  #### The Future of Plugins
317
333
 
318
334
  I want to start an eco-system of plugins for rspec-system, but do it in a sane way. Right now I see the following potential plugin types, if you think you can help please do:
319
335
 
320
336
  * node providers - that is, abstractions around other virtualisation, cloud or system tools. Right now a NodeSet is tied to a virtual type, but I think this isn't granual enough. Some ideas for future providers are:
321
- * blimpy - for firing up EC2 and OpenStack nodes, useful for Jenkins integration
322
- * vmware fusion - for using vmware fusion with vagrant
337
+ * other vagrant plugins - it should be reasonably easy to extend support out to new vagrant plugins, since most of the example plugins are already using a simple pattern to do this.
323
338
  * razor - for launching bare metail nodes for testing purposes. Could be really useful to have baremetal tests for software that needs it like `facter`.
324
339
  * manual - not everything has to be 'launched' I can see a need for defining a static configuration for older machines that can't be poked and peeked. Of course, we might need to add cleanup tasks for this case.
325
340
  * helper libraries - libraries that provide test helpers, and setup helpers for testing development on the software in question.
@@ -335,9 +350,9 @@ These could be shipped as external gems, and plugged in to the rspec-system fram
335
350
 
336
351
  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.
337
352
 
338
- #### Jenkins and the Vagrant provider
353
+ #### Jenkins
339
354
 
340
- My setup was:
355
+ For virtualbox the setup tested with was:
341
356
 
342
357
  * Single box - 32GB of RAM and 8 cpus
343
358
  * Debian 7
@@ -346,28 +361,7 @@ My setup was:
346
361
  * VirtualBox 4.2.10 (installed via packages from virtualbox)
347
362
  * RVM with Ruby 2.0.0
348
363
 
349
- The setup for a job is basically:
350
-
351
- * Setup your slave box to only have 1 executor (there is some bug here, something to do with vagrant not liking multiple projects)
352
- * Create new matrix build
353
- * Specify VCS settings etc. as per normal
354
- * Create a user defined axis called 'RSPEC_SET' and add your nodesets in there: fedora-18-x64, centos-64-x64 etc.
355
- * 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
356
- * Create an execute shell job like so:
357
-
358
- #!/bin/bash
359
- set +e
360
-
361
- [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
362
- rvm use ruby-2.0.0
363
- bundle install --path vendor/bundle
364
- bundle exec rake spec:system
365
-
366
- 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.
367
-
368
- #### Jenkins and the VSphere provider
369
-
370
- My setup was:
364
+ Or for VSphere:
371
365
 
372
366
  * Debian 7
373
367
  * Jenkins 1.510
@@ -377,16 +371,17 @@ The setup for a job is basically:
377
371
 
378
372
  * Create new matrix build
379
373
  * Specify VCS settings etc. as per normal
380
- * Create a user defined axis called 'RSPEC\_SET' and add your nodesets in there: fedora-18-x64, centos-64-x64 etc.
381
- * Use the enviornment injection facility to add all the other RSPEC\_VSPHERE vars as above
382
- * 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
374
+ * Create a user defined axis called 'RS\_SET' and add your nodesets in there: fedora-18-x64, centos-64-x64 etc.
375
+ * Use touchstone with a filter of RS\_SET=='centos-64-x64' so you don't chew up cycles running a whole batch of broken builds
376
+ * For the provider in question, make sure you have provided any custom configuration. For example VSphere requires a bunch of RS\_VSPHERE\_\* variables to be set. Make sure these are set using the environment variable injection facility.
383
377
  * Create an execute shell job like so:
384
378
 
385
379
  #!/bin/bash
386
380
  set +e
381
+
387
382
  [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
388
383
  rvm use ruby-2.0.0
389
384
  bundle install --path vendor/bundle
390
385
  bundle exec rake spec:system
391
386
 
392
- Basically the results were quite nice, as apposed to the 'vagrant' provider I was able to achieve running parallel jobs using my matrix setup.
387
+ 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.
@@ -8,7 +8,6 @@ require 'rspec-system/util'
8
8
  require 'rspec-system/log'
9
9
  require 'rspec-system/helper'
10
10
  require 'rspec-system/helpers'
11
- require 'rspec-system/internal_helpers'
12
11
  require 'rspec-system/node_set'
13
12
  require 'rspec-system/prefab'
14
13
  require 'rspec-system/node'
@@ -1,6 +1,5 @@
1
1
  require 'rspec-system'
2
2
  require 'rspec-system/result'
3
- require 'rspec-system/internal_helpers'
4
3
  require 'timeout'
5
4
 
6
5
  module RSpecSystem
@@ -16,8 +15,6 @@ module RSpecSystem
16
15
  #
17
16
  # @abstract Subclass and override methods to create a helper object
18
17
  class Helper
19
- include RSpecSystem::InternalHelpers
20
-
21
18
  # Cache of previous result data
22
19
  # @api private
23
20
  attr_reader :rd
@@ -169,7 +166,7 @@ module RSpecSystem
169
166
 
170
167
  # Return default node
171
168
  def default_node
172
- rspec_system_node_set.default_node
169
+ RSpecSystem::NodeSet.create.default_node
173
170
  end
174
171
 
175
172
  # Returns a node by its name.
@@ -179,7 +176,7 @@ module RSpecSystem
179
176
  # @param name [String] name of the node
180
177
  # @return [RSpecSystem::Node] node found
181
178
  def get_node_by_name(name)
182
- rspec_system_node_set.nodes[name]
179
+ RSpecSystem::NodeSet.create.nodes[name]
183
180
  end
184
181
  end
185
182
  end
@@ -164,7 +164,7 @@ module RSpecSystem::Helpers
164
164
  # @option options [String] :name the canonical name of the node
165
165
  # @return [RSpecSystem::Node] node object
166
166
  def node(options = {})
167
- ns = rspec_system_node_set
167
+ ns = RSpecSystem::NodeSet.create
168
168
  options = {
169
169
  :name => ns.default_node.name,
170
170
  }.merge(options)
@@ -7,7 +7,7 @@ module RSpecSystem::Helpers
7
7
  properties :success
8
8
 
9
9
  def initialize(opts, clr, &block)
10
- ns = rspec_system_node_set
10
+ ns = RSpecSystem::NodeSet.create
11
11
  opts = {
12
12
  :source_path => opts[:sp],
13
13
  :destination_path => opts[:dp],
@@ -32,10 +32,7 @@ module RSpecSystem::Helpers
32
32
 
33
33
  # Gathers new results by executing the resource action
34
34
  def execute
35
- ns = rspec_system_node_set
36
- d = opts[:d]
37
- sp = opts[:sp]
38
- dp = opts[:dp]
35
+ ns = RSpecSystem::NodeSet.create
39
36
 
40
37
  result = ns.rcp(opts)
41
38
  { :success => result }
@@ -35,7 +35,7 @@ module RSpecSystem::Helpers
35
35
  cmd = opts[:c]
36
36
 
37
37
  output << bold(color("#{dest}$", :green)) << " #{cmd}\n"
38
- rspec_system_node_set.run(opts)
38
+ RSpecSystem::NodeSet.create.run(opts)
39
39
  end
40
40
  end
41
41
  end
@@ -3,8 +3,6 @@ require 'rspec-system'
3
3
  module RSpecSystem
4
4
  # This class represents a node in a nodeset
5
5
  class Node
6
- include RSpecSystem::InternalHelpers
7
-
8
6
  # Static helper for generating a node direct from the hash returned by
9
7
  # the nodeset YAML file.
10
8
  #
@@ -44,7 +42,7 @@ module RSpecSystem
44
42
  # TODO: do not support not prefabs yet
45
43
  raise "No prefab defined, bailing"
46
44
  else
47
- @prefab = RSpecSystem::Prefab.prefab(prefab, custom_prefabs_path)
45
+ @prefab = RSpecSystem::Prefab.prefab(prefab, @custom_prefabs_path)
48
46
  @facts = @prefab.facts
49
47
  @provider_specifics = @prefab.provider_specifics
50
48
  end
@@ -5,13 +5,21 @@ module RSpecSystem
5
5
  #
6
6
  # @return [RSpecSystem::NodeSet::Base] returns an object based on the Base
7
7
  # abstract class.
8
- def self.create(setname, config, virtual_env, custom_prefabs_path, options)
8
+ # @api private
9
+ def self.create
10
+ provider = RSpec.configuration.rs_provider
11
+ custom_prefabs = RSpec.configuration.rs_custom_prefabs
12
+ setname = RSpec.configuration.rs_set || RSpec.configuration.rs_config['default_set']
13
+ options = {:destroy => RSpec.configuration.rs_destroy}
14
+ config = RSpec.configuration.rs_config['sets'][setname]
15
+
9
16
  begin
10
- require "rspec-system/node_set/#{virtual_env.downcase}"
17
+ require "rspec-system/node_set/#{provider.downcase}"
11
18
  rescue LoadError => e
12
- raise "Unsupported virtual environment #{virtual_env}: #{e}"
19
+ raise "Unsupported provider #{provider}: #{e}"
13
20
  end
14
- const_get(virtual_env.capitalize).new(setname, config, custom_prefabs_path, options)
21
+ class_name = provider.split("_").map {|v| v.capitalize }.join
22
+ const_get(class_name).new(setname, config, custom_prefabs, options)
15
23
  end
16
24
  end
17
25
  end
@@ -30,9 +30,83 @@ module RSpecSystem
30
30
  # Setup the NodeSet by starting all nodes.
31
31
  #
32
32
  # @return [void]
33
- # @abstract Override this method and provide your own node launching code
34
33
  def setup
35
- raise "Unimplemented method #setup"
34
+ launch
35
+ connect
36
+ configure
37
+ end
38
+
39
+ # Launch nodes
40
+ #
41
+ # @return [void]
42
+ # @abstract Override this method and provide your own launch code
43
+ def launch
44
+ raise RuntimeError "Unimplemented method #launch"
45
+ end
46
+
47
+ # Connect nodes
48
+ #
49
+ # @return [void]
50
+ # @abstract Override this method and provide your own connect code
51
+ def connect
52
+ raise RuntimeError "Unimplemented method #connect"
53
+ end
54
+
55
+ # Configure nodes
56
+ #
57
+ # This is the global configure method that sets up a node before tests are
58
+ # run, making sure any important preparation steps are executed.
59
+ #
60
+ # * fixup profile to stop using mesg to avoid extraneous noise
61
+ # * ntp synchronisation
62
+ # * hostname & hosts setup
63
+ #
64
+ # @return [void]
65
+ # @abstract Override this method and provide your own configure code
66
+ def configure
67
+ nodes.each do |k,v|
68
+ rs_storage = RSpec.configuration.rs_storage[:nodes][k]
69
+
70
+ # Fixup profile to avoid noise
71
+ if v.facts['osfamily'] == 'Debian'
72
+ shell(:n => k, :c => "sed -i 's/^mesg n/# mesg n/' /root/.profile")
73
+ end
74
+
75
+ # Setup ntp
76
+ if v.facts['osfamily'] == 'Debian' then
77
+ shell(:n => k, :c => 'apt-get install -y ntpdate')
78
+ elsif v.facts['osfamily'] == 'RedHat' then
79
+ if v.facts['lsbmajdistrelease'] == '5' then
80
+ shell(:n => k, :c => 'yum install -y ntp')
81
+ else
82
+ shell(:n => k, :c => 'yum install -y ntpdate')
83
+ end
84
+ end
85
+ shell(:n => k, :c => 'ntpdate -u pool.ntp.org')
86
+
87
+ # Grab IP address for host, if we don't already have one
88
+ rs_storage[:ipaddress] ||= shell(:n => k, :c => "ip a|awk '/g/{print$2}' | cut -d/ -f1 | head -1").stdout.chomp
89
+
90
+ # Configure local hostname and hosts file
91
+ shell(:n => k, :c => "hostname #{k}")
92
+
93
+ if v.facts['osfamily'] == 'Debian' then
94
+ shell(:n => k, :c => "echo '#{k}' > /etc/hostname")
95
+ end
96
+
97
+ hosts = <<-EOS
98
+ #{rs_storage[:ipaddress]} #{k}
99
+ 127.0.0.1 #{k} localhost
100
+ ::1 #{k} localhost
101
+ EOS
102
+ shell(:n => k, :c => "echo '#{hosts}' > /etc/hosts")
103
+
104
+ # Display setup for diagnostics
105
+ shell(:n => k, :c => 'cat /etc/hosts')
106
+ shell(:n => k, :c => 'hostname')
107
+ shell(:n => k, :c => 'hostname -f')
108
+ end
109
+ nil
36
110
  end
37
111
 
38
112
  # Shutdown the NodeSet by shutting down or pausing all nodes.
@@ -40,7 +114,7 @@ module RSpecSystem
40
114
  # @return [void]
41
115
  # @abstract Override this method and provide your own node teardown code
42
116
  def teardown
43
- raise "Unimplemented method #teardown"
117
+ raise RuntimeError "Unimplemented method #teardown"
44
118
  end
45
119
 
46
120
  # Run a command on a host in the NodeSet.
@@ -49,7 +123,11 @@ module RSpecSystem
49
123
  # @return [Hash] a hash containing :stderr, :stdout and :exit_code
50
124
  # @abstract Override this method providing your own shell running code
51
125
  def run(opts)
52
- raise "Unimplemented method #run"
126
+ dest = opts[:n].name
127
+ cmd = opts[:c]
128
+
129
+ ssh = RSpec.configuration.rs_storage[:nodes][dest][:ssh]
130
+ ssh_exec!(ssh, cmd)
53
131
  end
54
132
 
55
133
  # Copy a file to the host in the NodeSet.
@@ -61,14 +139,28 @@ module RSpecSystem
61
139
  # @return [Boolean] returns true if command succeeded, false otherwise
62
140
  # @abstract Override this method providing your own file transfer code
63
141
  def rcp(opts)
64
- raise "Unimplemented method #rcp"
142
+ dest = opts[:d].name
143
+ source = opts[:sp]
144
+ dest_path = opts[:dp]
145
+
146
+ # Do the copy and print out results for debugging
147
+ ssh = RSpec.configuration.rs_storage[:nodes][dest][:ssh]
148
+
149
+ begin
150
+ ssh.scp.upload! source.to_s, dest_path.to_s, :recursive => true
151
+ rescue => e
152
+ log.error("Error with scp of file #{source} to #{dest}:#{dest_path}")
153
+ raise e
154
+ end
155
+
156
+ true
65
157
  end
66
158
 
67
159
  # @!group Common Methods
68
160
 
69
161
  # Return environment type
70
- def env_type
71
- self.class::ENV_TYPE
162
+ def provider_type
163
+ self.class::PROVIDER_TYPE
72
164
  end
73
165
 
74
166
  # Return default node
@@ -105,6 +197,39 @@ module RSpecSystem
105
197
  '/tmp/' + random_string
106
198
  end
107
199
 
200
+ # Connect via SSH in a resilient way
201
+ #
202
+ # @param [Hash] opts
203
+ # @option opts [String] :host Host to connect to
204
+ # @option opts [String] :user User to connect as
205
+ # @option opts [Hash] :net_ssh_options Options hash as used by `Net::SSH.start`
206
+ # @return [Net::SSH::Connection::Session]
207
+ # @api protected
208
+ def ssh_connect(opts = {})
209
+ ssh_sleep = RSpec.configuration.rs_ssh_sleep
210
+ ssh_tries = RSpec.configuration.rs_ssh_tries
211
+ ssh_timeout = RSpec.configuration.rs_ssh_timeout
212
+
213
+ tries = 0
214
+ begin
215
+ timeout(ssh_timeout) do
216
+ output << bold(color("localhost$", :green)) << " ssh -l #{opts[:user]} #{opts[:host]}\n"
217
+ Net::SSH.start(opts[:host], opts[:user], opts[:net_ssh_options])
218
+ end
219
+ rescue Timeout::Error, SystemCallError => e
220
+ tries += 1
221
+ output << e.message << "\n"
222
+ if tries < ssh_tries
223
+ log.info("Sleeping for #{ssh_sleep} seconds then trying again ...")
224
+ sleep ssh_sleep
225
+ retry
226
+ else
227
+ log.error("Inability to connect to host, already tried #{tries} times, throwing exception")
228
+ raise e
229
+ end
230
+ end
231
+ end
232
+
108
233
  # Execute command via SSH.
109
234
  #
110
235
  # A special version of exec! from Net::SSH that returns exit code and exit