AWS の ElasticIP の一覧を取得するプラグインを例として、Ansible の lookup プラグインの作り方を解説します。
目次
lookup プラグインとは?
lookup プラグインとは、ファイルや API など外部からデータを取得して Ansible で利用するプラグインです。
lookup('プラグイン名')
もしくはwith_プラグイン名
のように使用する- よくある例では
with_items
が lookup プラグイン - プラグインに書かれているコードはローカルマシン上で実行される
- 作り方は Lookups — Ansible Documentation を参照
Ansible 本体の lookup プラグイン ansible/lib/ansible/plugins/lookup にたくさんサンプルがあるので、真似しながら書くと良いです。
ディレクトリ構成
それでは AWS の ElasticIP を取得する lookup プラグインを書いてみましょう。ディレクトリ構成はこんな感じ。
├── ansible.cfg
├── plugins
│ └── lookup
│ └── ec2_addresses.py
└── site.yml
plugins/lookup/ec2_addresses.py
AWS の ElasticIP の一覧を取得するプラグインの最小のコードは以下の通りです。ansible/plugins/lookup/aws_service_ip_ranges.py を参考に実装しました。
from __future__ import absolute_import, division, print_function
import boto3
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
ec2 = boto3.client('ec2')
addresses = ec2.describe_addresses()
return addresses['Addresses']
ansible.cfg
ansible.cfg に plugin の場所を指定します。
[defaults]
lookup_plugins = ./plugins/lookup
ansible.cfg の具体例は ansible/ansible.cfg を、それぞれの項目の詳細は Ansible Configuration Settings — Ansible Documentation から確認できます。
site.yml
プラグインの動作を確認する playbook です。プラグインから取得した値を ec2_addresses
変数に入れて、中身を for
ループで回してデバッグ表示しています。
- hosts: localhost
connection: local
vars:
ec2_addresses: "{{ lookup('ec2_addresses') }}"
tasks:
- name: "use list return option and iterate as a loop"
debug: msg="{% for address in ec2_addresses %}{{ address }} {% endfor %}"
playbook の実行
playbook を実行すると、以下のように boto3 で取得した変数の内容が表示できます。
$ OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES ansible-playbook site.yml
TASK [use list return option and iterate as a loop] ****
ok: [localhost] => {
"msg": "{'PublicIp': 'xxx.xxx.xxx.xxx', 'AllocationId': 'eipalloc-xxxxxxxx', ...}"
}
私の手元のマシン macOS High Sierra では debug モジュールを使用すると以下のエラーが出るので OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
の環境変数を指定しています。
objc[21237]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called.
objc[21237]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
パラメータを渡す
lookup プラグインにはパラメータを渡すことができます。さきほどのプラグインにパラメータを渡せるようにするには ec2_addresses.py に変更を加えます。パラメータは run
メソッドの terms
引数で渡されるので、受け取って適切に処理します。
from __future__ import absolute_import, division, print_function
import boto3
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
ret = []
if not terms:
terms = [{}]
for term in terms:
if 'region' in term:
ec2 = boto3.client('ec2', region_name=term['region'])
else:
ec2 = boto3.client('ec2')
address = ec2.describe_addresses()
ret.extend(address['Addresses'])
return ret
site.yml で以下のようにパラメータを渡します。
- hosts: localhost
connection: local
vars:
ec2_addresses: "{{ lookup('ec2_addresses', {region: 'ap-northeast-1'}) }}"
tasks:
- name: "use list return option and iterate as a loop"
debug: msg="{% for address in ec2_addresses %}{{ address }} {% endfor %}"
パラメータを扱えるプラグインは with_*
形式も使えるようになります。
- hosts: localhost
connection: local
tasks:
- name: "use list return option and iterate as a loop"
debug: msg="{{ item }}"
with_ec2_addresses:
- { region: "ap-northeast-1" }