OpsRampとAnsibleのインベントリ連携

# 概要
Ansibleでは、ファイルによる静的なインベントリ管理のほかにインベントリ情報を動的に管理する「Dynamic Inventory」があります。
[Developing Dynamnic Inventory](https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html)

「Dynamic Inventory」を使用することにより、外部システムからインベントリ情報を取得することができます。
OpsRampでは、Rest APIを提供しているため、「Dynamic Inventory」で連携することができます。
[OpsRamp API](https://docs.vistanet.jp/api/)

# Ansible Dynamic Inventory Script
Pythonスクリプトを使用し、外部システムと連携します。
[Inventory Script](https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html#developing-inventory-scripts)
Pythonスクリプトは、実行時に「--list」および「--host」引数が使用でき、実行結果をJSON形式で返す必要があります。
以下がサンプルのPythonスクリプトです。

```py:opsramp-inv.py
import requests
import json
import sys
import argparse


def getAuthKey(params):
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Accept": "application/json"
    }
    payload = {
        "grant_type": "client_credentials",
        "client_id": params["KEY"],
        "client_secret": params["SECRET"]
    }
    url = "https://{url}/auth/oauth/token".format(url=params['URL'])
    r = requests.post(url, headers=headers, data=payload)
    json_res = json.loads(r.text)

    return str(json_res["access_token"])


def getDeviceGroups(params):
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authorization": "Bearer "+params["AUTHKEY"]
    }
    url = "https://{url}/api/v2/tenants/{c_id}/deviceGroups/minimal".format(
        url=params["URL"],
        c_id=params["CLIENT_ID"]
    )
    r = requests.get(url, headers=headers)
    results = json.loads(r.text)

    return results


def getResourcesMinimal(params, deviceGroup):
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authorization": "Bearer "+params["AUTHKEY"]
    }
    url = "https://{url}/api/v2/tenants/{c_id}/resources/minimal?deviceGroupId={deviceGroup}".format(
        url=params["URL"],
        c_id=params["CLIENT_ID"],
        deviceGroup=deviceGroup
    )
    r = requests.get(url, headers=headers)
    results = json.loads(r.text)

    return results


def get_inventory_from_opsramp(params):
    params.update({'AUTHKEY':getAuthKey(params)})
    deviceGroups = getDeviceGroups(params)
    print(deviceGroups)
    inventory = {}
    for deviceGroup in deviceGroups:
        groupName = deviceGroup["name"]
        resources = getResourcesMinimal(params, deviceGroup["id"])
        inventory.update({groupName: {'hosts': []}})
        for resource in resources:
            inventory[groupName]['hosts'].append(resource["ipAddress"])

    return inventory


def to_json(dict):
    return json.dumps(dict)


def parse_args():
    parser = argparse.ArgumentParser(description='OpsRamp Inventory Module')
    group = parser.add_mutually_exclusive_group()
    group.add_argument('--list', action='store_true', help='List active servers')
    group.add_argument('--host', help='List details about the specific host')

    return parser.parse_args()


def main():
    args = parse_args()
    params = {
            "URL": <API URL: OpsRamp設定上から取得>,
            "CLIENT_ID": <Client Id: OpsRamp設定上から取得>,
            "KEY": <API Key: OpsRamp設定上から取得>,
            "SECRET": <API Secret: OpsRamp設定上から取得>
    }
    if args.list:
        inventory = get_inventory_from_opsramp(params)
        output = to_json(inventory)
        print(output)
    elif args.host:
        output = {}
        print(output)
    sys.exit(0)


if __name__ == '__main__':
    main()
```

::: note info
requestsモジュールを使用しています。
「--host」引数は未実装です。
:::

# OpsRampの設定
OpsRampのRest APIを使用するためには、カスタムインテグレーションを設定する必要があります。
設定方法については、下記を参照ください。
[Custom Integrationを使い倒す](https://qiita.com/yusawada/items/385241a8bf4cc7a6e235)

# 結果
以下が「ansible-inventory」の実行結果です。

```sh:bash
[root@ansible ansible]# ansible-inventory -i opsramp-inv.py  --list
{
    "TEST0001": {
        "hosts": [
            "192.168.0.205"
        ]
    },
    "_meta": {
        "hostvars": {}
    },
    "all": {
        "children": [
            "TEST0001",
            "ungrouped"
        ]
    }
}
```

以下がOpsRamp上のデバイスグループ設定です。
![opsramp-inventory.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/8b238f1b-91e1-d596-b4cf-b4ebc14ad3a0.png)


---------------------------------------
[<img width = 250 height = 200 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/111de30a-4d33-aa33-5c7d-83d9015093e6.png">](https://www.vistanet.jp/knowledge-base/)