Junos OS를 실행하는 디바이스에서 Python에 대한 요청 라이브러리를 사용하는 방법
Python에 대한 Requests 라이브러리는 Python 확장 패키지를 지원하는 Junos OS를 실행하는 특정 디바이스에서 사용할 수 있습니다. Python 스크립트의 requests 모듈을 사용하여 HTTP/1.1 요청을 보낼 수 있습니다. Enhanced Automation을 사용하는 Junos OS를 실행하는 디바이스에서 Python 대화형 모드에서 모듈을 requests 사용할 수도 있습니다. Requests 라이브러리는 Junos OS를 실행하는 디바이스에서 일상적인 모니터링 및 구성 변경을 수행할 뿐만 아니라 초기 구축을 지원하는 추가 방법을 제공합니다. 모듈 및 해당 기능에 대한 requests 자세한 내용은 http://docs.python-requests.org/ 요청 설명서를 참조하십시오.
발행 요청
받은 편지함 Python 스크립트에서 모듈을 사용하여 requests HTTP/1.1 요청을 보낼 수 있습니다. 요청을 하려면 스크립트에서 모듈을 가져오고 원하는 요청에 해당하는 함수를 호출합니다. 이 모듈은 HTTP GET 및 POST 요청은 물론HEAD, DELETEPUT 및 요청을 지원합니다. 요청은 서버의 응답이 포함된 Response 객체를 반환합니다. 기본적으로 요청은 기본 라우팅 인스턴스를 사용하여 이루어집니다.
Requests 라이브러리는 REST API 서비스를 지원하는 Junos OS를 실행하는 디바이스에서 RPC를 실행하는 데 사용할 수 있습니다. REST를 사용하는 HTTP 또는 HTTPS를 통해 Junos OS 명령을 사용하도록 하기 위해서는 대상 장비가 계층 수준에서 적절한 명령문 [edit system services rest] 으로 구성되어야 합니다.
예를 들어, 다음 op 스크립트는 기본 포트(3000)에서 구성된 HTTP를 통해 REST API 서비스가 있는 Junos OS를 실행하는 원격 디바이스에서 RPC를 실행하는 get-software-information GET 요청을 수행합니다. 스크립트는 응답 상태 코드를 인쇄하고 상태 코드가 성공을 표시하면 응답 컨텐트를 인쇄합니다.
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 대상 장비에서 운영 모드 명령과 show interfaces ge-2/0/1 terse 동등한 RPC를 실행합니다.
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)
또한 사용자가 필요한 변수를 제공하고 스크립트가 요청을 구성하고 실행하는 일반 운영 스크립트를 만들 수 있습니다. requests-rpc.py 운영 스크립트에 대한 , rpc및 rpc_args 명령줄 인수를 구성하는 host다음 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;
다음 샘플 운영 스크립트는 Junos OS를 실행하는 원격 디바이스에 연결합니다. Junos OS는 계층 수준에서 적절한 명령문 [edit system services rest] 으로 구성되어 REST를 사용하여 HTTP를 통해 Junos OS 명령을 사용할 수 있습니다. 스크립트는 연결 암호를 프롬프트하고 인수를 통해 제공된 호스트 및 포트에 host 연결합니다. 그런 다음 스크립트는 모듈을 사용하여 requests 명령줄 인수를 통해 제공된 RPC를 실행하는 GET 요청을 보냅니다.
Junos OS Release 21.2R1 및 Junos OS Evolved Release 21.2R1에서 시작하여 디바이스가 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 요청을 사용하면 단일 요청에서 여러 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)
운영 스크립트를 실행하면 잠금, 로드, 커밋 및 잠금 해제 작업에 대한 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 인코딩된 clear-text 문자열로 보냅니다. 인증 자격 증명을 도청으로부터 보호하기 위해 TLS(Transport Layer Security) 또는 SSL(Secure Sockets Layer)을 사용하여 통신을 암호화하는 HTTPS를 통해 RESTful API 서비스를 활성화하는 것이 좋습니다. 이 서비스 구성에 대한 자세한 내용은 Junos OS REST API 가이드를 참조하십시오.
기본적으로 Requests 라이브러리는 HTTPS 요청에 대한 SSL 인증서를 검증합니다. SSL 검증 옵션을 제어하기 위한 요청에 인수를 cert 포함 verify 할 수 있습니다. 이러한 옵션에 대한 자세한 내용은 요청 설명서를 참조하십시오.
Python 2.7을 사용하여 모듈을 사용하여 requests HTTPS 요청을 실행하는 스크립트를 실행하면 스크립트가 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)
로컬 클라이언트측 인증서를 지정하려면, 인수를 클라이언트의 전용 키 및 인증서를 포함하는 단일 파일의 경로 또는 개별 클라이언트 인증서 및 전용 키 파일의 경로를 포함하는 tuple에 설정합니다 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 레벨 셸에서 스크립트를 실행하는 것을 지원합니다. Enhanced Automation을 사용하는 Junos OS(FreeBSD Release 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)
Enhanced Automation을 통해 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지정된 라우팅 인스턴스로 운영 스크립트를 실행하려면 명령을 사용하여
setfib스크립트를 실행하고 인덱스(index)를 참조합니다. 예를 들어: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가 서버의 파일을 탐지하면 파일의 첫 번째 줄이 검사됩니다. Junos OS에서 문자 #를 찾은 경우! 그리고 해석자 경로가 뒤따르면 해당 파일을 스크립트로 취급하고 지정된 해석자로 실행합니다. 실행 스크립트에서 Requests 라이브러리를 사용하여 ZTP 프로세스를 간소화할 수 있습니다.
예를 들어, 다음 샘플 Python 스크립트를 생각해 보십시오. 이 샘플은 ZTP 프로세스 중에 새 디바이스가 다운로드하고 실행합니다. 스크립트가 실행되면 먼저 지정된 서버의 위치에서 CA 인증서를 ca_cert_remote 다운로드하고 해당 위치에 로컬로 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()