PR

Serverspecの効果的活用に向けたTips

2014年9月4日(木)
池田 大輔

テストコード内で利用する変数を別ファイルで管理

第2回の記事中で紹介したテストコードの例では、テストコードの中で変数を定義していました。しかし各テストコードの中で変数を定義していると、場合によっては同じ変数を複数のファイルの中に記載することになり、メンテナンスが煩雑になります。そこで、変数を別ファイルに切り出し、各テスト対象サーバ共通の変数設定と、あるサーバ固有の変数設定に分けて管理できるようにします。

  • YAMLファイルに変数に格納したい情報を記載
  • spec_helper.rbを変更し変数情報をセット
  • テストコード内で変数を展開

YAMLファイルに変数に格納したい情報を記載

先ほど作成したhosts.ymlに、変数として格納したい情報を記載します。ここでは、第2回で紹介したMySQLのテストコード中で利用したデータベースへの接続ユーザ名とパスワードを別ファイルに切り出して管理する場合の例です。

hosts.yml

server-01:
  :roles:
    - base
    - web
server-02:
  :roles:
    - base
    - db
  :db_user: root
  :db_password: password

DBサーバ(server-02)に対してのみdb_user、db_passwordの値を記述しています。

spec_helper.rbを変更し変数情報をセット

次に、hosts.ymlに記載した変数情報をServerspecのテストコード中で扱えるように、変数に登録します。ServerspecではSpecInfra::Helper::Propertiesというモジュールにset_propertyというメソッドが定義されています。このset_propertyというメソッドを利用すると、テストコード中で利用できる変数情報を登録できます。

変更後のspec_helper.rbは以下になります。

spec/spec_helper.rb

require 'serverspec'
require 'pathname'
require 'net/ssh'
require 'yaml'   # YAMLファイルを処理するライブラリの読込み

include SpecInfra::Helper::Ssh
include SpecInfra::Helper::DetectOS
include SpecInfra::Helper::Properties  # 変数処理用Propertiesモジュールの読込み

properties = YAML.load_file('hosts.yml')  # YAMLファイル読込み

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.host  = ENV['TARGET_HOST']
  set_property properties[c.host]  # テスト実行対象ホストの設定配下にあるProperty情報をセット
  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
  c.request_pty = true
end

全サーバで共通の情報やweb、dbなど役割に対して共通の情報を管理したい場合には、以下のようなYAMLファイル(properties.yml)を1つ追加し、spec_helper.rbを変更することで対応できます。

properties.yml

base:
  :dns_server: 172.19.1.34
db:
  :db_port: 3306
web:
  :web_port: 80

spec/spec_helper.rb

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

include SpecInfra::Helper::Ssh
include SpecInfra::Helper::DetectOS
include SpecInfra::Helper::Properties

host_properties = YAML.load_file('hosts.yml')
common_properties = YAML.load_file('properties.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.host  = ENV['TARGET_HOST']
  properties = host_properties[c.host]
  properties[:roles].each do |r|
    properties = common_properties[r].merge(host_properties[c.host]) if common_properties[r]
  end
  set_property properties
  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
  c.request_pty = true
end

変数を定義しているファイルが複数(上記の例では、hosts.ymlとproperties.yml)に分けられていても、set_propertyメソッドは各テスト実行対象ホストに対して1回のみ実行するという点に注意しましょう。これはset_propertyメソッドを実行すると、内部で一旦変数情報が初期化された後、引数で渡した変数群をセットする仕様だからです。そのためset_propertyを複数回呼び出すと、最後に実行したset_propertyのみが有効な状態になってしまいます。

テストコード内で変数を展開

spec_helper.rbで設定した値をテストコード内で呼び出すには、propertyという名前の変数を利用します。

spec/db/mysql_spec.rb

describe command("mysqlshow -u#{property[:db_user]}") do
  it { should return_stdout /zabbix/ }
end

テスト実行サーバ内の情報をもとにした分岐処理

より詳細に稼働状況を確認したいケースなどでは、サーバ内部の情報をもとに処理を振り分けたいといった場合もあるかと思います。第2回の記事中では、OSの情報をもとに分岐処理する方法を紹介しました。それ以外にも、任意のコマンドの実行結果をもとに処理を分岐させることも可能です。

テストコードの記述例

テスト実行対象サーバ内にあるファイルが存在していればテストAを、なければテストBを実行する例を紹介します。サーバ内部で処理を実行するにはbackend.run_commandを実行します。この結果はSpecInfra::CommandResultオブジェクトとして、以下の値を取得できます。

  • 標準出力の結果
  • 標準エラー出力の結果
  • 終了ステータスの結果
  • シグナルの受信結果
result = backend.run_command('ls <ファイルパス>')

if result[:exit_status] == 0
  テストAのコード
elsif
  テストBのコード
end
TIS株式会社

Twitter : @ike_dai
TIS株式会社OSS推進室所属。社内向けシステムの保守運用業務を経験後、クラウド時代の効率的な統合運用管理をテーマに活動中。特に、OSSを駆使した運用のエコシステム実現を目指し、Zabbix,fluentd,Serverspec,Ansibleなどの導入や検証に取り組む。技術検証成果などを技術ブログ『Tech-Sketch』にて発信中。著書:『Zabbix統合監視徹底活用 - 複雑化・大規模化するインフラの一元管理』

連載バックナンバー

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

他にもこの記事が読まれています