Molecule 備忘録

Molecule は、 Ansible 向けのテストフレームワークです。 role 単体のテストしか試していませんが、複数の role を跨いだテストもできるかもしれません。

<!-- TOC depthFrom:2 -->

- [1. Molecule](#1-molecule)
- [2. 使い方](#2-使い方)
    - [2.1. Python の環境](#21-python-の環境)
    - [2.2. テストの追加](#22-テストの追加)
    - [2.3. テストの実行](#23-テストの実行)
- [3. 使ってみて](#3-使ってみて)

<!-- /TOC -->

## 1. Molecule

Ansible を書いていると冪等性を保つために `register` や `when` を使うわけですが、コード量が増えてくると意図した通りに動作しているのか不安になってきます。

Molecule を使うと仮想環境の準備から Ansible の実行、環境の破棄までを行ってくれます。

* YAML ファイルの静的解析 ( YAML lint / Ansible lint )
* 指定した仮想環境への Ansible playbook 流し込み
* Testinfra による構築環境の状態テスト
* Ansible playbook (role's task) の冪等性検証

Molecule では、 Ansible を流し込む仮想環境を Driver と呼んでおり、いくつか用意されています。デフォルトの Driver は、 Docker です。 ( 私が試したのも Docker です )

* Azure
* Delegated
* Docker (Default)
* EC2
* GCE
* LXC
* LXD
* Openstack
* Vagrant
* Molecule Vagrant Module

## 2. 使い方

以下、テストの実行環境は Ubuntu 16.04 です。

### 2.1. Python の環境

何はともあれ、 Python の環境を整えます。以下、 [pyenv](https://github.com/pyenv/pyenv) と [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv) を使う場合の手順です。

```console
$ pyenv install 3.6.5
$ pyenv virtualenv 3.6.5 molecule-py3
$ pyenv shell molecule-py3
```

必要な Python パッケージをインストールします。この記事を書いた時点でのインストールパッケージのバージョンです。

package   | version
----------|---------
ansible   | 2.5.2
molecule  | 2.13.1
docker-py | 1.10.6

```console
$ pip install ansible molecule docker-py
$ pip list --format=columns
pip list --format=columns
Package          Version
---------------- ---------
ansible          2.5.2
ansible-lint     3.4.21
anyconfig        0.9.4
arrow            0.12.1
asn1crypto       0.24.0
attrs            18.1.0
bcrypt           3.1.4
binaryornot      0.4.4
Cerberus         1.1
certifi          2018.4.16
cffi             1.11.5
chardet          3.0.4
click            6.7
click-completion 0.3.1
colorama         0.3.9
cookiecutter     1.6.0
cryptography     2.2.2
docker-py        1.10.6
docker-pycreds   0.2.3
fasteners        0.14.1
flake8           3.5.0
future           0.16.0
git-url-parse    1.1.0
idna             2.6
Jinja2           2.10
jinja2-time      0.2.0
MarkupSafe       1.0
mccabe           0.6.1
molecule         2.13.1
monotonic        1.5
more-itertools   4.1.0
paramiko         2.4.1
pathspec         0.5.6
pbr              3.0.1
pexpect          4.2.1
pip              10.0.1
pluggy           0.6.0
poyo             0.4.1
psutil           5.2.2
ptyprocess       0.5.2
py               1.5.3
pyasn1           0.4.2
pycodestyle      2.3.1
pycparser        2.18
pyflakes         1.6.0
PyNaCl           1.2.1
pytest           3.5.1
python-dateutil  2.7.2
python-gilt      1.2.1
PyYAML           3.12
requests         2.18.4
setuptools       39.0.1
sh               1.12.14
six              1.11.0
tabulate         0.8.2
testinfra        1.12.0
tree-format      0.1.2
urllib3          1.22
websocket-client 0.47.0
whichcraft       0.4.1
yamllint         1.11.1
```

### 2.2. テストの追加

既存の Ansible Role にテストを追加する場合、 Role が配置されているディレクトリまで移動します。 Ansible の [Best Practices](http://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#directory-layout) に従っている場合、 `tasks`  や `files` ディレクトリが存在する場所です。

```console
$ cd /path/to/<role_name>
```

`molecule init scenario` で既存の Role に Molecule のテストを追加します。

```bash
$ molecule init scenario -r <role_name>
```

以下のファイルが生成されます。

```bash
$ tree molecule
molecule/
└── default
    ├── create.yml
    ├── destroy.yml
    ├── Dockerfile.j2
    ├── INSTALL.rst
    ├── molecule.yml
    ├── playbook.yml
    ├── prepare.yml
    └── tests
        ├── __pycache__
        │   └── test_default.cpython-36.pyc
        └── test_default.py

3 directories, 9 files
```

テストを走らせる前に `molecule.yml` と `test_default.py` を編集します。

`molecule.yml` に Driver と Ansible を流し込むイメージを指定します。 Driver が `docker` で、イメージが `Ubuntu 16.04` の場合、以下のように指定します。他の設定は [公式ドキュメント](http://molecule.readthedocs.io/en/latest/configuration.html) を参照してください。 [サンプルコード](https://github.com/metacloud/molecule/tree/master/test/scenarios/driver) も **一応** 用意されています。

```yaml
...
driver:
  name: docker
platform:
  - name: instance
    image: ubuntu:16.04
...
```

`test_default.py` にテストを記述します。テストには [testinfra](https://github.com/philpep/testinfra) が使われています。 Python 版の Serverspec 的な位置づけですかね。

### 2.3. テストの実行

この時点で一応 `molecule test` を実行できます。

```
$ sudo -E molecule test
```

`molecule test` はすべてのテストを実行するので、場合によっては非効率になります。例えば、 `molecule test` には環境の破棄まで含まれているので、エラーが発生したときに調査できなくなってしまいます。

Molecule には、 `test` 以外にもいくつかのコマンドが用意されていますので、使い分けると効率的にテストができます。

```
  check        Use the provisioner to perform a Dry-Run...
  converge     Use the provisioner to configure instances...
  create       Use the provisioner to start the instances.
  dependency   Manage the role's dependencies.
  destroy      Use the provisioner to destroy the instances.
  idempotence  Use the provisioner to configure the...
  init         Initialize a new role or scenario.
  lint         Lint the role.
  list         Lists status of instances.
  login        Log in to one instance.
  prepare      Use the provisioner to prepare the instances...
  side-effect  Use the provisioner to perform side-effects...
  syntax       Use the provisioner to syntax check the role.
  test         Test (lint, destroy, dependency, syntax,...
  verify       Run automated tests against instances.
```

よく使うのは `converge` と `destroy` ですかね。

`converge` は次のテストが含まれていて、環境の準備と Ansible の流し込みが行われます。

```console
└── default
    ├── dependency
    ├── create
    ├── prepare
    └── converge
```

環境は破棄されていないので、普通に `docker` のコマンドでコンテナの中に入れます。

```console
$ sudo docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS
         PORTS               NAMES
c12b3f5ab75f        molecule_local/ubuntu:16.04   "bash -c 'while true…"   22 minutes ago      Up 22 minutes                           instance
$ sudo docker exec -it c1 bash
root@instance:/#
```

`destroy` は、文字通り環境の破棄です。

## 3. 使ってみて

Ansible を含めて Molecule は、 Python で書かれているので環境の準備が簡単です。テストで面倒な環境の生成と破棄を行ってくれるのは非常に便利です ( Docker なので起動と終了も早い ) 。

ただ 1 点、日本語のドキュメントが少なくて困るので、備忘録として残しておきます。