Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

Ansibleで遊んでみる(3)

前回作ったロールはロール名に"-"が入っていて、これはどうも良くないらしいので名前を直した。

さて、前回はテスト用のタスクだったけど、今度はホントにgroupを作ってみよう。

実際にテストとして走らせるplaybookは、molecule/default/converge.ymlとなる。

---
- name: Converge
  hosts: all
  tasks:
    - name: "Include usergroup"
      include_role:
        name: "usergroup"
        vars_from: "test"

ここでテスト用の変数ファイルを読み込む様に指定する。

テスト用変数ファイル(vars/test.yml)はこんな感じ。

---
usergroups:
  - { name: "hoge", gid: 7777 }
  - { name: "fuga", gid: 8888 }

タスクを書いてみる。tasks/main.ymlはこんな感じ。

---
- name: Make groups
  group:
    name: "{{ item.name }}"
    gid: "{{ item.gid }}"
  loop: "{{ usergroups }}"

実行してみる。

> molecule converge
INFO     default scenario test matrix: dependency, create, prepare, converge
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > create
INFO     Sanity checks: 'docker'

PLAY [Create] ******************************************************************

TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item={'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False', 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item', 'i': 0, 'ansible_index_var': 'i'})

TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/pycontribs/centos:8)

TASK [Create docker network(s)] ************************************************

TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: Wait for instance(s) creation to complete (300 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '506425403898.18190', 'results_file': '/Users/tambara/.ansible_async/506425403898.18190', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0

INFO     Running default > prepare
WARNING  Skipping, prepare playbook not configured.
INFO     Running default > converge

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [inst]

TASK [Include usergroup] *******************************************************

TASK [usergroup : Make groups] *************************************************
changed: [inst] => (item={'name': 'hoge', 'gid': 7777})
changed: [inst] => (item={'name': 'fuga', 'gid': 8888})

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

確認する

> molecule login
INFO     Running default > login
[root@inst /]# cat /etc/group
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
(中略)
dbus:x:81:
input:x:999:
kvm:x:36:
render:x:998:
systemd-journal:x:190:
systemd-coredump:x:997:
systemd-resolve:x:193:
ssh_keys:x:996:
hoge:x:7777:
fuga:x:8888:

これに対するassertを書く。molecure/default/verify.ymlをこう書き換える。

---
# This is an example playbook to execute Ansible tests.

- name: Verify
  hosts: all
  gather_facts: false
  tasks:
  - shell: grep hoge /etc/group |grep -q 7777
    register: hoge
  - shell: grep fuga /etc/group |grep -q 8888
    register: fuga
  - name: Example assertion
    assert:
      that:
        - hoge.rc == 0
        - fuga.rc == 0

こんなんでいいのかな?

実行してみる。

> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
changed: [inst]

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
ok: [inst] => {
    "changed": false,
    "msg": "All assertions passed"
}

PLAY RECAP *********************************************************************
inst                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Verifier completed successfully.

わかりにくい・・・。

試しに、grep hoge...の行の最後の7777を8888に変えてみる。

実行するとテストがfailになる。

> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
fatal: [inst]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": "grep hoge /etc/group |grep -q 8888", "delta": "0:00:00.003928", "end": "2021-03-07 09:08:57.065460", "msg": "non-zero return code", "rc": 1, "start": "2021-03-07 09:08:57.061532", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

PLAY RECAP *********************************************************************
inst                       : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

CRITICAL Ansible return code was 2, command was: ansible-playbook --inventory /Users/tambara/.cache/molecule/usergroup/default/inventory --skip-tags molecule-notest,notest /Users/tambara/study/ansible_study/roles/usergroup/molecule/default/verify.yml

assertに入る前にエラーになってる。

ignore_errors: trueしてみる。

---
- name: Verify
  hosts: all
  gather_facts: false
  ignore_errors: true
  tasks:
  - shell: grep hoge /etc/group |grep -q 8888
    register: hoge
  - shell: grep fuga /etc/group |grep -q 8888
    register: fuga
  - name: Example assertion
    assert:
      that:
        - hoge.rc == 0
        - fuga.rc == 0

実行してみる。

> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
fatal: [inst]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": "grep hoge /etc/group |grep -q 8888", "delta": "0:00:00.005223", "end": "2021-03-07 09:21:12.978052", "msg": "non-zero return code", "rc": 1, "start": "2021-03-07 09:21:12.972829", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
fatal: [inst]: FAILED! => {
    "assertion": "hoge.rc == 0",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}
...ignoring

PLAY RECAP *********************************************************************
inst                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=2

INFO     Verifier completed successfully.

assertもignoreされた。これではダメだ。

shellモジュールに個別にignore_errors: trueを付けたら、上手くいったが、これはこれでテストの失敗がわかりづらい。

---
- name: Verify
  hosts: all
  gather_facts: false
  tasks:
  - shell: grep hoge /etc/group |grep -q 8888
    ignore_errors: true
    register: hoge
  - shell: grep fuga /etc/group |grep -q 8888
    ignore_errors: true
    register: fuga
  - name: Example assertion
    assert:
      that:
        - hoge.rc == 0
        - fuga.rc == 0
> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
fatal: [inst]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": "grep hoge /etc/group |grep -q 8888", "delta": "0:00:00.003725", "end": "2021-03-07 09:24:25.994889", "msg": "non-zero return code", "rc": 1, "start": "2021-03-07 09:24:25.991164", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
fatal: [inst]: FAILED! => {
    "assertion": "hoge.rc == 0",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=2    unreachable=0    failed=1    skipped=0    rescued=0    ignored=1

CRITICAL Ansible return code was 2, command was: ansible-playbook --inventory /Users/tambara/.cache/molecule/usergroup/default/inventory --skip-tags molecule-notest,notest /Users/tambara/study/ansible_study/roles/usergroup/molecule/default/verify.yml

とりあえず、これで全体を実行してみる。

> molecule test
INFO     default scenario test matrix: dependency, lint, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > lint
COMMAND: yamllint .
ansible-lint
flake8

./molecule/default/verify.yml
  17:1      error    too many blank lines (1 > 0)  (empty-lines)

WARNING  Listing 9 violation(s) that are fatal
You can skip specific rules or tags by adding them to your configuration file:

┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ # .ansible-lint                                                                                                      │
│ warn_list:  # or 'skip_list' to silence them completely                                                              │
│   - '201'  # Trailing whitespace                                                                                     │
│   - '301'  # Commands should not change things if nothing needs doing                                                │
│   - '502'  # All tasks should be named                                                                               │
│   - '701'  # meta/main.yml should contain relevant info                                                              │
│   - '703'  # meta/main.yml default values should be changed                                                          │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
701 Role info should contain platforms
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: author
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: company
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: license
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

301 Commands should not change things if nothing needs doing
molecule/default/verify.yml:6
Task/Handler: shell grep hoge /etc/group |grep -q 7777

502 All tasks should be named
molecule/default/verify.yml:6
Task/Handler: shell grep hoge /etc/group |grep -q 7777

301 Commands should not change things if nothing needs doing
molecule/default/verify.yml:9
Task/Handler: shell grep fuga /etc/group |grep -q 8888

502 All tasks should be named
molecule/default/verify.yml:9
Task/Handler: shell grep fuga /etc/group |grep -q 8888

201 Trailing whitespace
molecule/default/verify.yml:14
      that:

INFO     Running default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Running default > destroy
INFO     Sanity checks: 'docker'

PLAY [Destroy] *****************************************************************

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
ok: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '352555244554.23499', 'results_file': '/Users/tambara/.ansible_async/352555244554.23499', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

TASK [Delete docker network(s)] ************************************************

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     Running default > syntax

playbook: /Users/tambara/study/ansible_study/roles/usergroup/molecule/default/converge.yml
INFO     Running default > create

PLAY [Create] ******************************************************************

TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item={'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False', 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item', 'i': 0, 'ansible_index_var': 'i'})

TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/pycontribs/centos:8)

TASK [Create docker network(s)] ************************************************

TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: Wait for instance(s) creation to complete (300 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '929437985046.23918', 'results_file': '/Users/tambara/.ansible_async/929437985046.23918', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0

INFO     Running default > prepare
WARNING  Skipping, prepare playbook not configured.
INFO     Running default > converge

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [inst]

TASK [Include usergroup] *******************************************************

TASK [usergroup : Make groups] *************************************************
changed: [inst] => (item={'name': 'hoge', 'gid': 7777})
changed: [inst] => (item={'name': 'fuga', 'gid': 8888})

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Running default > idempotence

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [inst]

TASK [Include usergroup] *******************************************************

TASK [usergroup : Make groups] *************************************************
ok: [inst] => (item={'name': 'hoge', 'gid': 7777})
ok: [inst] => (item={'name': 'fuga', 'gid': 8888})

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Idempotence completed successfully.
INFO     Running default > side_effect
WARNING  Skipping, side effect playbook not configured.
INFO     Running default > verify
INFO     Running Ansible Verifier

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
changed: [inst]

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
ok: [inst] => {
    "changed": false,
    "msg": "All assertions passed"
}

PLAY RECAP *********************************************************************
inst                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Verifier completed successfully.
INFO     Running default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Running default > destroy

PLAY [Destroy] *****************************************************************

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '477983483623.24900', 'results_file': '/Users/tambara/.ansible_async/477983483623.24900', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

TASK [Delete docker network(s)] ************************************************

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     Pruning extra files from scenario ephemeral directory

Lintはいっぱい怒られているけど、とりあえず、一通りは流れたようだ。