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 5 years have passed since last update.

Ansible自作モジュールを使ってターミナルサーバ経由でNW機器を操作してみた

Posted at

はじめに

以前の記事で、Pythonを使ったターミナルサーバ経由のNW機器操作例をご紹介しました。
Pythonを使ってターミナルサーバ経由でNW機器を操作する方法

今回は、このPythonコードをベースに、同じ事ができるAnsibleモジュールを自作しました。

console_commandモジュール

モジュール作成にあたり、networktocode/ntc-ansiblentc_show_commandモジュールを参考にさせて頂きました。
実装機能は、複数のshowコマンドを実行し、標準出力するだけのシンプルなものです。

console_command.py
import os.path
import socket
from netmiko import redispatch
import time

HAS_NETMIKO = True
try:
    from netmiko import ConnectHandler
except:
    HAS_NETMIKO = False


def main():

    module = AnsibleModule(
        argument_spec=dict(
            host=dict(required=False),
            username=dict(required=False, type='str'),
            password=dict(required=False, type='str', no_log=True),
            port=dict(required=False),
            secret=dict(required=False, type='str', no_log=True),
            platform=dict(required=False),
            commands=dict(type='list', required=True),   # 複数のshowコマンドを実行できるよう、データ型をリストに指定
            delay=dict(default=1, required=False),
            provider=dict(type='dict', required=False),
        ),
        supports_check_mode=False
    )

    provider = module.params['provider'] or {}

    no_log = ['password', 'secret']
    for param in no_log:
        if provider.get(param):
            module.no_log_values.update(return_values(provider[param]))

    # allow local params to override provider
    for param, pvalue in provider.items():
        if module.params.get(param) != False:
            module.params[param] = module.params.get(param) or pvalue

    # AnsibleのInventory/Playbook/Variableファイルで定義された値を取得し、変数に格納
    ip = module.params['host']
    username = module.params['username']
    password = module.params['password']
    port = module.params['port']
    secret = module.params['secret']
    device_type = module.params['platform']
    command = module.params['commands']
    delay = int(module.params['delay'])

    # netmikoがインストールされていない場合、Failメッセージを出力
    if not HAS_NETMIKO:
        module.fail_json(msg='This module requires netmiko.')
    else:
        # ここからは前回記事と同様
        device_args = dict(
            device_type = 'terminal_server',
            ip = ip,
            port = port,
            username = username,
            password = password,
            secret = secret,
          )

        net_connect = ConnectHandler(**device_args)
        net_connect.write_channel('\r')
        time.sleep(1)
        net_connect.write_channel('\r')
        time.sleep(1)
        net_connect.read_channel()

        redispatch(net_connect, device_type = device_type)

        if secret:
            net_connect.enable()

        output_list = []

        for cmd in command:
            output = net_connect.send_command_timing(cmd, delay_factor=delay)
            output_list.append(output)

        net_connect.disconnect()
        # ここまで

    # 実行結果をJSON形式で標準出力
    results = {}
    results['response_list'] = [output_list]

    module.exit_json(**results)


from ansible.module_utils.basic import *
if __name__ == "__main__":
    main()

自作モジュールをAnsibleが認識できるよう、[Best Practices > Directory Layout]
(https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#directory-layout)に従って`library`ディレクトリを作成し、直下に`console_command.py`を格納しました。
また、ansible.cfgファイルにlibraryディレクトリへのパスを追加しました。

ansible.cfg
[defaults]
library = /home/centos/ansible/library

ansible.cfgの格納先は、ansible --versionコマンドのconfig fileで確認可能です。

[centos@localhost ~]$ ansible --version
ansible 2.7.9
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/centos/ansible/library']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.7 (default, Dec  5 2018, 15:02:05) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]

pip(Pythonのパッケージ管理システム)を使ってansibleをインストールした場合は、ansible.cfgが作成されないため、新規作成する必要があるようです。

Playbook

Ansible2.5以降は、CLIベースのNW機器を操作する際、コネクションプラグインnetwork_cliを使用するのが標準的ですが、今回はNW機器への接続・ログイン処理も自作したため、localを指定しています。
簡単のため、showコマンドの出力結果は|で限定しています。

playbook_consv.yml
---

- hosts: all
  gather_facts: no
  connection: local
  
  tasks:
    - name: execute show command
      console_command:
        commands:
          - show version | inc Cisco
          - show running-config | section interface FastEthernet1 
        port: "{{ port }}"
        provider: "{{ cli }}"
      register: result

    - name: display the output of show command
      debug:
        var: result.response_list

  vars:
    cli:
      platform: "{{ platform }}"
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      secret: "{{ secret | default(omit) }}"

Inventoryファイル

今回はCisco 1812J×1台を対象機器としています。

inventory_consv2
[all] 
# ターミナルサーバのIPアドレス SSHログイン用のポート番号 NW機器のenableパスワード
192.168.100.56 port=3001 secret=test

[all:vars]
platform=cisco_ios   # NW機器のOS名(=netmikoのdevice_type)
username=admin   # ターミナルサーバのユーザ名
password=password   # ターミナルサーバのパスワード

実行結果

"result.response_list": を見ると、2つのshowコマンド結果が問題なく表示されている事が分かります。
(ただ、改行はうまくできませんでした。。)

[centos@localhost ansible]$ ansible-playbook -i inventory_consv2 playbook_consv.yml

PLAY [all] ******************************************************************************

TASK [execute show command] *************************************************************
ok: [192.168.100.56]

TASK [display the output of show command] ***********************************************
ok: [192.168.100.56] => {
    "result.response_list": [
        [
            "Cisco IOS Software, C181X Software (C181X-ADVIPSERVICESK9-M), Version XX.X(X)XX, RELEASE SOFTWARE (fc5)\nCopyright (c) 1986-2007 by Cisco Systems, Inc.\nuse. Delivery of Cisco cryptographic products does not imply\nA summary of U.S. laws governing Cisco cryptographic products may be found at:\nCisco 1812-J (MPC8500) processor (revision 0x400) with 118784K/12288K bytes of memory.",
            "interface FastEthernet1\n description << border2 - dist1 Segment >>\n ip address 192.168.200.9 255.255.255.252\n speed 100\n full-duplex"
        ]
    ]
}

PLAY RECAP ******************************************************************************
192.168.100.56             : ok=2    changed=0    unreachable=0    failed=0   

最後に

今回は最低限の機能のみ実装しましたが、参考にしたntc_show_commandモジュールには、textFSMによるパース機能や、出力結果のファイル出力機能もありますので、併せて取り込めば、かなり使えるモジュールになると思います。

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?