概要
ルータ群のコンフィグを一元取得するツールを作りました。作ったツールは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経由でコンフィグを取得します。
[
{
"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ファイルを読み込み、ルータ操作を呼び出すファイル
#! /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を呼び出しているだけです。
! /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