空き ipv4 サブネットを検索するタスクの例を使用した Junos PyEZ

Junos PyEZ の使用に関する記事 - 「Junos OS を実行しているデバイスの管理と自動化を可能にする Python マイクロフレームワーク」自動化と管理、私たちが愛するすべて。 この記事で説明するスクリプトの作成には、Python を学習し、Junos OS を実行している機器で情報を収集したり構成を変更したりするタスクを自動化するという、いくつかの目的がありました。 Python + Junos PyEZ というこの特定の組み合わせを選択したのは、Python プログラミング言語への参入障壁が低いことと、Junos OS の専門知識を必要としない Junos PyEZ ライブラリの使いやすさのためです。

タスク

会社に属する空き IPv4 サブネットの監査。 サブネットが空いているかどうかの基準は、Junos OS を実行しているルーターとして機能するスイッチ上のルートにそのサブネットに関するエントリがないことです。

具現化

Python + Junos PyEZ、paramiko と ssh.exec_command を使用する誘惑がありましたが、 その結果、ポーリングされる機器上で netconf デバイス ネットワーク管理プロトコルを設定する必要があります。 Netconf はリモート プロシージャ コール RPC を介してハードウェアと連携し、この例では XML を使用して受信した情報を提供します。

PyPI から Junos PyEZ の現在のバージョンをインストールするには、次のコマンドを使用します。

$ pip install junos-eznc

次のコマンドを使用して、GitHub 上のプロジェクトのメイン ブランチからインストールすることもできます。

$ pip install git+https://github.com/Juniper/py-junos-eznc.git

そしてもうXNUMXつのオプションは、

$ pip install -r requirements.txt 

このコマンドは、システムに不足している、操作に必要なライブラリをインストールします。 私のバージョンでは Requirements.txt それらは XNUMX つだけあり、最新バージョンはスクリプト作成時点で示されています。

junos-eznc
netaddr

デフォルトでは、スクリプトはシステム内の現在のユーザーの名前を取得します。show_route.py -u キーを使用して別のユーザーの名前でログインできます。 getpass.getpass は標準入力からパスワードを取得するため、パスワードはシステムに残りません。 機器に接続するには、プロンプトが表示されたらホスト名または IP アドレスを入力する必要もあります。 デバイス上の認証に必要なデータはすべて受信されました。

Junos PyEZ は、コンソール、Telnet、または ssh 経由の netconf を使用した Junos OS を実行している機器への接続をサポートします。 この記事では後者のオプションについて説明します。

機器に接続するには、jnpr.junos モジュールの Device クラスを使用します。

with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:

要求は、リモート プロシージャ コールまたはリモート プロシージャ コールのどちらか都合のよい方を介して、ルーターに認識されているすべてのルートに対して行われます。

data = dev.rpc.get_route_information()

Junos OS での同様のコマンド

user@router> show route | display xml

コマンドの末尾に rpc を追加すると、リクエスト タグが取得され、それを RPC メソッドの名前と照合することができます。これにより、対象となる他の名前を見つけることができます。 リクエスト タグを記述するための構文はメソッド名とは異なることに注意してください。つまり、ハイフンをアンダースコアに置き換える必要があります。

user@router> show route | display xml rpc
<rpc-reply >route_list = data.xpath("//rt-destination/text()")

残りの部分は while ループでラップされ、ルーターがすでに知っているサブネットとは別のサブネットをチェックインする必要がある場合にルーターへの要求を繰り返さないようにします。 リクエストを行っているルーターは OSPF 経由でのみルートを認識しているため、エッジ ルーターの場合はリクエストを少し変更してスクリプトの実行時間を短縮することをお勧めします。

data = dev.rpc.get_ospf_route_information()

次に、while ループの内容を見てみましょう。

最初に、ユーザーは、マスク付きで、同じサブネットのネットワークから XNUMX オクテット以内のサブネットを入力するように求められます。これは、検索範囲を設定するために必要です。 私は条件と検索範囲を指定するこの実装があまり好きではありませんが、今のところこれより良い解決策を見つけていません。 次に、得られたサブネットのリストroute_listから、XNUMXオクテット以内の変数を使用して、興味のあるサブネットを選択します。

tmp = re.search(r'^%sS*' % subnet_search, route_list[i])

IPNetwork (netaddr モジュール) を通じて、IPv4 アドレスのリストの形式でサブネットを受け取ります

range_subnet = netaddr.IPNetwork(tmp.group(0))

IPNetwork を使用して、ユーザーが入力したネットワークからマスク付きのアドレス範囲を取得し、占有アドレスのリストと比較するために、この範囲からすべてのアドレスのリストを生成します。

for i in set(net_list).difference(set(busyip)):
        freeip.append(i)

結果として得られるフリー アドレスのリストをサブネットの形式で表示します

print(netaddr.IPSet(freeip))

以下は、ルータとして使用されるスイッチ、モデル ex4550、ex4600 でテストされた完全なスクリプトです。


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import getpass
import netaddr
import re
import sys

import jnpr.junos

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user',
                    action='store',
                    dest='name',
                    help='Enter login from tacacs if it differs from the '
                         'username in the system.')
args = parser.parse_args()

if not args.name:
    args.name = getpass.getuser()    # Return the “login name” of the user.
router = input("Full routers name: ")
password = getpass.getpass("Password: ")

try:
    # Authenticates to a device running Junos, for get information about routs
    # into xml format and selects by tag.
    route_list = []
    with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:
        data = dev.rpc.get_route_information()
    route_list = data.xpath("//rt-destination/text()")
except (jnpr.junos.exception.ConnectRefusedError,
        jnpr.junos.exception.ConnectUnknownHostError) as err:
    print("Equipment name or password wrong.")
    sys.exit(1)

while True:
    subnet = input("Net with mask: ")
    subnet_search = input("Input no more three octet: ")
    # Gets a list of busy IP addresses from the received subnets.
    busyip = []
    for i in range(len(route_list)):
        tmp = re.search(r'^%sS*' % subnet_search, route_list[i])
        if tmp:
            range_subnet = netaddr.IPNetwork(tmp.group(0))
            for ip in range_subnet:
                busyip.append("%s" % ip)
    range_subnet = netaddr.IPNetwork(subnet)
    # Gets list ip adresses from subnetworks lists.
    net_list = []
    for ip in range_subnet:
        net_list.append("%s" % ip)
    # Сomparing lists.
    freeip = []
    for i in set(net_list).difference(set(busyip)):
        freeip.append(i)
    print(netaddr.IPSet(freeip))

    request = input("To run request again enter yes or y, "
                    "press 'enter', complete request: ")
    if request in ("yes", "y"):
        continue
    else:
        print('Bye')
        break

出所: habr.com

コメントを追加します