본문 바로가기

프로그래밍/Python

Programmability for Networker : Part 10

 


10번째 Python for Networker 포스팅입니다.

이번 포스팅에서 Cisco Nexus의 7000과 5000에서 공통으로 사용이 가능하도록 기존에 만들었던 ipinfo.py 모듈을 변경해봅니다.

장비별로 개개의 코드를 작성해서 수행하는 것보다는 장비에서 공통으로 호환성있게 사용 가능한 코드를 만드는 것이 향후 코드에 대한

유지보수 측면에서 더욱 유리할 것 이기 때문에 유심있게 봐두면 좋을 듯 싶습니다.

 

Git에서 Code 보기

  - einfo.py : https://github.com/NetworkZIGI/Python_for_Network/blob/master/eipinfo.py

  - vCheck.py : https://github.com/NetworkZIGI/Python_for_Network/blob/master/vCheck.py

 


 

 

Nexus 7000와 Nexus 5000에서 지원하는 Python의 경우에는 각각 지원되는 방식이 다르다.

 

실제 Cisco에서 제공되는 Python의 Cisco Module을 확인해 보면 아래와 같이 내장된 Member가 서로 다른 것을 확인할 수 있다.

 

◇ Nexus 7K Cisco Module

 

__doc__

__name__

__package__

cli

cli_execution_error

clil_syntax_error

clid

clip

set_vrf

 

 

◇ Nexus 5K Cisco Module

 

BGPSession

Routes

check_port_discards

line_parser

show_run

BufferDepthMonitor

SectionParser

cisco_secret

mac_address_table

ssh

CLI

VRF

cisco_socket

md5sum

tacacs

CheckPortDiscards

Vlan

cli

msdp

telnet

CiscoSecret

__all__

dhcp

ospf

transfer

CiscoSocket

__builtins__

eigrp

ospfv3

udld

Feature

__doc__

feature

pim

vlan

History

__file__

get_global_vrf

private-vlan

vpc

IPv4ACL

__name__

get_valid_port

ptp

vrf

IPv6ACL

__package__

history

rip

vrrp

Interface

__path__

hsrp

routes

vtp

Key

acl

interface

scheduler

 

LineParser

bfd

interface-vlan

section_parser

 

MacAddressTable

bgp

key

set_global_vrf

 

OSPFSession

buffer_depth_monitor

lacp

show_queues

 

 

 

서로 지원되는 Cisco Module이 다르기 때문에, 관리자가 Module을 새롭게 만들 경우에는 이러한 점이 고려되어야 합니다.

물론 Cisco Module을 사용하지 않고 만든 Python Module은 상관이 없겠지만, Cisco Module을 Import하여 만든 Python Module은

각 Nexus 별로 지원되는 내용과 결과값이 다르기 때문에 별개의 코드로 만들어야 하는 경우가 발생하게 됩니다.

 

기존 Python for Networker : Part 6 에서 다뤄졌던, IP를 가지고 해당 IP의 정보(IP / Mac  / VLAN / Interface / Description)를 보는

ipinfo.py의 경우에도 대부분의 코드가 비슷하지만, Cisco Module이 사용된 부분에 대해서는 내용이 달라지게 됩니다.

 

가령 Nexus 7K의 경우에는 Cisco Cli 명령을 수행하기 위해서 cisco.cli 메서드를 사용하여 결과를 수행하면 str(문자열) 값으로

결과값을 가져옵니다. 반면에 Nexus 5K의 경우에는 cisco.CLI 메서드르 사용하고 이러한 결과값은 tuple 형태로 결과를 가져옵니다.

 

이처럼 cisco에서 제공하는 Module이 서로 다르게 처리되다 보니, 각 Module을 만들고자 할 때에는 각각의 Module에서 사용되는

cisco Module을 고려하여 만들어야 합니다.

 

그렇다면, Nexus 7K와 Nexus 5K에서 공통으로 사용할 수 있는 코드를 만들 수는 없을까요?.... 물론 가능합니다.

 

먼저 아래의 예제 코드를 살펴보면..

 

 

vCheck.py : Nexus 7000/5000 구분하는 예제 코드

import sys
N7K = 'Nexus7000'
N5K = 'Nexus5000'
#N3K = 'Nexus3000'     : Constant for Extension.

NexusVersion = ''

def NexusVersionCheck():
    global NexusVersion
    sysPathList = sys.path
    for pathItem in sysPathList:
        if(pathItem=='/bootflash/scripts'):
            NexusVersion = N7K
            break
    else:
        NexusVersion = N5K

 

위의 예제 코드는 코드가 실행되는 장비가 Nexus 7000인지, 5000인지 확인하는 코드입니다.

원리는 무척이나 단순합니다.

 

각 장비의 path 정보값을 가져와서 확인을 하는 데, Nexus 7000에서는 기존 포스팅에서 다뤘던 것처럼

bootflash/scripts 에 Python Module이 들어가게 됩니다. 그리고 이 Path 정보는 Nexus 7000에만 있습니다.

(물론 제가 Testing이 가능한 장비가 Nexus 7000과 5000밖에 없기 때문에, 다른 장비에서는 어떻게 달라질지 그리고 그경우에는

 어떠한 방법으로 다시 구분을 할지는 달라지게 됩니다. 단지 장비별로 이렇게 특정값을 확인하여 어떤 장비인지 확인할 수 있는지에

 대한 부분을 확인하는 Module을 만든다면, 현재 해당 Module이 실행되는 장비가 어떤 장비인지 확인 할 수 있습니다.)

 

이러한 구분 정보를 통하여 현재 동작하고 있는 Module의 장비 값을 Global 변수에 저장할 수 있습니다.

그러면, 실제 특정 기능을 수행하는 Module에서는 위의 정보를 바탕으로 필요한 Cisco Module을 사용하여 처리할 수 있습니다.

 

위의 Nexus Version을 체크하는 Module을 바탕으로, 기존에 작성하였던 ipinfo.py를 Nexus 7000과 5000에서 모두 동작하게 하는

공통 Module로 아래와 같이 작성할 수 있습니다.

 

 

eipinfo.py

#!/bin/env python
import argparse
import sys
import cisco
import vCheck
from vCheck import NexusVersionCheck


IP = 'IP-Address'
MAC = 'Mac-Address'
Vlan = 'Vlan'
Intf = 'Interface'
Desc = 'Description'


IP_info = {IP:'None', MAC:'None', Vlan:'None', Intf:'None', Desc:'None'}

 

def get_ARP_Table(ipaddr):
    arpCmd = 'sh ip arp ' + ipaddr
    arpCmdResultList = [] 
    if(vCheck.NexusVersion==vCheck.N7K):
        arpCmdResult = cisco.cli(arpCmd)
        arpCmdResultList = arpCmdResult.split('\n')
    elif(vCheck.NexusVersion==vCheck.N5K):
        arpCmdResult = cisco.CLI(arpCmd, False)
        arpCmdResultList = arpCmdResult.get_output()

    for arp in arpCmdResultList:
        if (-1<arp.find(args.ip)):
            return arp
    else:
        print ' %s : Not found IP Address Infomation' % args.ip
        sys.exit()

 

def get_IP_MAC_info(info):
    info_list = info.split()
    IP_info[IP] = info_list[0]
    IP_info[MAC] = info_list[2]
    IP_info[Vlan] = info_list[3][4:]

 

def get_Interface_info():
    macCmd = 'sh mac address-table addr ' + IP_info[MAC]
    macCmdResultList = [] 

    if(vCheck.NexusVersion==vCheck.N7K):
        macCmdResult = cisco.cli(macCmd)
        macCmdResultList = macCmdResult.split('\n')
    elif(vCheck.NexusVersion==vCheck.N5K):
        macCmdResult = cisco.CLI(macCmd, False)
        macCmdResultList = macCmdResult.get_output()

 

    for infInfo in macCmdResultList:
        idx = infInfo.find(IP_info[MAC])
        if(-1<idx):
            IP_info[Intf] = infInfo[58:]
            get_Description_info(IP_info[Intf])
            break


def get_Description_info(iInfo):
    if(iInfo.find('Eth') == 0 or iInfo.find('Po')==0):
        intCmd = 'sh int desc | inc ' + iInfo
        if(vCheck.NexusVersion==vCheck.N7K):
            intCmdResult = cisco.cli(intCmd)
            intCmdResultList = intCmdResult.split('\n')
            if(intCmdResult != ''):
                IP_info[Desc] = intCmdResultList[0][25:].strip()
        elif(vCheck.NexusVersion==vCheck.N5K):
            intCmdResult = cisco.CLI(intCmd, False)
            intCmdResultList = intCmdResult.get_output()
            if(intCmdResult != ''):
                IP_info[Desc] = intCmdResultList[0][25:].strip()

 

def show_IP_info():
    print '==================================='
    print '      enhanced IP Info : NetworkZIGI                 '
    print '==================================='
    print '%-15s : %s' % (IP,IP_info[IP])
    print '%-15s : %s' % (MAC,IP_info[MAC])
    print '%-15s : %s' % (Vlan, IP_info[Vlan])
    print '%-15s : %s' % (Intf, IP_info[Intf])
    print '%-15s : %s' % (Desc,IP_info[Desc])

 

NexusVersionCheck()
parser = argparse.ArgumentParser('Args',description='Args Desc')
parser.add_argument('ip')
args = parser.parse_args()
iparp = get_ARP_Table(args.ip)
get_IP_MAC_info(iparp)
get_Interface_info()
show_IP_info()

 

 

위의 Code 중에서 파란색으로 표기된 부분이 Nexus 7K와 5K를 구분하기 위한 부분입니다.

 

 그럼 이제 위의 1개의 코드로 Nexus 7000과 Nexus 5000에서 별도의 코드를 각각 사용하는 것이 아닌, 하나의 동일한 코드로

원하는 결과값을 같이 얻을 수 있게 되었습니다.

 

 이번 Part에서 다뤄진 부분은 제가 Test가 가능한 장비를 기준으로 두 장비에 대해서 단순한 방법으로 구분을 지었습니다.

하지만, Nexus 의 다른 시리즈의 경우에는 또 지원되는 부분이 다르기 때문에 그러한 부분까지 수용하기 위해서는 장비를 구분하는

vCheck 모듈의 수정이 필요하게 될 것입니다.

 

 여기서 세부적인 장비 구분을 체크하는 실제적인 내용보다는, 그러한 장비 구분을 통해서 실제 수행을 원하는 내용의 코드를 장비 개별

코드가 아니라, 하나의 공통 코드로 만들어서 사용할 수 있다는 것이 다루고자 하는 내용이었습니다.  

 

 그러한 부분을 잘 활용하게 된다면, 하나의 코드로 다른 버전의 장비에서도 호환이 되는 코드를 작성할 수 있을 것입니다.

 

물론 아예 처음부터 지원되는 cisco module이 동일하다면, 이러한 부분을 별도로 고려하지 않을 수 있겠지만

그러한 부분도 고려한 코드를 작성하는 것도 현재 시점에서는 또 하나의 몫이 아닐까 생각을 해봅니다.