[Python][Network] ネットワーク機器のコンフィグをバックアップする

技術のお話し

netmikoに触れてみる

先の記事で書いたのですが、ネットワーク機器の操作をある程度自動化することが出来るようだということで、コードを書いてみたわけですが、まともに標準ライブラリで接続周りを書くのはかなりしんどいなぁ・・・と感じる次第で。

で、今回試しにネットワーク周りの外部モジュールを使ってそのあたりをもう少し簡単にできないものだろうか?と考え、手始めにということでnetmikoというライブラリを使用してみることにしました。

netmikoとは、ネットワークデバイスの操作自動化を目的としたPythonモジュールです。対応機種がかなり多く、色んなメーカーのデバイス触ってる自宅環境にはぴったりかなぁとおもって使ってみることにしました。

netmikoの導入

pipを使用して導入します。

# pip3 install netmiko

依存関係が幾つかあり、それも伴ってインストールされていきます。

やりたいこと

定期的にネットワーク機器のrunning-configを取得したいなぁと考えました。こんな感じです。

図示してみるとしょうもないんですが、今までコレを個別にTELNET/SSH叩いて気まぐれにバックアップしてきたことを考えると、まぁ、ちゃんとこういうのは自動化したのが良いのかなと思い。

そして、出来上がったコードはHinemosで定期実行させることを想定しています。フォルダは日付ごとにフォルダを作成し、そこに必要な定義情報を格納するイメージとしています。格納先は集合NFSストレージとしており、ここに格納させることで、災対サイトのバックアップ対象に含める感じにしています。

実際に書いたコード

実際に書いてみたコードはこんな感じになりました。

import sys
import time
import os
from datetime import datetime
from netmiko import ConnectHandler

#リモートログイン処理
def remote_login(type, ip, user, pwd):
    #接続メッセージの出力
    print("connecting: %s" % ip)
    params = {
        'device_type': type,
        'ip': ip,
        'username': user,
        'password': pwd,
        'secret': pwd
    }

    #ログイン処理
    conn = ConnectHandler(**params)
    conn.enable()
    return conn

#Config取得処理
def exec_get_config(conn,type):

    if type == "dell_powerconnect":
        sendcmd="show running-config"
    elif type == "cisco_ios_telnet":
        sendcmd="show running-config"
    elif type == "huawei_ssh":
        sendcmd="display current-configuration"
    elif type == "juniper_ssh":
        sendcmd="show configuration"
    else:
        return -1

    output = conn.send_command(sendcmd)

    return output

#メイン処理
def main():
    #引数からタイプ/IPアドレス/ユーザ名/パスワードを取り出す
    (acc_type, acc_ip, acc_user, acc_pwd) = (sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])

    #出力ディレクトリの作成
    tdatetime = datetime.now()
    tstr = tdatetime.strftime('%y%m%d-%a-%H')
    dirpath = "/nfs/nwconf/" + tstr
    if os.path.isdir(dirpath) == False:
        os.mkdir(dirpath)

    #出力ファイル名の定義
    acc_filename = dirpath + "/config_" + acc_ip + \
                   "_" + acc_type + datetime.now().strftime("%s") + ".conf"

    #ログインを実行する
    conn=remote_login(acc_type, acc_ip, acc_user, acc_pwd)

    #コンフィグ格納ファイルをWriteモードで開く
    acc_cmdfile=open(acc_filename,"w")

    #引数にリストを渡してコマンド実行をさせる
    out_config=exec_get_config(conn,acc_type)

    #実行結果をファイルに書き込む
    acc_cmdfile.write(out_config)

    #ファイルをクローズする
    acc_cmdfile.close()

if __name__== "__main__":
    main()

使用法は以下のような感じです。

# python3 /usr/local/bin/nwgetconfig.py <type> <ipaddr> <username> <password>

コード簡略化のためEnableパスワードを一般ログインパスワードと同一視して作ってますが、本当はここは引数を分けるべきところだとは思います。

netmikoを使用している所

netmikoを使用している所は以下の場所です。

リモートログイン処理

#リモートログイン処理
def remote_login(type, ip, user, pwd):
    #接続メッセージの出力
    print("connecting: %s" % ip)
    params = {
        'device_type': type,  
        'ip': ip,
        'username': user,
        'password': pwd,
        'secret': pwd
    }

    #ログイン処理
    conn = ConnectHandler(**params)
    conn.enable()
    return conn

特徴的なのはparamsの中にある「device_type」と言うやつで、これを色々指定することでそれぞれに合った機器の特権モード移動までを次の構文で実行します。

 conn = ConnectHandler(**params)
 conn.enable()

pexpectで書いたときのように、一々応答期待する文字列の定義等をしなくて良いので、そこら辺楽といえば楽です。

コマンド実行処理

その後、コマンドラインの実行を行っていくわけですが、netmikoでは以下の様なところでその実行命令を送信しています。

#Config取得処理
def exec_get_config(conn,type):

    if type == "dell_powerconnect":
        sendcmd="show running-config"
    elif type == "cisco_ios_telnet":
        sendcmd="show running-config"
    elif type == "huawei_ssh":
        sendcmd="display current-configuration"
    elif type == "juniper_ssh":
        sendcmd="show configuration"
    else:
        return -1

    output = conn.send_command(sendcmd) (★)
    return output

前半部分のIF分は、単なるモジュール名との照合結果に基づいて、設定抽出コマンドを選別しているだけで、実際にnetmikoが使われてる箇所は上記(★)箇所になります。

netmikoは文字列の送信はやっとくので、そのコマンド生成はどうぞ宜しくってポリシーで構成されています。つまり、何のコマンドを送信するかは事前に何らかの定義を行わなければなりません。そういう意味では、意外と処理の抽象化っておもったほどやってくれない感じです。

使った感じ

率直に感じたのは、「対応範囲は広く、でも抽象化は浅く」と言う感じです。ある程度処理の共通化はしとくけど、厳密な部分はユーザにお願いよろしくって言う印象を受けました。そういう意味では、出来る幅・柔軟性は広いですが、結局各モジュールの対応を行おうとすると条件分の羅列が続き、あまり効率的なコードが書けないなぁという気持ちになりました。

どーしても私自身バッチスクリプト的な思考に偏るのでそう思うだけなのかもしれませんし、実際のDevOpsではもっと効率的なコードがNetmikoを使用して行われているのかもしれません。

もう一点、情報がとにかく少ない。サンプルコードも中々見つけられず、特に苦労したのはモジュール名です。githubのソース見ながら「多分コレだろうなー」とか言いながら使ってた感じです。ただ、どうしてもPowerConnectのSSH接続に関してはうまくいかず、ぐむむ・・・となりました。

Python本体にはもう少し詳細なリファレンスが有りますが、Netmikoって微妙にそれが見つけにくい感じがします。

しかしながら、接続部分やコマンド実行部分の抽象化がなされてるのは非常に救いになりますし、役に立ちます。実際コレである程度スイッチやルーターの設定バックアップが取れましたのでー。あとFujitsuやNEC IXのコンフィグが取れるように改造できれば、大体のネットワークデバイスの設定バックアップを自動化できそうな気がします。

今まではTeratermログに頼りきりでしたからね(苦笑)

Tags:

Comments are closed

PAGE TOP