본문 바로가기

프로그래밍/Python

Programmability for Networker : Part 5

이전까지 다뤄졌던 pingrange Python 예제를 변형해봅니다.

 

코드를 모두 짤 수 없다면, 잘 짜여진 기본 에제를 바탕으로 필요한 내용을 수정/보완하는 것도 중요할 것입니다.

물론 그렇게 하기 위해서는 기존 코드를 잘 이해하는 것이 매우 중요합니다.

 

기존 예제 소스를 이해하기 위해서 이론 정리만 했다면 이번 변형 예제는 기존 예제와 달라진 점을 비교해보고

또한 변형 예제에 대해서는 나름대로.. 친절하게 주석을 달았습니다.

물론 이론적인 부분이 함께 알아두고, 코드를 잘 쪼개서 볼 수 있어야 이해가 쉬울 것입니다.

 

 기존 예제 포스팅은 아래와 같습니다.

 

Python for Networker : Part 2                  Python for Networker : Part 3                    Python for Networker : Part 4 

 

기존 예제는 아래에서 볼 수 있습니다.

[ 예제 링크 ] https://github.com/datacenter/who-moved-my-cli

 

※ 본 내용의 진행은 Nexus 5548 6.0(2)N2(4) 기준입니다.

 

※ Modified Version Code는 다음에서 받을 수 있스니다.

      - https://github.com/NetworkZIGI/Python_for_Network

 


 

 

pingrange.py

import re

from cisco import cli

from argparse import ArgumentParser

def expandrange(rangefunc):

    hosts = []

    octets = rangefunc.split('.')

    for i,octet in enumerate(octets):

        if '-' in octet:

            octetrange = octet.split('-')

            for digit in range(int(octetrange[0]), int(octetrange[1])+1):

                ip = '.'.join(octets[:i] + [str(digit)] + octets[i+1:])

                hosts += expandrange(ip)

            break

    else:

        hosts.append(rangefunc)

    return hosts

 

parser = ArgumentParser('pingrange')

parser.add_argument('ip', help='IP range to ping, e.g., 10.1.0-1.0-255 will expand to 10.1.0.0/23')

parser.add_argument('options', nargs='*', help='Options to pass to ping', default=['count 1'])

args = parser.parse_args()

targets = expandrange(args.ip)

for ip in targets:

    tupleping  = cli('ping %s %s' % (ip, ' '.join(args.options)))

    strping = str(tupleping)

    m = re.search('([0-9\.]+)% packet loss',strping )

    print('%s - %s' % (ip, 'UP' if float(m.group(1)) == 0.0 else 'DOWN'))

 

 

기존 pingrange의 변형된 코드의 달라진 점

      IP범위를 잘못 입력했을 경우에 예외 처리를 하였다.  (옥텟별로 1~255 사이)

             : checkRagne 메서드 정의.

             : 잘못된 입력인 경우에는 오류 메시지를 출력하고 시스템을 종료(sys.exit())를 한다.

      지정된 IP범위에서 증가값을 옵션으로 임의로 지정 할 수 있게 하였다.

              : 별도의 범위를 지정하지 않으면, default 1씩 증가한다.

 

 ◇ 기타 대부분의 코드는 아래의 변형된 코드와 유사하기 때문에 변형 코드의 주석과 기존 Part 2~4에서 다루었던 코드 이해하기

     이론 내용 등을 함께 보면 기존 코드를 이해하는 데 도움이 될 수 있을 것 같습니다.

 

 

pingrange Code : Modified Version

import sys                                                             # 시스템 패키지. 시스템 종료 메서드를 호출하기 위해 사용

import re                                                              # 정규식을 쓰기 위한 패키지

import cisco                                                         # Cisco 패키지  : Cli 명령을 사용하기 위해 사용.

from argparse import ArgumentParser               # 실행시의 매개변수를 다루기 위한 패키지

 

def checkRange(checkIP):                                       # 입력받은 IP 옥텟이 IP범위에 해당하는지 확인하기 위한 메서드

    octets = checkIP.split('.')                                  # 입력받은 IP를 '.으로 나눠서 각 옥텟별로 만듬

    for octet in octets:                                            # 각 옥텟이 저장된 List의 항목(IP의 각 옥텟)을 순환

        ip = int(octet)                                              # int 형 데이터로 변경

        if (ip < 0 or ip > 255):                                 # IP의 적정 범위인지 확인하여, 그 이외의 숫자인 경우에는 에러 발생

            print "Invalid Input Value"

            print "IP value is not less than 0 or greater than 255."

            sys.exit()                                                 # 시스템 종료

    return True

 

 

def expandrange(rangefunc,stepcnt):   # 사용자가 요청한 IP 범위 / 체크할 IP띄어쓸 범위

                                                                          # 체크할 IP 범위를 별도로 지정하지 않으면 1default 값으로 함.

    hosts = []                                                      # ping을 확인할 IP를 저장하기 위한 리스트 변수

    step = str(stepcnt[0])                                   # 매개변수 두번째를 리스트 type으로 받기 때문에 문자열 처리를 위해서 변경

    octets = rangefunc.split('.')                         # IP리스트를 옥텟별로 분리하여 LIST 변수에 저장

    for i,octet in enumerate(octets):                 # 옥텍별로 확인

        if '-' in octet:                                            # 만약에 옥텟안에 '-'이 있다면 해당 옥텟은 범위를 뜻하는 것.

            octetrange = octet.split('-')                # IP 범위를 LIST로 분리 (제일 앞 대역과 제일 대역)

            sip = int(octetrange[0])                      # IP 범위의 앞 부분을 sip로 int type으로 저장

            dip = int(octetrange[1])                     # IP 범위의 뒷 부분을 dip로 int type으로 저장

            for digit in range(sip,dip+1, int(step) if i==3 else 1):     

                                                                        # 순환문을 위한 값 지정 : 범위 지정의 첫번째 IP / IP / 증가값

                                         # 증가값의 경우에는 1~3번째 옥텟에는 해당하지 않고, 마지막 옥텟에만 해당되기 떄문에

                                         # 4번째 옥텟일 경우에만(i가 3인 경우가 옥텟이 4번째인 경우임, 0,1,2,3) 증가값을 적용하고

                                         # 그 이외의 경우에는 기본 증가값인 1을 사용한다.

                ip = '.'.join(octets[:i] + [str(digit)] + octets[i+1:])   # 범위의 옥텟전 / 범위옥텟 / 범위 옥텟후를 더해서 IP로만듬

                                        # List의 경우 [] 안에 시작이나 종료점을 쓰지 않으면, 처음부터 끝까지를 나타냄.

                hosts += expandrange(ip,stepcnt)    # 옥텟에서 아직 범위가 있을 수 있기 때문에 다시 expandrage 호출

            break

    else:                                                                        # for문이 break로 종료되지 않고 정상 종료된 경우에 실행.

        if checkRange(rangefunc):                   # for문이 정상 종료된 경우 범위가 지정되지 않은 숫자로만 이뤄진 IP이나

            hosts.append(rangefunc)            # IP가 정상적인 IP범위에 해당하는지 checkRange메서드 호출해서 true인경우만

    return hosts                                          # Host에 IP를 추가하고 리턴해준다.

 

parser = ArgumentParser('AdvPing')

parser.add_argument('ip', help='IP range to ping, e.g., 10.1.0-1.0-255 will expand to 10.1.0.0/23')

                                                                # 매개변수 관리용 : 'ip' 이름으로 매개변수 1번째를 관리

parser.add_argument('options', type=str, default=['1'], nargs='*', help='Options to pass to ping')

                                                                # 매개변수 관리용 : 'options'로 처리하며, typestr로 하고 default값은 '1' 로 한다.

args = parser.parse_args()                     # 매개변수 손쉽게 사용하기 위해서 parse_args()메서드 호출

targets = expandrange(args.ip,args.options)    # IP와 option(IP 증가값)을 가지고 호출

for ip in targets:     # Ping을 체크할 전체 IP 리스트를 순환하면서 실행

    tupleping  = cisco.cli('ping %s' % ip)       # Ping 명령을 실행하고 그에 대한 결과값을 받음.

    strping = str(tupleping) # Tuple형식의 결과값을 str type으로 변형

    m = re.search('([0-9\.]+)% packet loss',strping ) # 정규식을 활용하여 IP가 UP/Down 확인

    print('%s - %s' % (ip, 'UP' if float(m.group(1)) == 0.0 else 'DOWN')) # 해당 IP의 UP/Down 표기

 

 

 

pingrange Code : Modified Version : 결과값

NX-OS# python pingrange2.py 10.9.8.1-200 32

10.9.8.1 - UP

10.9.8.33 - DOWN

10.9.8.65 - UP

10.9.8.97 - UP

10.9.8.129 - DOWN

10.9.8.161 - DOWN

10.9.8.193 - DOWN