LoginSignup
4

More than 5 years have passed since last update.

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

Posted at

免責

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

前提

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

バージョンチェック
$ 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()

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4