久々の記事を書いてみる
最近Gitlabのサーバを立てて作ったツール類の管理をしていたのだが、運用する機器のconfigも管理したいなーと思っていた。
手始めにNetwork機器のconfigを取得してgitで管理してみる事に。
ネットで調べたところPythonモジュール類でいくつか良さそうながありました。
ネットで見つけたPythonモジュール類のお話
Cisco/Juniperルータのコンフィグを一元取得するツール #Python - Qiita
netmikoでネットワーク機器の種類を自動検出してコマンドを実行する #Python - Qiita
今回は以下の前提もありPythonで標準モジュールのみで一旦作ってみた。
次回はnetmikoあたりを使ってみたい・・・。
あとはAnsibleで叩いてからgitへとかもできそうな気もしている。
前提
みなさんの環境で環境構築に融通が利くと思うのでこんな感じにする必要はない気もしますが。
また、今回はGitlabへの反映はMaster branchに直接pushしてしまっている。
Pythonコード
SampleとしてCisco機器にtelnet、A10 Networks機器にSSHで入ってexpectモドキでsh runしてconfigをテキストで書き込むようなものを書いてみた。(無理矢理感もありますが)
destlistというtextファイルに
ipaddress,hostname,os type
をカンマ区切りでリスト化したものを読み込んで動かす形。
#! /usr/bin/env python # -*- coding: utf-8 -*- import telnetlib import datetime import subprocess import time import paramiko import swpass.password """ settings from """ home_dir = '/home/' destlist = home_dir + 'destlist' """ settings end """ date = datetime.datetime.now().strftime("%Y%m%d") loginp = swpass.password.password() def cisco_get(ipaddr, sw_name): try: con = telnetlib.Telnet(ipaddr, '23') con.read_until('Password: ') con.write(loginp + '\n') time.sleep(2) login_result = con.read_some() if sw_name + '>' in login_result: con.write('en\n') con.write(loginp + '\n') con.write('terminal length 0\n') con.write('sh run\n') time.sleep(2) con.write('exit\n') result = con.read_all() time.sleep(10) print('Finish.') con.close() return result else: message = 'LOGIN Error: ' + sw_name print(message) con.close() return message except Exception as e: print(sw_name + ' telnet error : ' + str(e.args)) def aten_ssh_get(ipaddr, sw_name): con = paramiko.SSHClient() con.load_system_host_keys() con.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: con.connect(ipaddr, port=22, username='admin', password=loginp, look_for_keys=False, allow_agent=False) ssh_con = con.invoke_shell() time.sleep(2) result = ssh_con.recv(65535) if sw_name in result: ssh_con.send('en\n') time.sleep(1) ssh_con.send(loginp+ '\n') time.sleep(1) ssh_con.send('terminal length 0\n') time.sleep(1) ssh_con.send('sh run\n') time.sleep(5) ssh_con.send('exit\n') time.sleep(1) ssh_con.send('exit\n') time.sleep(1) ssh_con.send('y\n') time.sleep(1) command_result = ssh_con.recv(65535) print('Finish. MODE:ssh') con.close() return command_result else: message = 'LOGIN Error: ' + sw_name print(message) con.close() return message except Exception as e: print(sw_name + ' ssh error : ' + str(e.args)) def config_get(): with open(destlist) as f: for lists in f: dest = lists.rstrip() ipaddr = dest.split(',')[0] sw_name = dest.split(',')[1] ostype = dest.split(',')[2] print('Start : ' + sw_name) with open(home_dir + sw_name + '-config', 'w') as result_log: if 'cisco' == ostype: result = cisco_get(ipaddr, sw_name) result_log.write(str(result)) elif 'a10_ssh' == ostype: result = aten_ssh_get(ipaddr, sw_name) result_log.write(str(result)) def main(): config_get() subprocess.call('sed -i -e \'/clock-period/d\' *config ', shell=True) subprocess.call('/usr/bin/git pull origin master', shell=True) subprocess.call('/usr/bin/git add --a', shell=True) subprocess.call('/usr/bin/git commit -m "[auto update] ' + date + '."', shell=True) subprocess.call('/usr/bin/git push -u origin master', shell=True) if __name__ == '__main__': main()
機器ログイン時のパスワードは、Pythonのモジュール化させて外部から読み込ませています。
あと、Ciscoでsh runをするとntp clock-periodの行でgit diffが出てしまうので思い切って行の削除をsedでしてます。
expectモドキなので、前半でご紹介したモジュール類で機器が対応してない場合は、柔軟に対応できるのがメリットといったところでしょうか。
その後の運用メインの話はこちら
rotek.hateblo.jp