serverspecでZabbixサーバの稼働テストを書いてみた

先日http:/http://togetter.com/li/501076togetter.com/li/501076(5/10)開催されたProvisioning Frameworks Casual Talks vol.1に参加しました。
Provisioning Frameworks Casual Talks vol.1の中身は他の方がたくさんブログを書かれているのでそちらを参照して下さい。

Provisioning Frameworks Casual Talks vol.1 - Togetter

serverspecの話がたくさん出てきたので自分も試しにservespecを使ってテストコードを書いてみました。
ついでに、serverspecのver.0.3.0から利用できるようになったattributeの機能も使ってみました。

serverspecのattributeはこちらを参考にしました。

今回テストコードを書いたのは、Zabbixサーバが正しい状態で稼働しているかのテストです。
以下のようなテストを書いています。

前提条件
Zabbixサーバのテスト
  • 必要なパッケージがインストールされていること
  • Zabbixプロセスが稼働していること
  • Zabbixの初期起動設定がされていること
  • Zabbixの起動ユーザが作成されていること
  • Zabbixが正しいポートでリッスンしていること
  • Zabbixの設定ファイル(zabbix_server.conf)に最低限の設定(DB設定が行われていること)
MySQLサーバのテスト
  • 必要なパッケージがインストールされていること
  • MySQLプロセスが稼働していること
  • MySQLの初期起動設定がされていること
  • MySQLの起動ユーザが作成されていること
  • MySQLが正しいポートでリッスンしていること
  • MySQLの設定ファイル(/etc/my.cnf)にZabbix監視する上で有用な設定が行われていること
Apacheのテスト
  • 必要なパッケージがインストールされていること
  • httpdプロセスが稼働していること
  • httpdの初期起動設定がされていること
  • httpdの起動ユーザが作成されていること
  • httpdが正しいポートでリッスンしていること
  • httpdのzabbix用設定ファイル(/etc/httpd/conf.d/zabbix.conf)にZabbixのフロントエンドを利用する上で有用なphpのパラメータ設定が行われていること
実際に書いたテスト

実際に作成したファイルは次のようになります。
なお、今回は全て同じサーバ上で稼働している前提で以下のようにspecファイル類を作成しました。

$ serverspec-init
Select a backend type:

  1) SSH
  2) Exec (local)
  3) Puppet providers (local)

Select number: 2

attributes.yml
(設定は環境に応じて書き換えて下さい)

zabbix_server:
    :listen_port: 10051
    :user: zabbix
    :db_name: zabbix
    :db_user: zabbix
    :db_password: zabbixpassword
    :db_socket: /var/lib/mysql/mysql.sock
mysql_server:
    :listen_port: 3306
    :user: mysql
    :innodb_buffer_pool_size: 64M
    :innodb_log_file_size: 16M
    :innodb_log_files_in_group: 2
httpd:
    :listen_port: 80
    :user: apache
    :max_execution_time: 300
    :memory_limit: 128M
    :post_max_size: 16M
    :upload_max_filesize: 2M
    :max_input_time: 300
    :timezone: Asia/Tokyo

Rakefile
(attributes.ymlから値を取得し、サービス毎にテストができるよう設定)

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

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

desc "Run serverspec to all services"
task :serverspec => 'serverspec:all'

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

spec/spec_helper.rb
(attrubutes.ymlから値を取得し、各サービス毎に属性値を設定)

require 'serverspec'
require 'pathname'
require 'yaml'
### include requirements ###

include Serverspec::Helper::Exec
include Serverspec::Helper::DetectOS
include Serverspec::Helper::Attributes

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

RSpec.configure do |c|
  if ENV['ASK_SUDO_PASSWORD']
    require 'highline/import'
    c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
  else
    c.sudo_password = ENV['SUDO_PASSWORD']
  end
  c.before :all do
    c.os = backend(Serverspec::Commands::Base).check_os
  end
  attr_set attributes[ENV['TARGET_SERVICE']]
end

spec/localhost/zabbix_server_spec.rb

require 'spec_helper'

describe 'zabbix-server' do
    it { should be_installed }
    it { should be_enabled }
    it { should be_running   }
end

### related package install check ###
%w(zabbix-release zabbix-server-mysql zabbix-web-mysql zabbix-web zabbix-web-japanese zabbix zabbix-get).each do |pkg|
    describe pkg do
        it { should be_installed }
    end
end

describe attr[:user] do
    it { should be_user }
end

describe "port #{attr[:listen_port]}" do
    it { should be_listening }
end

describe '/etc/zabbix/zabbix_server.conf' do
    it { should be_file }
    it { should contain "DBName=#{attr[:db_name]}" }
    it { should contain "DBUser=#{attr[:db_user]}" }
    it { should contain "DBPassword=#{attr[:db_password]}" }
    it { should contain "DBSocket=#{attr[:db_socket]}" }
end

spec/localhost/mysql_server_spec.rb

require 'spec_helper'

describe 'mysql55-server' do
    it { should be_installed }
end

describe 'mysqld' do
    it { should be_enabled }
    it { should be_running }
end

describe attr[:user] do
    it { should be_user }
end

describe "port #{attr[:listen_port]}" do
    it { should be_listening }
end

describe '/etc/my.cnf' do
    it { should be_file }
    it { should contain "innodb_file_per_table" }
    it { should contain "innodb_buffer_pool_size=#{attr[:innodb_buffer_pool_size]}" }
    it { should contain "innodb_log_file_size=#{attr[:innodb_log_file_size]}" }
    it { should contain "innodb_log_files_in_group=#{attr[:innodb_log_files_in_group]}" }
    it { should contain "character-set-server=utf8" }
end

spec/localhost/httpd_spec.rb

require 'spec_helper'

describe 'httpd' do
    it { should be_installed }
    it { should be_enabled   }
    it { should be_running   }
end

describe attr[:user] do
    it { should be_user }
end

describe "port #{attr[:listen_port]}" do
    it { should be_listening }
end

describe '/etc/httpd/conf.d/zabbix.conf' do
    it { should be_file }
    it { should contain "php_value max_execution_time #{attr[:max_execution_time]}" }
    it { should contain "php_value memory_limit #{attr[:memory_limit]}" }
    it { should contain "php_value post_max_size #{attr[:post_max_size]}" }
    it { should contain "php_value upload_max_filesize #{attr[:upload_max_filesize]}" }
    it { should contain "php_value date.timezone #{attr[:timezone]}" }
end

実行するとこんな感じ

$ rake serverspec
/usr/bin/ruby -S rspec spec/localhost/zabbix_server_spec.rb
.................

Finished in 0.61575 seconds
17 examples, 0 failures
/usr/bin/ruby -S rspec spec/localhost/mysql_server_spec.rb
...........

Finished in 0.31917 seconds
11 examples, 0 failures
/usr/bin/ruby -S rspec spec/localhost/httpd_spec.rb
...........

Finished in 0.26358 seconds
11 examples, 0 failures

まだまだ勉強不足なため記述がこれで正しいのかは怪しいですが、非常に簡単にサーバの状態をテストできるので活用できそうです。
attributeの機能のおかげでテストコードの使い回しがとてもやりやすくなっているかと思います。