Qiang Blog

Just another zhangjingqiang's blog.

How to use serverspec to test servers?

Start a test project

$ serverspec-init

Directory

.
├── README.md
├── Rakefile
├── properties.yml
└── spec
    ├── app
    │   └── ruby_spec.rb
    ├── base
    │   ├── host_spec.rb
    │   └── users_and_groups_spec.rb
    ├── db
    │   └── mysql_spec.rb
    ├── proxy
    │   └── nginx_spec.rb
    ├── spec_helper.rb
    └── worker
        └── redis_spec.rb

Source

Rakefile

require 'rake'
require 'rspec/core/rake_task'
require 'yaml'

properties = YAML.load_file('properties.yml')

task :spec    => 'serverspec:all'
task :default => :spec

namespace :serverspec do
  task :all => properties.keys.map {|key| 'serverspec:' + key.split('.')[0] }
  properties.keys.each do |key|
    desc "Run serverspec to #{key}"
    RSpec::Core::RakeTask.new(key.split('.')[0].to_sym) do |t|
      ENV['TARGET_HOST'] = key
      t.pattern = 'spec/{' + properties[key][:roles].join(',') + '}/*_spec.rb'
    end
  end
end

properties.yml

# server1

app.server1:
  :roles:
    - base
    - proxy
db.server1:
  :roles:
    - db
worker.server1:
  :roles:
    - app
    - worker

# server2

app.server2:
  :roles:
    - base
    - proxy
db.server2:
  :roles:
    - db
worker.server2:
  :roles:
    - app
    - worker

spec/spec_helper.rb

require 'serverspec'
require 'net/ssh'
require 'yaml'

properties = YAML.load_file('properties.yml')

set :backend, :ssh
set :request_pty, true

if ENV['ASK_SUDO_PASSWORD']
  begin
    require 'highline/import'
  rescue LoadError
    fail "highline is not available. Try installing it."
  end
  set :sudo_password, ask("Enter sudo password: ") { |q| q.echo = false }
else
  set :sudo_password, ENV['SUDO_PASSWORD']
end

host = ENV['TARGET_HOST']
set_property properties[host]

options = Net::SSH::Config.for(host)

options[:user] ||= Etc.getlogin

set :host,        options[:host_name] || host
set :ssh_options, options

# Disable sudo
# set :disable_sudo, true


# Set environment variables
# set :env, :LANG => 'C', :LC_MESSAGES => 'C'

# Set PATH
# set :path, '/sbin:/usr/local/sbin:$PATH'

spec/app/ruby_spec.rb

require_relative '../spec_helper'

describe process("ruby") do
  it { should be_running }
end

spec/base/host_spec.rb

require_relative '../spec_helper'

shared_examples "cpu and memory should be ok" do
  it { should be_resolvable }
  it { should be_resolvable.by('dns') }

  it 'CPU should eq 2' do
    expect(host_inventory['cpu']['total']).to eq('2')
  end

  it 'Memory should > 7000000kB' do
    expect(host_inventory['memory']['total']).to be > '7000000kB'
  end
end

# server1

describe host('www.server1.com') do
  include_examples "cpu and memory should be ok"
end

# server2

describe host('www.server2.com') do
  include_examples "cpu and memory should be ok"
end

spec/db/mysql_spec.rb

require_relative '../spec_helper'

describe 'MySQL config parameters' do
  context mysql_config('innodb-buffer-pool-size') do
    its(:value) { should > 100000000 }
  end

  context mysql_config('socket') do
    its(:value) { should eq '/var/lib/mysql/mysql.sock' }
  end
end

spec/proxy/nginx_spec.rb

require_relative '../spec_helper'

describe port(80) do
  it { should be_listening }
end

describe port(80) do
  it { should be_listening.with('tcp') }
end

describe process("nginx") do
  it { should be_running }
end

spec/worker/redis_spec.rb

require_relative '../spec_helper'

describe process("redis") do
  it { should be_running }
end

Run test cases

$ rake spec

More resource types

http://serverspec.org/resource_types.html

serverspec