Posted at

Fabric のホストリストにAnsibleのインベントリを使う(2017年版)

More than 1 year has passed since last update.


免責

超やっつけのコードなので、ざっくりとした動作しか見てないです


前提

こんな環境下での話ですよ。というメモ


バージョンチェック

$ ansible --version

ansible 2.2.0.0
config file = /home/takei_kazuya/ansible/ansible.cfg
configured module search path = Default w/o overrides
$ fab --version
Fabric 1.12.0
Paramiko 1.17.2


TL;DR

最新バージョン向け「AnsibleのInventoryをFabricのホストリストに使う簡易レシピ」はこちら


fabfile.py

# 前略


from ansible.inventory import Inventory
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager

ansible_loader = DataLoader()
ansible_var_manager = VariableManager()
ansible_inventory = Inventory(ansible_loader, ansible_var_manager, '/etc/ansible/hosts')
env.roledefs = ansible_inventory.get_group_dict()

# 以下略



本題

構成管理にAnsibleをデプロイ系にFabricを採用するケースで、Ansibleのinventoryを使いたいというのは多分よくある話ではあって、Qiitaにも「FabricからAnsibleのインベントリを美味しく参照する」という記事もあります。

で、参照して(というかインベントリファイル以外コピペ)して実行すると、

# 前略

from ansible.inventory import Inventory

inventory = Inventory('MY_INVENTORY')
env.roledefs = inventory.groups_list()

# 攻略

Traceback (most recent call last):

File "/usr/lib/python2.6/site-packages/fabric/main.py", line 666, in main
docstring, callables, default = load_fabfile(fabfile)
File "/usr/lib/python2.6/site-packages/fabric/main.py", line 167, in load_fabfile
imported = importer(os.path.splitext(fabfile)[0])
File "/home/attakei/infra/fabfile.py", line 17, in <module>
ansible_inventory = Inventory(ansible_inventory_file)
TypeError: __init__() takes at least 3 arguments (2 given)

動かなかった。。。

以下、最新のリポジトリを見ながら少しずつ直していく。


Inventoryのinit時引数が違っている

上記のエラーの通り、どうやら__init__の引数が以前とは違っているっぽい?

現状のInventory.initを見ると、確かに引数は最低2個必要な上にinventoryファイルはオプションになっている模様。

じゃあ、最初のloader,variable_managerには何を渡せばいんんだろうか?

手っ取り早くansible-playbookの実体を見てみた。

loaderにはansible.parsing.dataloader.DataLoaderのインスタンス、 variable_managerにはansible.vars.VariableManagerのインスタンスをそれぞれ渡せば良さげな気がする。


groups_listがなくなっている

Inventory()実行時のエラーは上記で解消できるのだが、今度はinventory.groups_list()が失敗する。コードを見ると、このメソッドは今はない模様。

斜め読みした感じではInventory.get_group_dict()がそれっぽいので、代用する。


出来上がったのがこちら


fabfile.py

# 前略


from ansible.inventory import Inventory
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager

ansible_loader = DataLoader()
ansible_var_manager = VariableManager()
ansible_inventory = Inventory(ansible_loader, ansible_var_manager, '/etc/ansible/hosts')
env.roledefs = ansible_inventory.get_group_dict()

# 以下略



補足事項

上記のコードだとinventoryファイルを1個しか指定することができず、ちょっと使いづらいです。

この辺はfabricの側でもしかしたらスマートな手法があるかもしれないですが、自環境では暫定で環境変数にinventoryを突っ込む運用で間に合わせています。


fabfile.py

from fabric.api import env

from ansible.inventory import Inventory
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager

ansible_inventory_file = os.environ.get('INVENTORY', '/etc/ansible/hosts')
ansible_loader = DataLoader()
ansible_var_manager = VariableManager()
ansible_inventory = Inventory(ansible_loader, ansible_var_manager, ansible_inventory_file)
env.roledefs = ansible_inventory.get_group_dict()