はじめに
Rubygemsはgemコマンドでインストールしますが、当然ながらAnsibleにはそのモジュールがありません。
今回は、rbenvの環境でも使えるように、環境変数を使うためshellモジュールで実装します。
gem install
はすでに導入済みのgemについて再度実行しても問題ありませんが、毎回実行されるのは非効率なので、gem list
で導入済みかどうかを確認して、導入されていないものがある場合のみ実行するようにします。
また、バージョン指定/未指定に対応します。
ポイント
- shellモジュールはデフォルトでは
~/.bash_profile
を読まないので、bash -lc
で環境変数を読み込んでgemコマンドを実行する - インストール時、バージョン指定/未指定でコマンドを分ける
- インストール判定時、バージョン指定があればバージョンまで確認
- 個々のインストール判定結果のうち、失敗をlistに追加していき、要素数をカウントして1件でも失敗があればインストールタスクを実行する
- インストールタスクの終了コードを見てretryを実施
注意事項
shellモジュールで実装する都合上、アンインストールには対応していません。
Sample
ディレクトリ構成
ディレクトリ構成
├── roles
│ └── gems
│ └── tasks
│ └── main.yml
├── site.yml
└── vars
└── vars.yml
Role
roles/gems/tasks/main.yml
---
- name: Check gems installed
shell: >-
bash -lc "gem list | grep {{ item.name }}
{% if item.version is defined %}
| grep '({{ item.version }}[).]'
{%- endif -%}
| wc -l"
register: check_gem_install
changed_when: False
ignore_errors: yes
check_mode: no
with_items: "{{ my_vars.middlewares.gems | default([]) }}"
- name: Save Checking gems results
set_fact:
gem_chk: >-
{%- set cnt = [] -%}
{%- for i in check_gem_install.results -%}
{%- if i.stdout == "0" -%}
{%- set _ = cnt.append(i.stdout) -%}
{%- endif -%}
{%- endfor -%}
{{ cnt | length }}
changed_when: False
- name: install gems
shell: >-
bash -lc "gem install {{ item.name }}
{% if item.version is defined %}
-v {{ item.version }}
{%- endif %} --no-ri --no-rdoc"
register: result
until: result.rc == 0
retries: 5
delay: 10
with_items: "{{ my_vars.middlewares.gems | default([]) }}"
when: not ansible_check_mode and gem_chk != "0"
vars
vars/vars.yml
---
my_vars:
middlewares:
gems:
- name: bundler #バージョン指定なし
- name: serverspec
version: 2.38.1
- name: builder
version: 3.2.3
- name: rspec_junit_formatter
version: 0.2.3
site.yml
site.yml
---
- hosts: targethost
roles:
- role: gems
vars_files:
- ./vars/vars.yml
まとめ
shellモジュールやcommandモジュールを使う場合は、冪等性を担保するために色々と工夫が必要です。
ご参考になれば。