最近Ansibleの資格試験を準備していて、Ansible Automation Platform(以下AAPとする)には、レポジトリにある.pyのDynamic Inventoryはなかなか表示されないことがありました。この記事ではDynamic Inventory Fileを表示させた方法を書きます。
環境定義と問題再現 (解決方法は一番最後に)
まずはテストするために、以下のファイルを定義しました。
環境定義
inventory
[lb]
servera.lab.example.com
[web]
serverb.lab.example.com
serverc.lab.example.com
ansible.cfg
[defaults]
inventory=inventory
hello_world.yml
- name: Hello World Sample
  hosts: all
  gather_facts: no
  tasks:
    - name: Hello Message
      debug:
        msg: "Hello World!"
dynamic_inventory.py
#! のパスは各自Python3に指定する必要があると思います
#!/bin python3
import json
def get_inventory():
    inventory = {
        'lb': {
            'hosts': ['servera.lab.example.com']
        },
        'web': {
            'hosts': ['serverb.lab.example.com', 'serverc.lab.example.com']
        },
        '_meta': {
            'hostvars': {}
        }
    }
    return inventory
def main():
    import sys
    if len(sys.argv) == 2 and (sys.argv[1] == '--list' or sys.argv[1] == '--host'):
        if sys.argv[1] == '--list':
            print(json.dumps(get_inventory()))
        elif sys.argv[1] == '--host':
            print(json.dumps({}))
    else:
        print("Usage: %s --list | --host <hostname>" % sys.argv[0])
        sys.exit(1)
if __name__ == '__main__':
    main()
一部コマンドの実行結果
tree and ll
# tree
.
├── ansible.cfg
├── dynamic_inventory.py
├── hello_world.yml
└── inventory
# ll
total 16
-rw-rw-r--. 1 student student   31 May 26 02:39 ansible.cfg
-rw-rw-r--. 1 student student  735 May 26 02:49 dynamic_inventory.py
-rw-rw-r--. 1 student student  135 May 26 02:39 hello_world.yml
-rw-rw-r--. 1 student student   85 May 26 02:43 inventory
# ansible-playbook hello_world.yml
PLAY [Hello World Sample] *************************************************************
TASK [Hello Message] ******************************************************************
ok: [servera.lab.example.com] => {
    "msg": "Hello World!"
}
ok: [serverb.lab.example.com] => {
    "msg": "Hello World!"
}
ok: [serverc.lab.example.com] => {
    "msg": "Hello World!"
}
PLAY RECAP ****************************************************************************
servera.lab.example.com      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb.lab.example.com      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc.lab.example.com      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
# ansible-playbook -i dynamic_inventory.py hello_world.yml
[WARNING]: * Failed to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py with script plugin: problem running
/home/student/git-repos/advanced-inventory/dynamic_inventory.py --list ([Errno 13] Permission denied: '/home/student/git-repos/advanced-inventory/dynamic_inventory.py')
[WARNING]: * Failed to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py with ini plugin: /home/student/git-
repos/advanced-inventory/dynamic_inventory.py:2: Expected key=value host variable assignment, got: json
[WARNING]: Unable to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Hello World Sample] *************************************************************
skipping: no hosts matched
PLAY RECAP ****************************************************************************
ansible-playbook hello_world.yml
$ ansible-playbook hello_world.yml
PLAY [Hello World Sample] *************************************************************
TASK [Hello Message] ******************************************************************
ok: [servera.lab.example.com] => {
    "msg": "Hello World!"
}
ok: [serverb.lab.example.com] => {
    "msg": "Hello World!"
}
ok: [serverc.lab.example.com] => {
    "msg": "Hello World!"
}
PLAY RECAP ****************************************************************************
servera.lab.example.com      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb.lab.example.com      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc.lab.example.com      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
# ansible-playbook -i dynamic_inventory.py hello_world.yml
[WARNING]: * Failed to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py with script plugin: problem running
/home/student/git-repos/advanced-inventory/dynamic_inventory.py --list ([Errno 13] Permission denied: '/home/student/git-repos/advanced-inventory/dynamic_inventory.py')
[WARNING]: * Failed to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py with ini plugin: /home/student/git-
repos/advanced-inventory/dynamic_inventory.py:2: Expected key=value host variable assignment, got: json
[WARNING]: Unable to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Hello World Sample] *************************************************************
skipping: no hosts matched
PLAY RECAP ****************************************************************************
ansible-playbook -i dynamic_inventory.py hello_world.yml
$ ansible-playbook -i dynamic_inventory.py hello_world.yml
[WARNING]: * Failed to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py with script plugin: problem running
/home/student/git-repos/advanced-inventory/dynamic_inventory.py --list ([Errno 13] Permission denied: '/home/student/git-repos/advanced-inventory/dynamic_inventory.py')
[WARNING]: * Failed to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py with ini plugin: /home/student/git-
repos/advanced-inventory/dynamic_inventory.py:2: Expected key=value host variable assignment, got: json
[WARNING]: Unable to parse /home/student/git-repos/advanced-inventory/dynamic_inventory.py as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Hello World Sample] *************************************************************
skipping: no hosts matched
PLAY RECAP ****************************************************************************
再現
この状態でAAPにおいて、Inventoryを作成して、SourceをSourced from a Projectに指定しても、Inventory fileには作成していたdynamic_inventory.pyは表示されることがなく、inventoryしかなかったです。
もちろん手動で入力してもエラーになりました。
解決方法
dynamic inventoryは実行可能なファイルでないといけないことが分かり、以下のコマンドを実行すれば無事に反映されました。
chmod +x dynamic_inventory.py
# ProjectにPushして、AAP ProjectでSyncを行います。
git add dynamic_inventory.py
git commit -m "add x to dynamic inventory"
git push
最後に
Ansible Dynamic Inventoryの知識は以前から頭に入っていましたが、実践経験が少なかったため、実際の問題に出会った際、Ansible Documentを調べていても、操作していてもpyファイルを認識されていなく、慌てていました。実際一度手で触って見れば、二度と忘れることのない解決方法でした。やはり、知識の吸収よりは、実践経験を積むのですね。

