5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ネットワーク自動化Advent Calendar 2019

Day 5

Ansibleのテキストパース用フィルタープラグインを自作してみた

Last updated at Posted at 2019-12-04

はじめに

以前の記事で、TTP(Template Text Parser)というPythonのパーサーライブラリを使って、L2SWのConfigファイルをパースし、ポート管理表の自動生成を行いました。
L2SWのConfigからポート管理表を自動生成してみた

今回は、このパーサーをAnsibleのカスタムフィルターとして取り込み、xxx_commandモジュールで取得したshowコマンド結果をパースできるようにしてみました。

※ フィルタープラグイン自作例は、以前こちらでも紹介しています。
※ 私が知る限り、パース用フィルタープラグインとして、他にもTextFSMを利用したparse_cli_textfsmや、pyATS/Genieを利用したparse_genie(Ansible Galaxyからインストールが必要。詳細はGitHub/parse_genieに記載。)があります。

セットアップ

Python3.6.7の仮想環境内にインストールしたAnsibleを使いました。当初、バージョン2.9.0でテストしていたのですが、Logging error(KeyError)メッセージが複数出たため、2.8.4を使っています。

追加でTTPのインストールが必要です。

(venv) [centos@localhost ansible]$ pip install ttp

カスタムフィルター

以下のPythonスクリプトを作成しました。

custom_filters_ttp.py
from ansible.errors import AnsibleError

# ttp、jsonのインポート。インポートに失敗した場合、後続の処理でエラー出力できるようにする。
try:
    from ttp import ttp
    HAS_TTP = True
except ImportError:
    HAS_TTP = False

try:
    import json
    HAS_JSON = True
except ImportError:
    HAS_JSON = False


class FilterModule(object):

    def parse_cli_ttp(self, cli_output, template_file):
        if not HAS_TTP:
            raise AnsibleError('parse_cli_ttp filter requires TTP library to be installed')

        if not HAS_JSON:
            raise AnsibleError('parse_cli_ttp filter requires JSON library to be installed')

        with open(template_file, 'rt') as ft:
            ttp_template = ft.read()

        # create parser object and parse data using template
        parser = ttp(data=cli_output, template=ttp_template)
        parser.parse()

        # return result in JSON format
        results = parser.result(format='json')[0]
        return results

    def filters(self):
        return {
            # 左側がPlaybook内で使用するフィルター名、右側が紐付ける関数名。
            'parse_cli_ttp': self.parse_cli_ttp,
        }

ベストプラクティスに従い、Playbookを格納しているディレクトリ配下に、filter_pluginsディレクトリを作成し、その中に本ファイルを格納しました。

また、Ansibleがこのカスタムフィルターを認識できるよう、ansible.cfgの設定を以下の通り書き換えました。

ansible.cfg
[defaults]
filter_plugins     = [Playbook格納ディレクトリのフルパス]/filter_plugins

Playbook

ios_commandモジュールでRunning Configを取得し、続くdebugモジュール内で、取得したConfigと以前の記事で作成したL2インターフェース設定用テンプレートのファイルパスを指定しました。シンプルですね!

playbook_ttp.yml
---

- hosts: cisco
  gather_facts: no
  connection: network_cli

  tasks:
    - name: run show command on remote devices
      ios_command:
        commands: show running-config
      register: result

    - name: display parsed output
      debug:
        msg: "{{ result.stdout[0] | parse_cli_ttp('catalyst2960_template_ttp2.txt') }}"

出力結果

前回とConfigが異なるため結果に違いはありますが、パース自体は問題なくできています。

$ ansible-playbook -i inventory_2960.ini playbook_ttp.yml

PLAY [cisco] *************************************************************************************************

TASK [run show command on remote devices] ********************************************************************
ok: [hqdist1A]

TASK [display parsed output] *********************************************************************************
ok: [hqdist1A] => {
    "msg": [
        {
            "l2_interfaces": [
                {
                    "description": "<< Connect hqdist1 and hqdist2 >>",
                    "duplex": "auto",
                    "mode": "trunk",
                    "port_no": "Port-channel1",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "1,101"
                },
                {
                    "description": "<< To hqborder1 Fa1 >>",
                    "duplex": "full",
                    "mode": "access",
                    "port_no": "FastEthernet0/1",
                    "portfast": "x",
                    "speed": "100",
                    "status": "o",
                    "vlan": "200"
                },
                {
                    "description": "<< To hqborder2 Fa1 >>",
                    "duplex": "full",
                    "mode": "access",
                    "port_no": "FastEthernet0/2",
                    "portfast": "x",
                    "speed": "100",
                    "status": "o",
                    "vlan": "202"
                },
                {
                    "description": "<< To hqaccess1 Fa0/23 >>",
                    "duplex": "full",
                    "mode": "access",
                    "port_no": "FastEthernet0/3",
                    "portfast": "x",
                    "speed": "100",
                    "status": "o",
                    "vlan": "100"
                },
                {
                    "duplex": "auto",
                    "mode": "trunk",
                    "port_no": "FastEthernet0/4",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/5",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/6",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/7",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/8",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/9",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/10",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/11",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/12",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "203"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/13",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "100"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/14",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/15",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/16",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/17",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/18",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/19",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/20",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/21",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "FastEthernet0/22",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "x",
                    "vlan": "1"
                },
                {
                    "description": "<< To hqdist2 Fa0/23 >>",
                    "duplex": "auto",
                    "mode": "trunk",
                    "port_no": "FastEthernet0/23",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "1,101"
                },
                {
                    "description": "<< To hqdist2 Fa0/24 >>",
                    "duplex": "auto",
                    "mode": "trunk",
                    "port_no": "FastEthernet0/24",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "1,101"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "GigabitEthernet0/1",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "1"
                },
                {
                    "duplex": "auto",
                    "mode": "access",
                    "port_no": "GigabitEthernet0/2",
                    "portfast": "x",
                    "speed": "auto",
                    "status": "o",
                    "vlan": "1"
                }
            ]
        }
    ]
}

PLAY RECAP ***************************************************************************************************
hqdist1A                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

最後に

今回作ったプラグインはGitHub/ansible-ttpにアップしています。Configだけでなく、他のshowコマンドの出力結果も比較的簡単にパース出来ますので、ぜひ使ってみて頂ければと思います。

5
6
0

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
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?