はじめに

Ansibleで変数が定義されていれば処理を行い、定義されていなければ処理を行わないというロジックはwhen: var_x is definedあるいはwhen: var_x is not definedで簡単に書ける。このような変数が大量にあるときのいい書き方を考える。

実行version: Ansible 2.6

yum installを例に

ミドルウェア/ライブラリ/言語などのinstallを一手に引き受けるroleを作成する。各ミドルウェアの設定roleでinstallしてもいいのだが、yum install以外にやることがないものもあるし、install処理をまとめて可読性を上げたり、依存関係の問題が起きにくいようにする目的もあって、一手に引き受けるroleを作成する。

Nginx, Apache, MySQL, Redis等のメジャーでどんなプロジェクトでも大抵使うミドルウェアのinstallはデフォルトで行ってもいいのだが、Node.js, MongoDB, RabbitMQ等は使わないプロジェクトも多く、変数が定義されたときだけinstallするようにしたい。

メジャーミドルウェアは何も考えずwith_itemsyumでinstallするとして、追加ミドルウェアの処理を考えたい。

when: var_x is definedをひとつずつ書く

yumリポジトリを追加する場合、templatecopyで追加する場合はwith_itemsでまとめて各ミドルウェアのリポジトリファイルをリモートサーバに送れるが、curlとbashを組み合わせてinstallするような仕組みの場合は次のようにひとつずつ実行するしかない。

- name: get repository(erlang)
  shell: |
    curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | bash -
  args:
    creates: /etc/yum.repos.d/rabbitmq_erlang.repo
  when: rabbitmq is defined

- name: get repository(rabbitmq)
  shell: |
    curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh | bash -
  args:
    creates: /etc/yum.repos.d/rabbitmq_rabbitmq-server.repo
  when: rabbitmq is defined

with_items + when: item.required

リポジトリ追加と違ってyum installを実行する場合はyumモジュールを使って統一的に実行できるためwith_itemsでループさせる。このときwith_itemsに渡すリストの定義方法に工夫ができる。

通常は次のように単純なリストを渡す。

- name: install basic middlewares
  yum:
    name: "{{ item }}"
    state: installed
    enablerepo: "nginx,{{ mysql.version }}-community,epel,remi,remi-{{ php.version }}"
  with_items:
    - nginx
    - httpd
    - httpd-devel
    - mod_ssl
    - mysql-community-server
    - mysql-community-devel
    - redis
略

今回は単純なリストではなくdictにして渡す。dictの要素としてyum.nameyum.enablerepoに渡す値を定義しているのだが、「Ansibleで変数が定義されているかどうかで処理の実行可否をわける」という目的のために定義するrequiredという要素が重要になる。

- name: install other middlewares
  yum:
    name: "{{ item.name }}"
    state: installed
    enablerepo: "{{ item.repo }}"
  when: item.required
  with_items:
    - { name: nodejs,             repo: "epel,nodesource",               required: "{{ nodejs is defined }}" }
    - { name: mongodb-org,        repo: "epel,mongodb-org",              required: "{{ mongo is defined }}" }
    - { name: mongodb-org-server, repo: "epel,mongodb-org",              required: "{{ mongo is defined }}" }
    - { name: erlang,             repo: "epel,rabbitmq_erlang",          required: "{{ rabbitmq is defined }}" }
    - { name: rabbitmq-server,    repo: "epel,rabbitmq_rabbitmq-server", required: "{{ rabbitmq is defined }}" }

required: "{{ var_x is defined }}"をすることで、変数が定義されているときはrequired: true、定義されていない時はrequired: falseとして解釈される。そのためwhen: item.requiredで各ループ処理時に条件判定させることで実行可否を分けることができる。