ちょっと話題の記事

Ansibleのテストで使いたい8つのServerspec

2017.03.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。

Ansibleを使っている皆様、テスト書いてますか?

え、書いてない?

no-test

弊社では、社内共有しているAnsibleのRoleの検証にServerspecを利用しています。 今日はよく使うリソースタイプを紹介します。

テストの流れ

テストのフレームワークとしてはTest Kitchenを利用しています(kitchen-ansiblepushを利用したAnsible roleのテスト環境構築)。 はじめに、Test KitchenのEC2 Driverを利用し、AWS環境にEC2インスタンスを作成します。 次に、ひとつのRoleを実行するAnsibleのPlaybookを流します。 続けて、サーバの状態が期待された状態になっているかをServerspecで検証します。 最後に、AWS環境にEC2インスタンスが破棄されます(検証失敗時は破棄されない)。

test

Ansibleでもテストの仕組みが提供されています。 しかし、ユニットテストに近い仕組みであり、実際に起動したEC2インスタンスに適用できるかは保障されません。 このため、インテグレーションテストに近いテストの仕組みを採用しています(Ansibleのテスト事情)。

specファイルでの検証

テストの検証にはServerspecを利用します。 Serverspecでは、サーバの状態を「こうあるべきだ」というDSL風に記述します。 ほとんどのケースで同じように書けばいいので、基本的にコピペで大丈夫です。 「こういう時はどうするんだろう?」という時にドキュメントを参照しましょう。

サービスの状態を検証する

httpdやその他サービスがインストールされていることを検証するには、serviceを利用します。

describe service('httpd') do
  it { should be_running }
  it { should be_enabled }
end

serviceの引数を変更すれば、他のサービスでも同様に検証できるでしょう。 be_enabledで、サービスの自動起動が有効化されていること検証します。

なお、インストールされていないことを確認するには、以下のようにshould_notを使います。

# iptables should be disabled
describe service('iptables') do
  it { should_not be_running }
  it { should_not be_enabled }
end

プロセスが起動していることを検証する

httpdのようにサービスとして設定されていない場合、processを利用することで、プロセスとして起動しているかを検証出来ます。

describe process("amazon-ssm-agent") do
  it { should be_running }
end

パッケージの存在を検証する

パッケージがインストールされていることを検証するにはpackageを利用します。

describe package('awscli') do
  it { should be_installed.by('pip') }
end

この例では、be_installedだけではなく、さらにそのパッケージがpipでインストールされていることまでを検証しています。 .by('pip')は省略できます。

変更したファイルの内容を検証する

テキストファイルの内容を検証するには、fileを利用します。 さらに、以下のような書式でcontent(本文)を正規表現などで検証してください。

describe file('/etc/sysconfig/i18n') do
  its(:content) { should match /LANG=ja_JP\.UTF-8/ }
end

この書き方を知っていれば概ね問題無いと思います。

ディレクトリの存在を検証する

作成したディレクトリの存在を検証するには、fileを利用します。

describe file('/opt/classmethod/monitoring') do
  it { should be_directory }
  it { should be_owned_by 'cm-mon' }
  it { should be_grouped_into 'cm-mon' }
end

属性は、be_directorybe_owned_byなどで検証しましょう。

ユーザとグループの存在を検証する

作成したユーザやグループの存在を確認するには、groupuserを利用します。

describe group('cm-mon') do
  it { should exist }
end

describe user('cm-mon') do
  it { should exist }
end

cronの設定を検証する

cronの設定はcronで検証します。

describe cron do
  it { should have_entry('*/5 * * * * /opt/classmethod/monitoring/diskUsage.sh').with_user('cm-mon') }
  it { should have_entry('*/5 * * * * /opt/classmethod/monitoring/memoryUsage.sh').with_user('cm-mon') }
end

コマンドの実行結果を検証する

Roleで色々設定した結果、あるコマンドを実行して確認したいというケースは多いです。 そんな時は、commandを利用します。

describe command('date') do
  its(:stdout) { should match /JST/ }
end

システムのタイムゾーンを変更した後、dateコマンドを実行して、結果にJSTが含まれることを検証しています。 この辺りがインテグレーションテスト的な検証ですね。

まとめ

今回紹介したリソースを利用すれば、9割以上のスペック(テスト)は書けると思います。 スペックの書き方はほとんど変わらないので、Roleを作ったら息を吸うようにスペックを書きましょう。

さばんなちほーでも「Ansible Roleのテスト書いてるぜ」と言えるようにしてください。