免責
超やっつけのコードなので、ざっくりとした動作しか見てないです
前提
こんな環境下での話ですよ。というメモ
$ 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のホストリストに使う簡易レシピ」はこちら
# 前略
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()がそれっぽいので、代用する。
出来上がったのがこちら
# 前略
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を突っ込む運用で間に合わせています。
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()