てくなべ (tekunabe)

ansible / network / automation

[Ansible][ACI] EPG に紐付けされている Contract 一覧を取得する(aci_rest モジュール版)

■ はじめに

以前の記事 [Ansible][ACI] EPG に紐付けされている Contract 一覧を取得する - てくなべ (tekunabe)で、aci_epg_to_contract モジュール を利用して、EPG に紐付けられている Contract 一覧を取得するサンプルをご紹介しました。

一方で、aci_rest モジュール を利用する方法もあります。aci_rest モジュールでは、APIC REST API の仕様をより意識する必要がある代わりに、他のモジュールでは手の届かなかった柔軟な処理ができます。

たとえば、aci_epg_to_contract モジュールでは、Provide Contract、Consumed Contract それぞれ別に取得する必要がありました。aci_rest モジュールでは、リクエストする URL を工夫することで、Provide Contract、Consumed Contract 両方いっぺんに取得できます。

この記事では簡単なサンプルをもとにして説明します。

  • 環境
    • Cisco DevNet Sandbox (APIC 4.1)
    • Ansible 2.9.0

参考

aci_epg_to_contractモジュールを利用する場合はこちら

tekunabe.hatenablog.jp


APIC 側画面

f:id:akira6592:20191104110233p:plain:w400
EPG への Contract 紐付け設定画面

以前の記事 https://tekunabe.hatenablog.jp/entry/2019/11/04/ansible_aci_get_epg_contracts:titile と同様に、ある EPG

  • Provided Contract: c_sql、c_web
  • Consumed Contract: c_test

と設定されている状態を想定します。


■ Playbook

取得には、aci_rest モジュールを利用します。

ポイントは path オプション

aci_epg_to_contract モジュールでは、contract_type: provider のときにクエリストリングに rsp-subtree-class=fvRsProvを、contract_type: consumer のときに rsp-subtree-class=fvRsCons を付加します。

一方、今回利用する aci_rest モジュールでは、クエリストリングも自分で指定できます。rsp-subtree-class=fvRsProv,fvRsCons と指定することで、Provide Contract、Consumed Contract 両方いっぺんに取得するようにリクエストできます。

また、今回の場合、EPG の子オブジェクトまでの取得だけで十分なので、rsp-subtree=all ではなく、rsp-subtree=children を指定します。

参考: Cisco APIC REST API ユーザ ガイド - APIC REST API の使用 [Cisco Application Policy Infrastructure Controller(APIC)] - Cisco

少々雑ですが、各 Contract の情報をのまま debug で表示します。

---
- hosts: apic
  gather_facts: no

  tasks:
    # get contracts (provided/consumed)
    - name: get contracts
      aci_rest:
        host: "{{ ansible_host }}"
        username: "{{ username }}"
        password: "{{ password }}"
        validate_certs: no
        method: get
        path: /api/mo/uni/tn-tenant1/ap-ap1/epg-epg1.json?rsp-subtree-class=fvRsProv,fvRsCons&rsp-subtree=children
      register: result
    
    # debug  contracts
    - name: debug contracts
      debug: 
        msg: "{{ item }}"
      loop: "{{ result.imdata[0].fvAEPg.children | default([]) }}"
      loop_control:
        label: "{{ ansible_loop.index0 }}"
        extended: yes


■ 実行

Playbook を実行します。

$ ansible-playbook -i ../../inventory.ini get_contracts_rest.yml 

PLAY [apic] ********************************************************************

TASK [get contracts] ***********************************************************
ok: [apic01]

TASK [debug contracts] *********************************************************
ok: [apic01] => (item=0) => {
    "msg": {
        "fvRsProv": {          //  Provided Contract
            "attributes": {
                "annotation": "",
                "childAction": "",
                "ctrctUpd": "ctrct",
                "extMngdBy": "",
                "forceResolve": "yes",
                "lcOwn": "local",
                "matchT": "AtleastOne",
                "modTs": "2019-11-04T01:39:51.572+00:00",
                "monPolDn": "uni/tn-common/monepg-default",
                "prio": "unspecified",
                "rType": "mo",
                "rn": "rsprov-c_sql",
                "state": "formed",
                "stateQual": "none",
                "status": "",
                "tCl": "vzBrCP",
                "tContextDn": "",
                "tDn": "uni/tn-tenant1/brc-c_sql",
                "tRn": "brc-c_sql",
                "tType": "name",
                "tnVzBrCPName": "c_sql",   // Contract 名
                "triggerSt": "triggerable",
                "uid": "15374",
                "updateCollection": "no"
            }
        }
    }
}
ok: [apic01] => (item=1) => {
    "msg": {
        "fvRsProv": {          //  Provided Contract
            "attributes": {
                "annotation": "",
                "childAction": "",
                "ctrctUpd": "ctrct",
                "extMngdBy": "",
                "forceResolve": "yes",
                "lcOwn": "local",
                "matchT": "AtleastOne",
                "modTs": "2019-11-04T01:39:51.572+00:00",
                "monPolDn": "uni/tn-common/monepg-default",
                "prio": "unspecified",
                "rType": "mo",
                "rn": "rsprov-c_web",
                "state": "formed",
                "stateQual": "none",
                "status": "",
                "tCl": "vzBrCP",
                "tContextDn": "",
                "tDn": "uni/tn-tenant1/brc-c_web",
                "tRn": "brc-c_web",
                "tType": "name",
                "tnVzBrCPName": "c_web",   // Contract 名
                "triggerSt": "triggerable",
                "uid": "15374",
                "updateCollection": "no"
            }
        }
    }
}
ok: [apic01] => (item=2) => {
    "msg": {
        "fvRsCons": {          //  Consumed Contract
            "attributes": {
                "annotation": "",
                "childAction": "",
                "ctrctUpd": "ctrct",
                "deplInfo": "",
                "extMngdBy": "",
                "forceResolve": "yes",
                "lcOwn": "local",
                "modTs": "2019-11-04T01:39:51.572+00:00",
                "monPolDn": "uni/tn-common/monepg-default",
                "prio": "unspecified",
                "rType": "mo",
                "rn": "rscons-c_test",
                "state": "formed",
                "stateQual": "none",
                "status": "",
                "tCl": "vzBrCP",
                "tContextDn": "",
                "tDn": "uni/tn-tenant1/brc-c_test",
                "tRn": "brc-c_test",
                "tType": "name",
                "tnVzBrCPName": "c_test",   // Contract 名
                "triggerSt": "triggerable",
                "uid": "15374",
                "updateCollection": "no"
            }
        }
    }
}

PLAY RECAP *********************************************************************
apic01                     : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

各 debug モジュールの取得で

  • Provided Contract: c_sql、c_web
  • Consumed Contract: c_test

となっていることを確認できました。

参考: query で取得したデータの全体

参考のために query した結果の全体の中身も掲載します。

クリックして広げて見る

{
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "failed": false,
    "imdata": [
        {
            "fvAEPg": {
                "attributes": {
                    "annotation": "",
                    "childAction": "",
                    "configIssues": "",
                    "configSt": "applied",
                    "descr": "",
                    "dn": "uni/tn-tenant1/ap-ap1/epg-epg1",
                    "exceptionTag": "",
                    "extMngdBy": "",
                    "floodOnEncap": "disabled",
                    "fwdCtrl": "",
                    "hasMcastSource": "no",
                    "isAttrBasedEPg": "no",
                    "isSharedSrvMsiteEPg": "no",
                    "lcOwn": "local",
                    "matchT": "AtleastOne",
                    "modTs": "2019-11-03T14:54:44.955+00:00",
                    "monPolDn": "uni/tn-common/monepg-default",
                    "name": "epg1",
                    "nameAlias": "",
                    "pcEnfPref": "unenforced",
                    "pcTag": "32771",
                    "prefGrMemb": "exclude",
                    "prio": "unspecified",
                    "scope": "2555904",
                    "shutdown": "no",
                    "status": "",
                    "triggerSt": "triggerable",
                    "txId": "17293822569102705193",
                    "uid": "15374"
                },
                "children": [
                    {
                        "fvRsCons": {
                            "attributes": {
                                "annotation": "",
                                "childAction": "",
                                "ctrctUpd": "ctrct",
                                "deplInfo": "",
                                "extMngdBy": "",
                                "forceResolve": "yes",
                                "lcOwn": "local",
                                "modTs": "2019-11-04T01:39:51.572+00:00",
                                "monPolDn": "uni/tn-common/monepg-default",
                                "prio": "unspecified",
                                "rType": "mo",
                                "rn": "rscons-c_test",
                                "state": "formed",
                                "stateQual": "none",
                                "status": "",
                                "tCl": "vzBrCP",
                                "tContextDn": "",
                                "tDn": "uni/tn-tenant1/brc-c_test",
                                "tRn": "brc-c_test",
                                "tType": "name",
                                "tnVzBrCPName": "c_test",
                                "triggerSt": "triggerable",
                                "uid": "15374",
                                "updateCollection": "no"
                            },
                            "children": [
                                {
                                    "fvCollectionCont": {
                                        "attributes": {
                                            "childAction": "deleteNonPresent",
                                            "collectionDn": "uni/tn-tenant1/brc-c_test",
                                            "lcOwn": "local",
                                            "modTs": "2019-11-04T01:39:51.572+00:00",
                                            "monPolDn": "uni/tn-common/monepg-default",
                                            "name": "",
                                            "nameAlias": "",
                                            "rn": "collectionDn-[uni/tn-tenant1/brc-c_test]",
                                            "status": ""
                                        }
                                    }
                                }
                            ]
                        }
                    },
                    {
                        "fvRsProv": {
                            "attributes": {
                                "annotation": "",
                                "childAction": "",
                                "ctrctUpd": "ctrct",
                                "extMngdBy": "",
                                "forceResolve": "yes",
                                "lcOwn": "local",
                                "matchT": "AtleastOne",
                                "modTs": "2019-11-04T01:39:51.572+00:00",
                                "monPolDn": "uni/tn-common/monepg-default",
                                "prio": "unspecified",
                                "rType": "mo",
                                "rn": "rsprov-c_sql",
                                "state": "formed",
                                "stateQual": "none",
                                "status": "",
                                "tCl": "vzBrCP",
                                "tContextDn": "",
                                "tDn": "uni/tn-tenant1/brc-c_sql",
                                "tRn": "brc-c_sql",
                                "tType": "name",
                                "tnVzBrCPName": "c_sql",
                                "triggerSt": "triggerable",
                                "uid": "15374",
                                "updateCollection": "no"
                            },
                            "children": [
                                {
                                    "fvCollectionCont": {
                                        "attributes": {
                                            "childAction": "deleteNonPresent",
                                            "collectionDn": "uni/tn-tenant1/brc-c_sql",
                                            "lcOwn": "local",
                                            "modTs": "2019-11-03T15:28:38.764+00:00",
                                            "monPolDn": "uni/tn-common/monepg-default",
                                            "name": "",
                                            "nameAlias": "",
                                            "rn": "collectionDn-[uni/tn-tenant1/brc-c_sql]",
                                            "status": ""
                                        }
                                    }
                                }
                            ]
                        }
                    },
                    {
                        "fvRsProv": {
                            "attributes": {
                                "annotation": "",
                                "childAction": "",
                                "ctrctUpd": "ctrct",
                                "extMngdBy": "",
                                "forceResolve": "yes",
                                "lcOwn": "local",
                                "matchT": "AtleastOne",
                                "modTs": "2019-11-04T01:39:51.572+00:00",
                                "monPolDn": "uni/tn-common/monepg-default",
                                "prio": "unspecified",
                                "rType": "mo",
                                "rn": "rsprov-c_web",
                                "state": "formed",
                                "stateQual": "none",
                                "status": "",
                                "tCl": "vzBrCP",
                                "tContextDn": "",
                                "tDn": "uni/tn-tenant1/brc-c_web",
                                "tRn": "brc-c_web",
                                "tType": "name",
                                "tnVzBrCPName": "c_web",
                                "triggerSt": "triggerable",
                                "uid": "15374",
                                "updateCollection": "no"
                            },
                            "children": [
                                {
                                    "fvCollectionCont": {
                                        "attributes": {
                                            "childAction": "deleteNonPresent",
                                            "collectionDn": "uni/tn-tenant1/brc-c_web",
                                            "lcOwn": "local",
                                            "modTs": "2019-11-03T15:16:07.253+00:00",
                                            "monPolDn": "uni/tn-common/monepg-default",
                                            "name": "",
                                            "nameAlias": "",
                                            "rn": "collectionDn-[uni/tn-tenant1/brc-c_web]",
                                            "status": ""
                                        }
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        }
    ],
    "status": -1,
    "totalCount": 1,
    "warnings": [
        "Platform darwin on host apic01 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information."
    ]
}


■ まとめ

aci_rest モジュール を利用して、EPG に紐付けれられている Contract の一覧を取得しました。

aci_epg_to_contract モジュールではできない取得方法ができました。

使い分け方としては、基本は aci_epg_to_contract のような各オブジェクト用のモジュールを利用し、それでもできない場合のみ、aci_rest を利用する、といった形になるかと思います。

参考

[Ansible][ACI] EPG に紐付けされている Contract 一覧を取得する - てくなべ (tekunabe)