Ansible Tower(AWX) のインベントリースクリプトの使い方

スポンサーリンク

Ansible TowerまたはAWXでインベントリースクリプト(カスタムスクリプト)を使用する方法を説明します。Ansible Tower(AWX)にはvCenterやAWSと連携する機能が備わっていますが、スクリプトを書いて任意のホストやグループを動的に生成する事ができます。

インベントリースクリプトのユースケース

Ansible Tower(AWX)にはvCenterやAWSと連携する機能(ダイナミックインベントリ)が備わっていますが、以下のようなシナリオでは要件を満たす事ができません。

  • ダイナミックインベントリのデフォルトの挙動が許容されない(例えば、vCenterと連携させた時にホスト名末尾に表示されるUUIDを削除するように「偉い人」に指示された)
  • 設定のみで連携できないソフトウェアとの連携を作り込む必要がある(Cisco機器の管理製品, JP1ファミリーなど)

このようなシナリオが発生した時に有効になるのがインベントリースクリプト(カスタムスクリプト)です。

インベントリースクリプトの使い方

スクリプトの仕様

インベントリースクリプト(カスタムスクリプト)を作成するには、ホストやグループの一覧をJSON形式で標準出力するスクリプトを作成する必要があります。どのようなJSONフォーマットにすればよいかは、ansible-inventoryコマンドを使って調査すると良いでしょう。この辺りはマニュアルを読まなくても、ansible-inventoryコマンドの出力を見よう見真似でも充分実装できます。

まずはサンプルとなるインベントリースクリプトを作成します。

# cat <<EOF >inventory.ini
[ios:vars]
ansible_connection = network_cli
ansible_network_os = 'ios'
ansible_user = 'cisco'
ansible_password = 'cisco'

[eos:vars]
ansible_connection = network_cli
ansible_network_os = 'eos'
ansible_user = 'admin'
ansible_password = 'P@ssw0rd'

[ios]
ios171 ansible_host=192.168.1.171
ios172 ansible_host=192.168.1.172

[eos]
eos173 ansible_host=192.168.1.173
eos174 ansible_host=192.168.1.174
EOF

以下のようにansible-inventoryコマンドを使用すると、ini形式のインベントリファイルをJSON形式に変換する事ができます。このようなJSON形式を見よう見真似で出力すれば、カスタムスクリプトの開発は可能です。

# ansible-inventory -i inventory.ini --list
{
    "_meta": {
        "hostvars": {
            "eos173": {
                "ansible_connection": "network_cli",
                "ansible_host": "192.168.1.173",
                "ansible_network_os": "eos",
                "ansible_password": "P@ssw0rd",
                "ansible_user": "admin"
            },
            "eos174": {
                "ansible_connection": "network_cli",
                "ansible_host": "192.168.1.174",
                "ansible_network_os": "eos",
                "ansible_password": "P@ssw0rd",
                "ansible_user": "admin"
            },
            "ios171": {
                "ansible_connection": "network_cli",
                "ansible_host": "192.168.1.171",
                "ansible_network_os": "ios",
                "ansible_password": "cisco",
                "ansible_user": "cisco"
            },
            "ios172": {
                "ansible_connection": "network_cli",
                "ansible_host": "192.168.1.172",
                "ansible_network_os": "ios",
                "ansible_password": "cisco",
                "ansible_user": "cisco"
            }
        }
    },
    "all": {
        "children": [
            "eos",
            "ios",
            "ungrouped"
        ]
    },
    "eos": {
        "hosts": [
            "eos173",
            "eos174"
        ]
    },
    "ios": {
        "hosts": [
            "ios171",
            "ios172"
        ]
    }
}

インベントリースクリプトの登録

「インベントリースクリプト」の設定画面に遷移し、「+(追加)」ボタンを押下します。

インベントリースクリプトの登録01

今回は動作確認ですので、実践的ではありませんが以下のようなJSONファイルを標準出力するのみの単純なスクリプトを用意します。実践ではperlやpythonで動的なJSONファイルを生成する事になるでしょう。

#!/bin/bash
cat << EOF
{
  "ios_group": {
    "hosts": [
      "ios01",
      "ios02"
    ],
    "vars": {
      "ansible_password": "admin",
      "ansible_user": "admin"
    }
  }
}
EOF

インベントリースクリプトの登録02

CLIまたはAPIで操作する場合は以下の通りです。

CLI操作
# awx inventory_scripts create \
    --name "Cisco IOS scripts" \
    --description "" \
    --organization "スピードワゴン財団" \
    --script '#!/bin/bash
cat << EOF
{
  "ios_group": {
    "hosts": [
      "ios01",
      "ios02"
    ],
    "vars": {
      "ansible_password": "admin",
      "ansible_user": "admin"
    }
  }
}
EOF'
API操作
ORGANIZATION_ID=$(curl -u admin:P@ssw0rd \
  http://localhost/api/v2/organizations/ | \
  jq  '.results[] | select(.name == "スピードワゴン財団")' | jq ".id")

curl -XPOST -u admin:P@ssw0rd \
    --header "Content-Type: application/json" \
    -d @- http://localhost/api/v2/inventory_scripts/ << EOF
{
  "name": "Cisco IOS scripts",
  "description": "",
  "organization": ${ORGANIZATION_ID},
  "script": "#!/bin/bash\ncat << EOF\n{\n  \"ios_group\": {\n    \"hosts\": [\n      \"ios01\",\n      \"ios02\"\n    ],\n    \"vars\": {\n      \"ansible_password\": \"admin\",\n      \"ansible_user\": \"admin\"\n    }\n  }\n}\nEOF"
}
EOF

インベントリーソースの登録

「インベントリー」「ソース」の順に画面遷移し、「+(追加)」ボタンを押下します。

Ansible Tower インベントリソースの登録01

必要な情報を入力し「保存」を押下します。インベントリースクリプトを使用する場合は、「ソース」を「カスタムスクリプト」にします。

Ansible Tower インベントリソースの登録02

CLIで操作する場合は以下の通りです。awxのCLIは殆どの場合はidではなく名前による指定が可能ですが、例外的にインベントリスクリプトはid(数字)で指定する必要があります。

名前で指定できないのは意図した挙動ではなく、将来的に改善される可能性もあります。

CLI操作
INVENTORY_SCRIPTS_ID=$(awx inventory_scripts list -f jq \
  --filter '.results[] | select(.name == "Cisco IOS scripts")' | jq ".id")

awx inventory_sources create \
  --name "Cisco IOS Devices" \
  --description "" \
  --source "custom" \
  --source_script ${INVENTORY_SCRIPTS_ID} \
  --inventory "逸般の誤家庭"

APIで操作する場合は以下の通りです。

API操作
INVENTORY_ID=$(curl -u admin:P@ssw0rd \
  http://localhost/api/v2/inventories/ | \
  jq  '.results[] | select(.name == "逸般の誤家庭")' | jq ".id")

INVENTORY_SCRIPTS_ID=$(curl -u admin:P@ssw0rd \
  http://localhost/api/v2/inventory_scripts/ | \
  jq  '.results[] | select(.name == "Cisco IOS scripts")' | jq ".id")

curl -XPOST -u admin:P@ssw0rd \
    --header "Content-Type: application/json" \
    -d @- http://localhost/api/v2/inventory_sources/ << EOF
{
  "name": "Cisco IOS Devices",
  "description": "",
  "source": "custom",
  "source_script": ${INVENTORY_SCRIPTS_ID},
  "inventory": ${INVENTORY_ID}
}
EOF

インベントの同期

インベントリファイルの設定が終わったら、インベントリの「ソース」の設定画面に戻ります。設定直後に自動的に同期されるわけではありませんので、「同期」ボタンを押下しインベントリ情報を同期させます。

Ansible Tower インベントリソースの同期01

同期に成功した場合は、「雲(クラウド)」のアイコンが緑に変わります。

Ansible Tower インベントリソースの同期02

CLIで操作する場合は以下の通りです。inventory_source_idは環境に応じて適宜変更ください。また、–monitorオプションを付与すると同期の様子をリアルタイムで観察する事もできます。

CLI操作
awx inventory_sources update "Cisco IOS Devices" --monitor

Ansible Tower インベントリソースの同期03

APIで操作する場合は以下の通りです。同期の前後でstatusが”never updated”から”successful”に変わった事を確認できます。

API操作
INVENTORY_SOURCE_ID=$(curl -u admin:P@ssw0rd \
    http://localhost/api/v2/inventory_sources/ | \
    jq  '.results[] | select(.name == "Cisco IOS Devices")' | jq ".id")

# statusが"never updated"である事の確認
curl -u admin:P@ssw0rd \
    http://localhost/api/v2/inventory_sources/${INVENTORY_SOURCE_ID}/ | jq "."
 
 <omitted>
 
  "last_job_run": null,
  "last_job_failed": false,
  "next_job_run": null,
  "status": "never updated",
 
 <omitted>
 
curl -XPOST -u admin:P@ssw0rd \
   http://localhost/api/v2/inventory_sources/${INVENTORY_SOURCE_ID}/update/
 
# statusが"successful"である事の確認
curl -u admin:P@ssw0rd \
    http://localhost/api/v2/inventory_sources/${INVENTORY_SOURCE_ID}/ | jq "."

 <omitted>

  "last_job_run": "2020-08-23T11:50:09.846706Z",
  "last_job_failed": false,
  "next_job_run": null,
  "status": "successful",

 <omitted>

実践的なインベントリースクリプトの例

静的な結果を返すインベントリースクリプトではなく、やや実践的な例としてCisco DevNet SandboxのCisco DNA Centerに登録されている機器一覧を返すインベントリースクリプトを紹介します。

インベントリスクリプトがpythonモジュールを使用する場合は、予めpip installの操作をしておきましょう。コンテナ環境ではホストOS側ではなく、コンテナawx_webのpythonが呼び出される事に留意ください。

pip3 install requests
docker container exec -i -t awx_web /bin/bash
pip3 install requests

以下Cisco DevNet SandboxのCisco DNA Centerに登録された機器一覧を標準出力するスクリプトの実装例です。Cisco DevNet Sandboxへの接続パスワードなどは予告なしに変更される可能性がある事をご了承ください。

#!/usr/bin/python3

import json
import requests
requests.packages.urllib3.disable_warnings()

DNAC_HOST = 'sandboxdnac.cisco.com'
DNAC_USER = 'devnetuser'
DNAC_PASS = 'Cisco123!'

inventory = {
  'ios_group': {
    'hosts': [],
    'vars': {
      'ansible_user': 'cisco',
      'ansible_password': 'cisco'
    }
  }
}

url_login = 'https://' + DNAC_HOST  + '/dna/system/api/v1/auth/token'
result_login = requests.post(url=url_login, auth=(DNAC_USER, DNAC_PASS), verify=False)
token = result_login.json()['Token']
# print(token)

url_get = 'https://' + DNAC_HOST  + '/dna/intent/api/v1/network-device'
headers_get = {'X-auth-token': token}
result_get = requests.get(url=url_get, headers=headers_get, verify=False)
# print(json.dumps(result_get.json(), indent=2))

for item in result_get.json()['response']:
  inventory['iso_group']['hosts'].append(item['managementIpAddress'])

print(json.dumps(inventory, indent=2))

Ansible TowerとCisco DNA Centerの連携01

Cisco DevNet SandboxのCisco DNA Centerと連携できた事を確認します。

Ansible TowerとCisco DNA Centerの連携02

タイトルとURLをコピーしました