I'm using serverspec to carry out remote testing of servers.
I've a number of different tests, which all work fine:
`-- spec
|-- builder.example.org.uk
\ host_spec.rb
|-- chat.example.org.uk
\ host_spec.rb
|-- docker.example.org.uk
\ host_spec.rb
\-- git.example.org.uk
\ host_spec.rb
However each host-test has a lot of duplication, because I want to ensure that each host has sshd
running, for example.
I've tried several different ways of creating spec/common_tests.rb
but each time fails. For example adding spec/common.rb
:
describe command("lsb_release -d") do
its(:stdout) { should match /wheezy/ }
end
Then in spec/chat.example.org.uk/host_spec.rb
:
require 'common'
However this seems to suddenly want to connect to a different host, and fail:
shelob ~ $ bundle exec rake spec:ssh.example.org.uk
/usr/bin/ruby1.9.1 -S rspec spec/ssh.example.org.uk/host_spec.rb
F.....................
Failures:
1) Command "lsb_release -d" stdout
On host `ssh.example.org.uk`
Failure/Error: Unable to find matching line from backtrace
SocketError: getaddrinfo: Name or service not known
So my question is twofold:
I'm not sure whether your example has a typo, as it seems to do exactly what you want. You're running bundle exec rake spec:ssh.example.org.uk
and it's running against ssh.example.org.uk
.
The serverspec documentation suggests another way to run shared specs. Instead of organising your files by host, you should organise them by role. For instance:
`-- spec
|-- app
| `-- ruby_spec.rb
|-- base
| `-- users_and_groups_spec.rb
|-- db
| `-- mysql_spec.rb
|-- proxy
| `-- nginx_spec.rb
`-- spec_helper.rb
Then, in your Rakefile
, you map your hosts to roles:
hosts = [{name: 'www.example.org.uk', roles: %w(base app)},
{name: 'db.example.org.uk', roles: %w(base db)}]
You can then provide a ServerSpecTask
that runs commands by setting the host address as an environment variable, by overriding RSpec's spec_command
method:
class ServerspecTask < RSpec::Core::RakeTask
attr_accessor :target
def spec_command
cmd = super
"env TARGET_HOST=#{target} #{cmd}"
end
end
namespace :serverspec do
hosts.each do |host|
desc "Run serverspec to #{host[:name]}"
ServerspecTask.new(host[:name].to_sym) do |t|
t.target = host[:name]
t.pattern = 'spec/{' + host[:roles].join(',') + '}/*_spec.rb'
end
end
end
And then finally, update your spec_helper.rb
to read that environment variable and use it as the host:
RSpec.configure do |c|
c.host = ENV['TARGET_HOST']
options = Net::SSH::Config.for(c.host)
user = options[:user] || Etc.getlogin
c.ssh = Net::SSH.start(c.host, user, options)
c.os = backend.check_os
end