Moleculeとは
Ansible Roleのテストツールです。
Ansibleは便利ですが、実際の開発にしっかり使おうとすると作ったPlaybook自体の品質を確保することが重要になってきます。
また、実際に環境に流してみないと分からないエラーもあったりして、結構大変だと思います。
そこで使えるのがこのMoleculeです。Ansibleで作ったPlaybookの部品(Role)単位で、テストを実行することができます。
何をしてくれるのか
- Lint … PlaybookがYAMLの文法に従っているか
- Provision … Playbookが実際にAnsibleを使用してちゃんと実行できるかと、2回目の実行で不要な変更が入らないか
- Verify … 別のテストツールを使って作った環境をテスト
Lint
YAMLの文法に従っているかどうかをチェックします。
例) インデント、リストの書き方、変数の書き方などなど
Lintに何のソフトを使うかは後述のmolecule.yml
で指定できますが、特に要件がなければ普通はYAML Lintでいいと思います。
Provision
Playbookが実際にAnsibleで読み込めて実行できるかをチェックします。ついでに、Ansible観点でのLintもここでします。
Lintの例) モジュール名が間違ってないか、非推奨の機能を使っていないか、潜在的なバグの原因になるような記載方法がないか
実行には、テスト用のインスタンスを作成して、そこに対してPlaybookを実行します。
どのような方法でテスト用のインスタンスを作成するかをMoleculeではDriver
と呼びます。デフォルトではDockerになっています。
Ansibleでは冪等性という考え方があって、同じPlaybookを何度実行しても結果は同じになるべきという考え方があります。
これを確認するために同じインスタンスに2回Playbookが実行されます。2回目で不要な変更が入っていた場合はエラーとして出ます。
テストツール実行
別のテストツールを起動して、テスト用のインスタンスがちゃんと構築できているかを確認します。
別途テストコードを書く必要があります。
デフォルトではTestInfraが指定されていて、tests
フォルダにテストコードを配置します。
実際に使う
インストール
python >= 3.6, Ansible >= 2.8 が必要です。
インストールはpipで行います。
python3 -m pip install --user "molecule[docker,lint]"
Dockerコンテナ
Moleculeがインストール済みのDockerコンテナがRedhatから提供されています。
docker pull quay.io/ansible/molecule
で取得できるので、こちらを使ってもよいです。
Dockerで使う場合は、カレントディレクトリをバインドしたりして、
docker run --rm -v ${PWD}:/work/some-role -w /work/some-role quay.io/ansible/molecule [Moleculeのコマンド]
などすれば使いやすいでしょう。some-roleは自分のrole名に置き換えてください。
注意として、このように使う場合はカレントディレクトリ名をRoleの名前に合わせておかないとMoleculeの実行が失敗します。
上記の例だと、/work
に直接Roleを展開して実行するとRole not foundとなってしまいます。
Role作成
Moleculeを使ったRoleを作成するには、Moleculeのコマンドを使用して、
molecule init role --role-name some-role --driver-name docker
とすると、--role-name
に指定した名前の空のRoleを作成してくれます。
作成されたRoleには、molecule
フォルダがあり、ここに各種の定義を書いていきます。
フォルダ構成はこんな感じになってます。
-
molecule
-
default
- tests
Dockerfile.j2
INSTALL.rst
molecule.yml
playbook.yml
-
default
defaultフォルダ
moleculeフォルダの直下にはdefaultという名前のフォルダがあります。
Moleculeでは複数のシナリオでテストを定義できますので、シナリオを複数作成したい場合はこのフォルダを分けます。
Dockerfile.j2
ドライバーとしてDockerを使用する場合に使用するDockerfileです。
自動生成なので基本的には触りません。
molecule.yml
Lintにやテストツールに何を使うかなどを書いています。
---
dependency:
name: galaxy
driver:
name: docker # ドライバーはデフォルトでDocker
lint:
name: yamllint # LintツールはデフォルトでYamllint
platforms:
- name: instance
image: centos:7 # Dockerドライバーを使用する場合、テスト用のインスタンスに何を使うか
provisioner:
name: ansible # プロビジョニングに何を使うか。デフォルトはAnsibleです
lint:
name: ansible-lint
verifier:
name: testinfra # テストに何を使うか。デフォルトはAnsibleです
lint:
name: flake8
playbook.yml
テスト用のインスタンスにRoleを適用する際に使うダミーPlaybookです。
基本的には変更しません。
---
- name: Converge
hosts: all
roles:
- role: ansible-role-test
テストの実行
いざ実行してみましょう。
実行コマンド
Roleのフォルダで、以下のように実行します。
molecule test --all
インスタンスの作成などを個別に実行することもできますが、ここでは割愛します。
実行結果
こんな感じで実行結果が出ます。
この場合はYAMLの文法にエラーが出ています。
$ molecule test --all
--> Validating schema /var/jenkins_home/workspace/Ansible-Molecule/molecule/default/molecule.yml.
Validation completed successfully.
--> Test matrix
└── default
├── lint
├── cleanup
├── destroy
├── dependency
├── syntax
├── create
├── prepare
├── converge
├── idempotence
├── side_effect
├── verify
├── cleanup
└── destroy
--> Scenario: 'default'
--> Action: 'lint'
--> Executing Yamllint on files found in /var/jenkins_home/workspace/Ansible-Molecule/...
/var/jenkins_home/workspace/Ansible-Molecule/tasks/main.yml
8:1 warning comment not indented like content (comments-indentation)
8:16 error no new line character at the end of file (new-line-at-end-of-file)
An error occurred during the test sequence action: 'lint'. Cleaning up.
--> Scenario: 'default'
--> Action: 'destroy'
PLAY [Destroy] *****************************************************************
TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=None)
changed: [localhost]
TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
ok: [localhost] => (item=None)
ok: [localhost]
TASK [Delete docker network(s)] ************************************************
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
どこがエラー内容かわかりますか?
/var/jenkins_home/workspace/Ansible-Molecule/tasks/main.yml
8:1 warning comment not indented like content (comments-indentation)
8:16 error no new line character at the end of file (new-line-at-end-of-file)
この2行ですね。
コメントのインデントが不正(エラーではなく警告)なのと、ファイル末尾に改行がないことでエラーになっています。
こんな感じで実行結果を見ながら一つ一つ直していきましょう。
CIツールとの連携
毎回毎回手でコマンドを実行してるのはやってられないので、CIツールと連携させて実行するのが良いと思います。
Jenkinsfileの例
以下はJenkinsで実行するための例(Jenkinsfile)です。
pipeline {
agent {
docker {
image 'quay.io/ansible/molecule'
args '-v /var/run/docker.sock:/var/run/docker.sock'
}
}
stages {
stage ('バージョンの表示') {
steps {
sh '''
docker -v
python -V
ansible --version
molecule --version
'''
}
}
stage ('Moleculeテスト実行') {
steps {
sh 'molecule test --all'
}
}
}
}