Edited at

Cisco/Juniperルータのコンフィグを一元取得するツール

More than 3 years have passed since last update.


概要

ルータ群のコンフィグを一元取得するツールを作りました。作ったツールはgithubで公開しています。

https://github.com/taijiji/ConfigCollector


作った動機

管理しているルータのコンフィグを全機器分を一気に取得してGit管理したかったので作りました。

元々の想定では、[ルータ一覧ファイルの読み込み]->[ルータコンフィグの一元取得]->[Gitリモートレポジトリにpush] までの一連の工程をツール化しようと考えていたのですが、Git管理は運用者が手動でするほうがよいという考えのもと、ルータコンフィグの一元取得する部分だけを切り出してツール化しました。

ルータコンフィグ取得だけにフォーカスしたことでツール自体がシンプルになったことに加えて、結果的に他のツールとの連携がしやすくなったように感じています。


ツールのインストール

githubからダウンロードしてきます。

git clone git@github.com:taijiji/ConfigCollector.git

ダウンロードしたツールのディレクトリに移動します。

cd ConfigCollector

pipを使って関連モジュールをインストールします。

- pip未使用の場合は、事前にpipをインストールしてください。

pip install -r requirements.txt

以上で準備完了です。


ツールの使い方

"get_router_config.py"に対して、JSON形式で作成したルータ一覧情報をコマンドライン引数にして実行します。

python get_router_config.py [json file]

ルータ一覧情報のjson fileは以下のように記述します。

このように書くと、全ルータに対してSSH経由でコンフィグを取得します。


my_router.json

[

{
"hostname" : "router1",
"username" : "user1",
"password" : "aaabbbccc",
"ipv4" : "192.168.0.1",
"os" : "JUNOS"
},
{
"hostname" : "router2",
"username" : "user2",
"password" : "aaabbbccc",
"ipv4" : "192.168.0.2",
"os" : "IOS-XR"
},
{
"hostname" : "router3",
"username" : "user3",
"password" : "aaabbbccc",
"ipv4" : "192.168.0.3",
"os" : "IOS"
}
]

ルータOSは手元でテストできたものだけを対象としています。

- JUNOS

- IOS

- IOS-XE

- IOS-XR


出力されるもの

ツールを実行して成功すると、"router_config"ディレクトリ配下に各ルータごとのコンフィグが保存されます。ファイル名は「ルータホスト名.txt」になっています。

以下は、上記の"my_router.json"ファイルで実行させた場合の結果です。

$ ls router_config

router1.txt router2.txt router3.txt

$ less router_config/router1.txt

show configuration | no-more
## Last commit: 2015-05-01 17:00:00 JST by user1
version 10.x.x;
system {
host-name router1;
time-zone Asia/Tokyo;
(snip)

最後に管理者が手動で、"router_config"ディレクトリを丸ごと[git add]->[git commit]->[git push]を実施してGithubやGitlabなどで管理することで、ルータのコンフィグを一元的にバージョン管理することができます。


コード

参考までにコードを記載しておきます。全体的にそこまで難しいことはしていません。

ルータへのSSH + 情報取得はExscript というモジュールを使っています。

SSHツールではexpectが有名ですが、ExscriptはLinux/Unixの他にも、IOS, IOS-XR, JunOS, VRP,などに対応されています。ルータを制御する際に別途ルータ用に構文解析する必要がないので便利です。


JSONファイルを読み込み、ルータ操作を呼び出すファイル


get_router_config.py

#! /usr/bin/env python

import sys
import traceback
import json

from ssh_router import Router

# Open json input file
try:
# argument is routers' information with JSON formt.
input_filename = sys.argv[1]
input_file = open(input_filename ,'r')
print 'Reading router info from "' + input_filename + '"...'
except ( IOError, IndexError):
print 'Cannot open JSON file.'
print 'Please use bellow: " python get_router_config [JSON file] " '
sys.exit()
else:
router_info_json = input_file.read()
input_file.close()

# Convert format from json to dictionary_type
try:
router_info = json.loads(router_info_json)
except ValueError as error:
print 'JSON format error : '
print router_info_json
print error
sys.exit()

# Login and get config each routers using ssh
for num in range( len(router_info) ):
router = Router( router_info[num] )

# Login Router
print 'Accessing router: ' + router_info[num]['hostname'] + '...'
try:
router.login()
router_config = router.get_config()
except:
print 'Router login error'
print router_info[num]
router.logout()
sys.exit()

# Get config of Router
try:
router_config = router.get_config()
except:
print 'Router get configuration error'
print router_info[num]
router.logout()
sys.exit()
else:
router.logout()

# Create output file written config
try:
output_filename = 'router_config/' + router_info[num]['hostname'] + '.txt'
print 'Writing output file "' + output_filename + '"...'
except AtributeError:
print 'cannot read dictionary of router_info[' + num + '][hostname]'
sys.exit()

try:
output_file = open ( output_filename, 'w')
except:
print 'cannot open "' + output_filename + '"'
output_file.close
sys.exit()
else:
output_file.write( router_config )
output_file.close

print 'Success to create "' + output_filename + '" !'



ルータへの制御を構成するファイル

ここではほとんどExscriptを呼び出しているだけです。


ssh_router.py

! /usr/bin/env python

# -*- coding: utf-8 -*-

from Exscript.protocols import SSH2
from Exscript.Account import Account

class Router:
def __init__(self, router_info):
self.hostname = router_info['hostname']
self.username = router_info['username']
self.password = router_info['password']
self.ipv4 = router_info['ipv4']
self.os = router_info['os']

def login(self):
self.session = SSH2()
self.session.connect(self.ipv4)
self.session.login( Account(name=self.username, password=self.password) )

def logout(self):
if self.session :
self.session.send('exit\r')
self.session.close()
else:
raise AttributeError( 'cannot find a living session.' )

def get_config(self):
if( self.os=='IOS-XR' or self.os=='IOS' or self.os=='IOS-XE'):
self.session.execute('terminal length 0')
self.session.execute('show running-config')
result = self.session.response
elif( self.os == 'JUNOS'):
self.session.execute('show configuration | no-more')
result = self.session.response
else:
raise ValueError( 'OS is unknown value. Please describe from JUNOS / IOS / IOS-XE / IOS-XR.' )

return result