LoginSignup
24
24

More than 3 years have passed since last update.

NetmikoでヤマハのNW機器を操作する

Last updated at Posted at 2019-10-05

はじめに

Netmikoとは、ネットワーク機器へのログイン、ログ取得、設定変更等を行うための、マルチベンダー対応のPythonライブラリです。
今回は、ヤマハのルータ(RTX、NVR)やファイアウォール(FWX)のプロンプト方式に対応したNetmikoクラスを作成してみました。
GitHub - netmiko

作成にあたり、公式ドキュメントに加え、以下記事も参考にさせて頂きました。ありがとうございますm(_ _)m

netmiko と TextFSM を利用してネットワーク機器の show コマンド結果をパースする
netmikoでネットワーク機器の種類を自動検出してコマンドを実行する
netmikoをYamahaに対応させてみた

以降で、実装時に考慮した点と、簡単なサンプルコードを書き残しておきます。

1. 考慮した点

1-1. コマンドモード

Netmikoのドキュメントを見ると、新規ベンダーを追加する時は「可能な限り、既存のCiscoSSHConnectionやBaseConnectionから継承したメソッドを再利用するべき。」と記載されています。
Steps for adding a new vendor

Cisco機器の設定変更では、下表の通りenable()メソッドで特権EXECモードへ移行した後、send_config_set()send_config_from_file()メソッドでグローバルコンフィグレーションモードへの移行と設定変更を行います。
一方Yamaha機器の設定変更では、enable()メソッドで管理モードへの移行、send_config_set()send_config_from_file()メソッドで管理モードへの移行と設定変更を行います。
enable()メソッドは他ベンダー機器との統一性を図るために実装していますが、設定変更時の記述は必須ではないです。

Ciscoモード名 プロンプト Yamahaモード名 プロンプト モード移行のためのメソッド
ユーザEXEC > 一般 > メソッド不要
特権EXEC ※ # 管理 ※ # enable()
グローバルコンフィグレーション (config)# 管理 ※ # send_config_set()、send_config_from_file()

※モードに入る前に、enable or 管理パスワード入力が必要。

1-2. Config保存

管理モードで設定変更を行った後、exit(もしくはquit)で一般モードに移行する際、以下の通りConfigを保存するか聞かれます。勝手に保存されると困るケースもあると思うので、「Y/Nという文字列があったらNを返す」ようにして、一律保存しないようにしています。
保存したい場合は、設定Config内にsaveコマンドを含めるか、Netmikoのsave_config()メソッドを使うようにします。

yamaha1# ip lan1 address 10.1.1.100/24 
yamaha1# exit 
Save new configuration ? (Y/N)

2. 環境準備

テストを実施するにあたり、RTX側で以下設定を行っています。

  • ユーザパスワード、管理パスワードの設定
  • コンソールの文字コードをSJISからASCIIに変更
  • Telnet、SSHの有効化
config(snippet)
yamaha1> show config
# RTX810 Rev.11.01.33 (Fri Apr 20 08:44:58 2018)
administrator password *
login user yamaha *
timezone +09:00
console character ascii
console lines infinity
console prompt yamaha1
ip route default gateway 192.168.100.1
ip lan1 address 10.1.1.40/24
ip lan2 address 192.168.100.100/24
telnetd service on
sshd service on
sshd host key generate *

3. サンプルコード

3-1. SSHログイン、設定変更、ログ取得、Config保存

RTX810にSSHログインし、LAN1のIPアドレスを変更してみます。確認のため、事前事後でshow status lan1コマンドを取得し、アドレスを確認します。最後にConfig保存も行います。

send_config.py
from netmiko import ConnectHandler

device = {
    "host": "192.168.100.100",
    "username": "yamaha",
    "password": "yamaha",
    "secret": "yamaha",   # administrator password
    "device_type": "yamaha",   # device type for yamaha SSH login
}

# connect
net_connect = ConnectHandler(**device)

# send show command (before)
output = net_connect.send_command("show status lan1")
print('---------------before log---------------', output, sep='\n')

# change ip address
config_commands = ['ip lan1 address 10.1.1.100/24']
output = net_connect.send_config_set(config_commands)
print('---------------change config---------------', output, sep='\n')

# send show command (after)
output = net_connect.send_command("show status lan1")
print('---------------after log---------------', output, sep='\n')

# save config
output = net_connect.save_config()
print('---------------save config---------------', output, sep='\n')

# disconnect
net_connect.disconnect()

実行結果を見ると、事前事後でIPアドレスが10.1.1.40/24から10.1.1.100/24に変更されているのが分かります。また、設定変更後、問題なくNが入力され、一般モードに移行できているのが分かります。Configも問題なくconfig0に保存されています。

result3-1
$ python send_config_telnet.py
---------------before log---------------
LAN1
Description:                    
IP Address:                     10.1.1.40/24 
Ethernet Address:               00:a0:de:XX:XX:XX
Operation mode setting:         Type (Link status)
               PORT1:           Auto Negotiation (Link Down)
               PORT2:           Auto Negotiation (Link Down)
               PORT3:           Auto Negotiation (Link Down)
               PORT4:           Auto Negotiation (Link Down)
Maximum Transmission Unit(MTU): 1500 octets
Promiscuous mode:               OFF
Transmitted:                    0 packet (0 octet)
  IPv4(all/fastpath):           0 packet / 0 packet
  IPv6(all/fastpath):           0 packet / 0 packet
Received:                       0 packet (0 octet)
  IPv4:                         0 packet
  IPv6:                         0 packet
---------------change config---------------
administrator 
Password: 
yamaha1# ip lan1 address 10.1.1.100/24 
yamaha1# exit 
Save new configuration ? (Y/N)N
yamaha1> 
yamaha1> 
yamaha1> 
---------------after log---------------
LAN1
Description:                    
IP Address:                     10.1.1.100/24 
Ethernet Address:               00:a0:de:XX:XX:XX
Operation mode setting:         Type (Link status)
               PORT1:           Auto Negotiation (Link Down)
               PORT2:           Auto Negotiation (Link Down)
               PORT3:           Auto Negotiation (Link Down)
               PORT4:           Auto Negotiation (Link Down)
Maximum Transmission Unit(MTU): 1500 octets
Promiscuous mode:               OFF
Transmitted:                    0 packet (0 octet)
  IPv4(all/fastpath):           0 packet / 0 packet
  IPv6(all/fastpath):           0 packet / 0 packet
Received:                       0 packet (0 octet)
  IPv4:                         0 packet
  IPv6:                         0 packet
---------------save config---------------
Saving ... CONFIG0 Done .

3-2. Telnetログイン、設定変更(Configファイル)、ログ取得

先ほどはSSHログインでしたが、device_typeをyamaha_telnetとすることで、Telnetログインも可能です。
また、先ほどはsend_config_set()メソッドで、リスト形式のデータを読み込んで設定変更しましたが、send_config_from_file()でConfigファイルを流し込むことも可能です。今回は、以下のyamaha_config.txtでスタティックルート2行の追加とConfig保存(save)を行い、事前事後でConfig確認を行います。

yamaha_config.txt
ip route 10.1.2.0/24 gateway 10.1.1.1
ip route 10.1.3.0/24 gateway 10.1.1.1
save
send_config_file.py
from netmiko import ConnectHandler

device = {
    "host": "192.168.100.100",
    "username": "yamaha",
    "password": "yamaha",
    "secret": "yamaha",
    "device_type": "yamaha_telnet",   # device type for yamaha telnet login
}

# connect
net_connect = ConnectHandler(**device)

# send show command (before)
output = net_connect.send_command("show config | grep route")
print('---------------before log---------------', output, sep='\n')

# add static routes
output = net_connect.send_config_from_file(config_file='yamaha_config.txt')
print('---------------change config---------------', output, sep='\n')

# send show command (after)
output = net_connect.send_command("show config | grep route")
print('---------------after log---------------', output, sep='\n')

# disconnect
net_connect.disconnect()

実行結果を見ると、スタティックルートが問題なく追加されています。事前にConfig保存を行ったため、管理モードから抜ける時にY/Nを聞かれませんでしたが、後続処理もできています。

result3-2
$ python send_config_file.py 
---------------before log---------------
Searching ...
ip route default gateway 192.168.100.1
---------------change config---------------
administrator 
Password: 
yamaha1# ip route 10.1.2.0/24 gateway 10.1.1.1 
yamaha1# ip route 10.1.3.0/24 gateway 10.1.1.1 
yamaha1# save 
Saving ... CONFIG0 Done .
yamaha1# 
yamaha1# exit 
yamaha1> 
yamaha1> 
yamaha1> 
yamaha1> 
yamaha1> 
---------------after log---------------
Searching ...
ip route default gateway 192.168.100.1
ip route 10.1.2.0/24 gateway 10.1.1.1
ip route 10.1.3.0/24 gateway 10.1.1.1

3-3. 自動検出、TextFSMによるパース

最後に、Netmikoの自動検出機能を使ったdevice_typeの判定を行います。判定方法は、show copyrightコマンドを取得し、返ってきた値の中に「Yamaha Corporation」が含まれる場合、device_typeを「yamaha」としています。
合わせて、show environmentコマンドのTextFSMによるパースも行います。出力結果をパースする場合、send_command()に引数use_textfsm=Trueを追加します。(TextFSMのTemplateファイルは自作したものを用意。)

auto_detect.py
from netmiko.ssh_autodetect import SSHDetect
from netmiko import ConnectHandler
from pprint import pprint

device = {
    "host": "192.168.100.100",
    "username": "yamaha",
    "password": "yamaha",
    "secret": "yamaha",
    "device_type": "autodetect",  # set device type to "autodetect"
}

# autodetect device_type
guesser = SSHDetect(**device)
best_match = guesser.autodetect()

# display detected device_type
print("device_type: " + best_match)

# set device_type and connect
device['device_type'] = best_match
connection = ConnectHandler(**device)

# send show command and display output
output = connection.send_command('show environment')
print('---------------show environment---------------', output, sep='\n')

# send show command and display parsed output with textfsm
output = connection.send_command('show environment', use_textfsm=True)
print('---------------show environment (parsed)---------------')
pprint(output)

# disconnect
connection.disconnect()

自動検出機能により、「yamaha」と判定されています。パースも問題なくできました。

$ python auto_detect.py 
device_type: yamaha
---------------show environment---------------
RTX810 BootROM Ver. 1.00
RTX810 FlashROM Table Ver. 1.00
RTX810 Rev.11.01.33 (Fri Apr 20 08:44:58 2018)
  main:  RTX810 ver=00 serial=S3KXXXXXX MAC-Address=00:a0:de:00:00:00 MAC-Addre
ss=00:a0:de:aa:aa:aa
CPU:   8%(5sec)   1%(1min)   0%(5min)    Memory: 7% used
Packet-buffer:   0%(small)   0%(middle)   5%(large)   0%(huge) used
Firmware: internal  
Config. file: config0  Default config. file: config0
Boot time: 2019/10/01 22:00:17 +09:00
Current time: 2019/10/05 21:06:54 +09:00
Elapsed time from boot: 3days 23:06:37
Security Class: 1, FORGET: ON, TELNET: OFF
---------------show environment (parsed)---------------
[{'buffer_huge': '0',
  'buffer_large': '5',
  'buffer_middle': '0',
  'buffer_small': '0',
  'cpu_1_min': '1',
  'cpu_5_min': '0',
  'cpu_5_sec': '1',
  'date': '2019/10/05',
  'forget': 'ON',
  'hardware': 'RTX810',
  'mac': ['00:a0:de:00:00:00', '00:a0:de:aa:aa:aa'],
  'mem': '7',
  'sec_class': '1',
  'serial': 'S3KXXXXXX',
  'telnet': 'OFF',
  'temperature': '',
  'time': '21:06:55',
  'timezone': '+09:00',
  'uptime': '3days 23:06:38',
  'version': '11.01.33'}]

最後に

今回開発したものは、Netmikoにプルリクエストを出しマージされています。(ただし、Telnetログインの不具合があり、2021/1/1に再度プルリクエストを出しています。)
TextFSMのTemplateファイルは、後日プルリクエストを出したいと思います。

24
24
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
24
24