Junos OS を実行するデバイスで Python のリクエスト ライブラリを使用する方法
Python のリクエスト ライブラリは、Python 拡張パッケージをサポートする Junos OS を実行している特定のデバイスで利用できます。モジュールを requests Python スクリプトで使用して、HTTP/1.1 リクエストを送信できます。拡張自動化でJunos OSを実行しているデバイスでは、Pythonインタラクティブモードでモジュールを requests 使用することもできます。リクエストライブラリには、初期導入をサポートする方法や、Junos OSを実行するデバイスで日常的な監視や設定変更を実行するための追加の方法が用意されています。モジュールとその機能の詳細 requests については、 http://docs.python-requests.org/ のリクエストドキュメントを参照してください。
要求の発行
オンボックス Python スクリプトで モジュールをrequests使用して、HTTP/1.1 リクエストを送信できます。リクエストを作成するには、スクリプト内のモジュールをインポートし、目的のリクエストに対応する関数を呼び出します。モジュールは、HTTPGET、リクエスト、HEADおよび 、 リクエストDELETEをPUTサポートしています。POST要求は、サーバーの応答を含む Response オブジェクトを返します。デフォルトでは、リクエストはデフォルトのルーティングインスタンスを使用して行われます。
リクエストライブラリを使用して、REST APIサービスをサポートするJunos OSを実行するデバイスでRPCを実行できます。REST を使用して HTTP または HTTPS を介して Junos OS コマンドを [edit system services rest] 有効にするには、階層レベルで適切なステートメントを使用してターゲット デバイスを設定する必要があります。
たとえば、以下の op スクリプトは、デフォルト ポート(3000)で構成された HTTP 経由の REST API サービスを持つ Junos OS を実行しているリモート デバイスで RPC を実行する GET リクエストを実行 get-software-information します。スクリプトは応答ステータスコードを印刷し、ステータスコードが成功を示す場合は応答コンテンツを印刷します。
from junos import Junos_Context
import jcs
import requests
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
r = requests.get('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password))
print (r.status_code)
if (r.status_code == requests.codes.ok):
print (r.text)
user@host> op show-version.py Enter user password: 200 <software-information> <host-name>router1</host-name> <product-model>mx240</product-model> <product-name>mx240</product-name> <junos-version>18.3R1.8</junos-version> <package-information> <name>os-kernel</name> ...
ヘッダーのみを取得するには、単純な HEAD リクエストを送信します。
r = requests.head('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password))
print (r.headers)
print (r.headers['content-type'])
user@host> op request-headers.py
Enter user password:
{'Date': 'Tue, 02 Apr 2019 18:30:58 GMT', 'Connection': 'close', 'Content-Type': 'application/xml; charset=utf-8', 'Server': 'lighttpd/1.4.48'}
application/xml; charset=utf-8
GET リクエストに追加のパラメーターが必要な場合は、引数を params 含め、クエリ文字列に送信するタプルまたはバイトのリストを指定するか、URL の一部としてキーと値のペアを渡すことができます。同様に、HTTP ヘッダーの引数と辞書を headers 含めることで、カスタム ヘッダーを指定できます。
以下のリクエストは、指定された get-interface-information インターフェイスの terse オプションを使用して RPC を実行し、テキスト形式で応答を返します。
headers={'content-type': 'application/xml', 'Accept': 'text/plain'}
params={'interface-name':'ge-2/0/1', 'terse':''}
r = requests.get('http://198.51.100.1:3000/rpc/get-interface-information', auth=(user, password), headers=headers, params=params)
次の例では、URL のキーと値のペアとして引数を提供します。
headers={'content-type': 'application/xml', 'Accept': 'text/plain'}
rpc = 'get-interface-information?interface-name=ge-2/0/1&terse='
r = requests.get('http://198.51.100.1:3000/rpc/' + rpc, auth=(user, password), headers=headers)
同じリクエストで複数の RPC を実行するには、HTTP POST リクエストを開始し、実行する RPC を参照するようにパラメータを設定 data します。複数の RPC を実行する例については、 運用 RPC の 実行と 設定の管理 のセクションを参照してください。
運用 RPC の実行
モジュールを requests 使用して、REST API サービスが有効になっている Junos OS を実行しているリモート デバイスで、Junos XML API から RPC を実行できます。
次の op スクリプトは、モジュールを requests 使用して、対象デバイスで RPC と同等の show interfaces ge-2/0/1 terse 動作モード コマンドを実行します。
from junos import Junos_Context
import jcs
import requests
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
r = requests.get('http://198.51.100.1:3000/rpc/get-interface-information', auth=(user, password), params={'interface-name':'ge-2/0/1','terse':''})
print(r.text)
以下の op スクリプトは、ターゲット デバイス上で複数の RPC を実行する POST リクエストを送信します。このパラメータは data 、読みやすくするためにマルチライン文字列で定義されている、実行する RPC を参照します。
from junos import Junos_Context
import jcs
import requests
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
headers={'content-type': 'application/xml', 'Accept': 'text/plain'}
payload="""
<get-software-information/>
<get-interface-information>
<interface-name>ge-2/0/1</interface-name>
</get-interface-information>"""
r = requests.post('http://198.51.100.1/rpc/', auth=(user, password), headers=headers, data=payload)
if (r.status_code == requests.codes.ok):
print (r.text)
また、ユーザーが必要な変数を提供し、スクリプトを作成して要求を実行する汎用 op スクリプトを作成することもできます。requests-rpc.py op スクリプトの host、 、 rpc、および rpc_args コマンドライン引数を設定する、以下の op スクリプトの設定を検討してください。
[edit system scripts]
op {
file requests-rpc.py {
arguments {
host {
description "host:port to which to connect";
}
rpc {
description "base RPC to execute on target device";
}
rpc_args {
description "dictionary of RPC arguments to use";
}
}
}
}
language python;
以下のサンプルopスクリプトは、Junos OSを実行しているリモートデバイスに接続します。Junos OSは、 階層レベルで適切なステートメントで設定されており、RESTを使用してHTTP経由で [edit system services rest] Junos OSコマンドを有効にします。このスクリプトは、接続パスワードを入力するよう求め、引数を介して提供されたホストとポートに host 接続します。その後、このスクリプトはモジュールを requests 使用して、コマンドライン引数を介して提供された RPC を実行する GET リクエストを送信します。
Junos OS リリース 21.2R1 およびリリース 21.2R1 Junos OS Evolved以降、デバイスがコマンドライン引数を Python op スクリプトに渡すと、単一のハイフン(-)のプレフィックスが単一のハイフン(-)の引数名になり、2 つのハイフン(-)から複数文字の引数名がプレフィックスになります。以前のリリースでは、デバイスはすべての引数名に単一ハイフン(-)を付けます。
# Junos OS Release 21.1 and earlier
from junos import Junos_Context
from ast import literal_eval
import jcs
import argparse
import requests
## Argument list as configured in [edit system scripts op]
arguments = { 'host': 'host:port to which to connect',
'rpc' : 'base RPC to execute on target device',
'rpc_args' : 'dictionary of RPC arguments to use'
}
## Retrieve script arguments (Junos OS Release 21.1 and earlier)
parser = argparse.ArgumentParser(description='This is a demo script.')
for key in arguments:
if key == 'rpc_args':
parser.add_argument(('-' + key), help=arguments[key])
else:
parser.add_argument(('-' + key), required=True, help=arguments[key])
args = parser.parse_args()
## Convert rpc_args to a dictionary
if args.rpc_args is not None:
args.rpc_args = literal_eval(args.rpc_args)
## Retrieve username and prompt for password for connecting to target device
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
## Execute RPC
if args.rpc_args is None:
r = requests.get('http://' + args.host + '/rpc/' + args.rpc, auth=(user, password))
else:
r = requests.get('http://' + args.host + '/rpc/' + args.rpc, auth=(user, password), params=args.rpc_args)
## Print RPC contents if HTTP status code indicates success
if (r.status_code == requests.codes.ok):
print (r.text)
else:
print (r.status_code)
スクリプトを実行すると、リモートデバイスで指定されたオプションを使用してRPCを実行し、標準出力への応答を印刷します。
user@host> op requests-rpc.py host 198.51.100.1:3000 rpc get-interface-information rpc_args {'interface-name':'ge-2/0/1','terse':''}
Enter user password:
<interface-information xmlns="http://xml.juniper.net/junos/18.3R1/junos-interface" xmlns:junos="http://xml.juniper.net/junos/*/junos" junos:style="terse">
<physical-interface>
<name>ge-2/0/1</name>
<admin-status>up</admin-status>
<oper-status>up</oper-status>
</physical-interface>
</interface-information>
設定の管理
モジュールを requests 使用して、REST API サービスが有効になっている Junos OS を実行しているデバイスで設定を取得または変更できます。
以下の op スクリプトは、POST リクエストを [edit system] 使用して候補構成から階層を取得します。
from junos import Junos_Context
import jcs
import requests
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
headers = { 'content-type' : 'application/xml' }
payload = '<get-configuration><configuration><system/></configuration></get-configuration>'
r = requests.post('http://198.51.100.1:3000/rpc/', auth=(user, password), data=payload, headers=headers)
print (r.content)
HTTP POST リクエストを使用すると、1 つのリクエストで複数の RPC を実行できます。たとえば、設定のロック、ロード、コミット、ロック解除などです。
以下のサンプル op スクリプトは、リモート デバイスに接続し、指定されたインターフェイスにアドレスを設定します。読みやすさのために、ロック、ロード、コミット、およびロック解除操作は個別に定義されますが、RPC はリクエストで連結されます。
from junos import Junos_Context
import jcs
import requests
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
#### lock, load, commit, unlock configuration
headers={'content-type': 'application/xml'}
lock = '<lock><target><candidate/></target></lock>'
load = """<edit-config>
<target><candidate></candidate></target>
<default-operation>merge</default-operation>
<config>
<configuration>
<interfaces>
<interface>
<name>ge-2/0/1</name>
<unit>
<name>0</name>
<family>
<inet>
<address>
<name>192.0.2.1/24</name>
</address>
</inet>
</family>
</unit>
</interface>
</interfaces>
</configuration>
</config>
<error-option>stop-on-error</error-option>
</edit-config>"""
commit = '<commit/>'
unlock = '<unlock><target><candidate/></target></unlock>'
payload = lock + load + commit + unlock
r = requests.post('http://198.51.100.1:3000/rpc/', auth=(user, password), headers=headers, data=payload)
print(r.content)
op スクリプトを実行すると、ロック、ロード、コミット、およびロック解除操作に関する RPC 結果が返されます。一部のデバイスでは、応答出力により、個々の RPC が返信する境界行には、その後に境界文字列とヘッダーが含まれる -- もの Content-Type があります。その他のデバイスには、ヘッダーだけのもの Content-Type があります。
user@host> op requests-set-interface.py Enter user password: --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <ok/> --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <load-success/> --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <commit-results xmlns:junos="http://xml.juniper.net/junos/*/junos"> <routing-engine junos:style="normal"> <name>re0</name> <commit-success/> <commit-revision-information> <new-db-revision>re0-1555351754-53</new-db-revision> <old-db-revision>re0-1555033614-52</old-db-revision> </commit-revision-information> </routing-engine> </commit-results> --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <ok/> --harqgehabymwiax--
HTTPSリクエストでの証明書の使用
HTTP 基本認証メカニズムは、Base64 でエンコードされたクリアテキスト文字列としてユーザー資格情報を送信します。認証認証情報を傍受から保護するために、トランスポートレイヤーセキュリティ(TLS)またはSSL(セキュアソケットレイヤー)を使用して通信を暗号化するHTTPS経由のRESTful APIサービスを有効にすることをお勧めします。このサービスの設定については、 Junos OS REST API Guideを参照してください。
デフォルトでは、リクエストライブラリはHTTPSリクエストのSSL証明書を検証します。要求に および cert 引数をverify含め、SSL 検証オプションを制御できます。これらのオプションの詳細については、 リクエストのドキュメントを参照してください。
Python 2.7 を使用してモジュールを使用して HTTPS リクエストを requests 実行するスクリプトを実行すると、スクリプトに警告が生成 InsecurePlatformWarning されます SubjectAltNameWarning 。
以下の op スクリプトは、HTTPS 上で GET リクエストを送信し、CA バンドルのファイル パスまたは信頼できる CA 証明書を含むディレクトリに引数を設定 verify します。指定された CA 証明書を使用して、サーバーの証明書を検証します。
from junos import Junos_Context
import jcs
import requests
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
r = requests.get('https://198.51.100.1:3443/rpc/get-software-information', auth=(user, password), verify='path-to-ca-bundle')
print (r.status_code)
if (r.status_code == requests.codes.ok):
print (r.text)
ローカルクライアント側証明書を指定するには、クライアントの秘密鍵と証明書を含む単一ファイルのパスと等しい引数を設定するか、個々のクライアント証明書と秘密鍵ファイルのパスを含むタプルを設定 cert します。
r = requests.get('https://198.51.100.1:3443/rpc/get-software-information', auth=(user, password), verify='path-to-ca-bundle', cert=('path-to-client-cert','path-to-client-key')
ルーティング インスタンスの指定
デフォルトでは、リクエストはデフォルトのルーティングインスタンスを使用して実行されます。管理インスタンスまたは他のデフォルト以外のルーティング インスタンスを mgmt_junos 使用して、リクエストを実行することもできます。Junos OS インフラストラクチャを介してスクリプトを実行する場合、スクリプトで関数を呼び出すことでルーティング インスタンスを set_routing_instance() 指定できます。また、特定のデバイスは、ルーティング インスタンスの指定と Unix レベルのシェルでのスクリプトの実行もサポートします。
Junos OS Evolvedを実行するデバイスでは、この機能は set_routing_instance() 管理ルーティングインスタンスのみを使用してサポートします。
Pythonスクリプトでは、インスタンスを含むデフォルト以外のルーティングインスタンスを使用してリクエストを mgmt_junos 実行します。
以下のopスクリプトは、管理インスタンスを mgmt_junos 使用してターゲットデバイスに接続し、リクエストを実行します。
from junos import Junos_Context
import jcs
import requests
user = Junos_Context['user-context']['user']
password = jcs.get_secret('Enter user password: ')
jcs.set_routing_instance('mgmt_junos')
r = requests.get('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password))
print (r.text)
Python スクリプトでの関数の set_routing_instance() 使用については、 set_routing_instance()を参照してください。
スクリプトでルーティングインスタンスを指定するだけでなく、特定のデバイスはルーティングインスタンスの指定とUNIXレベルのシェルからのスクリプトの実行をサポートしています。拡張自動化機能を搭載した Junos OS(FreeBSD リリース 7.1 以降)を実行しているデバイスでは、 コマンドを setfib 使用して、管理インスタンスやその他のデフォルト以外のルーティング インスタンスを含む、指定されたルーティング インスタンスでリクエストを実行できます。
以下の Python スクリプトは、リモート デバイスで RPC を get-software-information 実行し、応答を印刷します。
#!/usr/bin/env python
import requests
from getpass import getpass
user = raw_input ('Enter username: ')
password = getpass('Enter password: ')
r = requests.get('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password))
print (r.text)
拡張自動化を備えたJunos OSを実行するデバイスで、デフォルト以外のルーティングインスタンスを使用してスクリプトを実行するために使用 setfib するには、次の手順に従います。
そのインスタンスのルーティング テーブルに関連付けられたソフトウェア インデックスを検索します。
次の例では、デバイスは非デフォルトの専用管理インスタンスを使用するように設定されています
mgmt_junos。ルーティング・テーブル・インデックスは、コマンド出力で参照されます。user@host> show route forwarding-table extensive table mgmt_junos Routing table: mgmt_junos.inet [Index 36738] Internet: Enabled protocols: Bridging, Destination: default Route type: permanent Route reference: 0 Route interface-index: 0 Multicast RPF nh index: 0 P2mpidx: 0 Flags: none Next-hop type: reject Index: 340 Reference: 1指定されたルーティング インスタンスで op スクリプトを実行するには、 コマンドを
setfib使用してスクリプトを実行し、インデックスを参照します。例えば:user@host> start shell % setfib -F36738 python /var/db/scripts/op/request-software-info.py
以下の例では、デバイスに非デフォルトのルーティングインスタンスvr1、およびvr1.inetルーティングテーブルインデックスが8で設定されています。
user@host> show route forwarding-table extensive table vr1 Routing table: vr1.inet [Index 8] Internet: Enabled protocols: Bridging, All VLANs, Destination: default Route type: permanent Route reference: 0 Route interface-index: 0 Multicast RPF nh index: 0 P2mpidx: 0 Flags: sent to PFE Next-hop type: reject Index: 592 Reference: 1以下のコマンドは、vr1 ルーティング インスタンスを使用して op スクリプトを実行します。
% setfib -F8 python /var/db/scripts/op/request-software-info.py
ZTP 操作の実行
ゼロタッチプロビジョニング(ZTP)により、手動操作を最小限に抑えながら、ネットワークに新しいジュニパーネットワークスデバイスを自動的にプロビジョニングできます。ZTPを使用するには、必要な情報を提供するようにサーバーを設定します。この情報には、Junos OSイメージと、読み込む設定ファイルや実行するスクリプトを含めることができます。デバイスを物理的にネットワークに接続し、工場出荷時のデフォルト設定で起動すると、デバイスは指定されたサーバーから情報を取得し、必要に応じてJunos OSイメージをアップグレードして、スクリプトを実行するか、設定ファイルを読み込みます。
新しいネットワークデバイスを接続して起動すると、Junos OSがサーバー上のファイルを検出すると、ファイルの1行目が検査されます。Junos OS で文字 #が見つかるとします。その後にインタープリター・パスが続き、ファイルをスクリプトとして処理し、指定されたインタープリターと共に実行します。実行されたスクリプトで Requests ライブラリを使用して、ZTP プロセスを合理化できます。
たとえば、新しいデバイスが ZTP プロセス中にダウンロードして実行する次のサンプル Python スクリプトを考えてみましょう。スクリプトを実行すると、最初に指定されたサーバー上の ca_cert_remote 場所から CA 証明書をダウンロードし、その場所にローカルに ca_cert_local 保存します。その後、このスクリプトはポート 8000 の設定サーバーに接続し、GET リクエストを発行して新しいデバイス設定を取得します。要求には CA 証明書へのパスが含まれており、これは交換中にサーバーの証明書を検証するために使用されます。次に、Junos PyEZ ライブラリを使用してデバイス上で設定を読み込み、コミットします。
#!/usr/bin/python
import os
import paramiko
import requests
from jnpr.junos import Device
from jnpr.junos.utils.config import Config
# Define the servers storing the certificate and configuration
host_cert = '198.51.100.1'
host_config = '192.0.2.1'
username = 'admin'
password = 'secret123'
# Define CA certificate file locations
ca_cert_remote = '/u01/app/myCA/certs/rootCA.crt'
ca_cert_local = '/var/tmp/rootCA.crt'
# Retrieve the CA certificate from the server
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=host_cert, username=username, password=password)
sftp = ssh.open_sftp()
sftp.get(ca_cert_remote, ca_cert_local)
sftp.close()
ssh.close()
# Retrieve the configuration from the server
uri = 'https://' + host_config + ':8000/'
config = requests.get(uri, auth=(username, password), verify=ca_cert_local)
# Load and commit the configuration on the device
with Device() as dev:
cu = Config(dev)
cu.load(config.text, format='text', overwrite=True)
cu.commit()