2013-01-05 30 views
6

[EDIT: Tôi đang chạy Python 2.7.3]Làm cách nào để ghi đè lên nội dung trong gói khi đang chạy?

Tôi là một kỹ sư mạng bằng thương mại, và tôi đã được hack vào ncclient (phiên bản trên trang web là cũ, và this là phiên bản tôi đã được làm việc ra khỏi) để làm cho nó làm việc với việc thực hiện của Brocade của NETCONF. Có một số chỉnh sửa mà tôi đã phải thực hiện để có được nó để làm việc với thiết bị thổ cẩm của chúng tôi, nhưng tôi đã phải ngã ba ra khỏi gói và làm cho tinh chỉnh cho nguồn chính nó. Điều này không cảm thấy "sạch" với tôi vì vậy tôi quyết định tôi muốn cố gắng làm điều đó "đúng cách" và ghi đè lên một vài điều tồn tại trong gói *; ba điều cụ thể:

  1. A "phương pháp tĩnh" được gọi là xây dựng() mà thuộc về lớp HelloHandler, mà chính nó là một lớp con của SessionListener
  2. Các "._id" thuộc tính của lớp RPC (thực hiện ban đầu uuid được sử dụng, và hộp thổ cẩm không thích điều này rất nhiều, vì vậy trong tinh chỉnh ban đầu của tôi, tôi chỉ thay đổi này thành một giá trị tĩnh mà không bao giờ thay đổi).
  3. Một tinh chỉnh nhỏ để một hàm util mà xây dựng bộ lọc XML thuộc tính

Cho đến nay tôi có mã này trong một tập tin brcd_ncclient.py:

#!/usr/bin/env python 

# hack on XML element creation and create a subclass to override HelloHandler's 
# build() method to format the XML in a way that the brocades actually like 

from ncclient.xml_ import * 
from ncclient.transport.session import HelloHandler 
from ncclient.operations.rpc import RPC, RaiseMode 
from ncclient.operations import util 

# register brocade namespace and create functions to create proper xml for 
# hello/capabilities exchange 

BROCADE_1_0 = "http://brocade.com/ns/netconf/config/netiron-config/" 
register_namespace('brcd', BROCADE_1_0) 

brocade_new_ele = lambda tag, ns, attrs={}, **extra: ET.Element(qualify(tag, ns), attrs, **extra) 

brocade_sub_ele = lambda parent, tag, ns, attrs={}, **extra: ET.SubElement(parent, qualify(tag, ns), attrs, **extra) 

# subclass RPC to override self._id to change uuid-generated message-id's; 
# Brocades seem to not be able to handle the really long id's 
class BrcdRPC(RPC): 
    def __init__(self, session, async=False, timeout=30, raise_mode=RaiseMode.NONE): 
     self._id = "1" 
     return super(BrcdRPC, self).self._id 

class BrcdHelloHandler(HelloHandler): 
    def __init__(self): 
     return super(BrcdHelloHandler, self).__init__() 

    @staticmethod 
    def build(capabilities): 
     hello = brocade_new_ele("hello", None, {'xmlns':"urn:ietf:params:xml:ns:netconf:base:1.0"}) 
     caps = brocade_sub_ele(hello, "capabilities", None) 
     def fun(uri): brocade_sub_ele(caps, "capability", None).text = uri 
     map(fun, capabilities) 
     return to_xml(hello) 
     #return super(BrcdHelloHandler, self).build() ??? 

# since there's no classes I'm assuming I can just override the function itself 
# in ncclient.operations.util? 
def build_filter(spec, capcheck=None): 
    type = None 
    if isinstance(spec, tuple): 
     type, criteria = spec 
     # brocades want the netconf prefix on subtree filter attribute 
     rep = new_ele("filter", {'nc:type':type}) 
     if type == "xpath": 
      rep.attrib["select"] = criteria 
     elif type == "subtree": 
      rep.append(to_ele(criteria)) 
     else: 
      raise OperationError("Invalid filter type") 
    else: 
     rep = validated_element(spec, ("filter", qualify("filter")), 
            attrs=("type",)) 
     # TODO set type var here, check if select attr present in case of xpath.. 
    if type == "xpath" and capcheck is not None: 
     capcheck(":xpath") 
    return rep 

Và sau đó trong tập tin của tôi netconftest.py tôi có:

#!/usr/bin/env python 

from ncclient import manager 
from brcd_ncclient import * 

manager.logging.basicConfig(filename='ncclient.log', level=manager.logging.DEBUG) 

# brocade server capabilities advertising as 1.1 compliant when they're really not 
# this will stop ncclient from attempting 1.1 chunked netconf message transactions 
manager.CAPABILITIES = ['urn:ietf:params:netconf:capability:writeable-running:1.0', 'urn:ietf:params:netconf:base:1.0'] 

# BROCADE_1_0 is the namespace defined for netiron configs in brcd_ncclient 
# this maps to the 'brcd' prefix used in xml elements, ie subtree filter criteria 
with manager.connect(host='hostname_or_ip', username='username', password='password') as m: 
    # 'get' request with no filter - for brocades just shows 'show version' data 
    c = m.get() 
    print c 
    # 'get-config' request with 'mpls-config' filter - if no filter is 
    # supplied with 'get-config', brocade returns nothing 
    netironcfg = brocade_new_ele('netiron-config', BROCADE_1_0) 
    mplsconfig = brocade_sub_ele(netironcfg, 'mpls-config', BROCADE_1_0) 
    filterstr = to_xml(netironcfg) 
    c2 = m.get_config(source='running', filter=('subtree', filterstr)) 
    print c2 
    # so far it only looks like the supported filters for 'get-config' 
    # operations are: 'interface-config', 'vlan-config' and 'mpls-config' 

Bất cứ khi nào tôi chạy tệp netconftest.py, tôi nhận được lỗi hết thời gian chờ vì trong tệp nhật ký ncclient.log I có thể thấy rằng các định nghĩa lớp con của tôi (cụ thể là một thay đổi XML cho hello exchange - staticmethod build) đang bị bỏ qua và hộp Brocade không biết cách giải thích XML mà phương thức ncclient HelloHandler.build() ban đầu đang tạo **. Tôi cũng có thể thấy trong logfile được tạo ra rằng những thứ khác mà tôi đang cố gắng ghi đè cũng bị bỏ qua, giống như id tin nhắn (giá trị tĩnh của 1) cũng như các bộ lọc XML.

Vì vậy, tôi hơi thất vọng ở đây. Tôi đã tìm thấy this blog post/module từ nghiên cứu của mình và dường như thực hiện chính xác những gì tôi muốn, nhưng tôi thực sự muốn hiểu những gì tôi làm sai bằng cách thực hiện nó bằng tay, thay vì sử dụng mô-đun mà ai đó có đã được viết như một cái cớ để không phải tự mình hình dung ra điều này.

* Ai đó có thể giải thích cho tôi nếu đây là "vá khỉ" và thực sự tệ? Tôi đã thấy trong nghiên cứu của tôi rằng khỉ vá không phải là mong muốn, nhưng this answerthis answer là khó hiểu tôi khá một chút. Đối với tôi, mong muốn của tôi để ghi đè các bit này sẽ ngăn cản tôi phải duy trì một chiếc nĩa toàn bộ ncclient của chính tôi.

** Để cung cấp cho một chút bối cảnh nhiều hơn, XML này, mà ncclient.transport.session.HelloHandler.build() tạo ra theo mặc định, thổ cẩm hộp dường như không thích:

<?xml version='1.0' encoding='UTF-8'?> 
    <nc:hello xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> 
     <nc:capabilities> 
      <nc:capability>urn:ietf:params:netconf:base:1.0</nc:capability> 
      <nc:capability>urn:ietf:params:netconf:capability:writeable-running:1.0</nc:capability> 
     </nc:capabilities> 
    </nc:hello> 

Mục đích của ghi đè build() phương pháp của tôi là để biến trên XML vào này (mà thổ cẩm làm như:

<?xml version="1.0" encoding="UTF-8"?> 
    <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> 
     <capabilities> 
      <capability>urn:ietf:params:netconf:base:1.0</capability> 
      <capability>urn:ietf:params:netconf:capability:writeable-running:1.0</capability> 
     </capabilities> 
    </hello> 
+0

Mã của bạn sẽ tạo NameErrors vì các tên như 'BROCADE_1_0' không được định nghĩa trong nfconftest.py. Bạn không đăng mã bạn đang chạy. Điều đó nói rằng, có vẻ như lệnh 'HOẠT ĐỘNG' trong 'người quản lý' có nghĩa là để bạn làm điều này. Bạn có nhìn vào đó không? – BrenBarn

+0

Không có lỗi tên nào được tạo trong quá trình chạy 'netconftest.py' về' BROCADE_1_0' vì tôi đã nhập 'brcd_ncclient' xác định chúng .... dict 'OPERATIONS' chỉ là một bản đồ lạ mắt cho' ncclient.operations. rpc.Method' và đây không phải là những gì tôi thực sự muốn thay đổi. Tôi không chắc chắn ý của bạn về việc đăng mã tôi đang chạy. Tôi đã đăng mã tôi đang chạy. –

+0

Nhập 'brcd_ncclient' sẽ không tạo tên có sẵn trong netconftest.py. Bạn sẽ phải sử dụng 'từ nhập khẩu brcd_ncclient *' hoặc truy cập tên thông qua 'brcd_ncclient.BROCADE_1_0', v.v. – BrenBarn

Trả lời

2

vì vậy, nó chỉ ra rằng "Thông tin meta" không nên có được như vậy vội vàng loại bỏ, bởi vì một lần nữa, thật khó để tìm câu trả lời cho những gì tôi là sau khi khi tôi không hoàn toàn hiểu những gì tôi muốn hỏi.Điều tôi thực sự muốn làm là ghi đè nội dung trong gói khi chạy.

Dưới đây là những gì tôi đã thay đổi brcd_ncclient.py đến (nhận xét bị xóa cho ngắn gọn):

#!/usr/bin/env python 

from ncclient import manager 
from ncclient.xml_ import * 

brcd_new_ele = lambda tag, ns, attrs={}, **extra: ET.Element(qualify(tag, ns), attrs, **extra) 
brcd_sub_ele = lambda parent, tag, ns, attrs={}, **extra: ET.SubElement(parent, qualify(tag, ns), attrs, **extra) 

BROCADE_1_0 = "http://brocade.com/ns/netconf/config/netiron-config/" 
register_namespace('brcd', BROCADE_1_0) 

@staticmethod 
def brcd_build(capabilities): 
    hello = brcd_new_ele("hello", None, {'xmlns':"urn:ietf:params:xml:ns:netconf:base:1.0"}) 
    caps = brcd_sub_ele(hello, "capabilities", None) 
    def fun(uri): brcd_sub_ele(caps, "capability", None).text = uri 
    map(fun, capabilities) 
    return to_xml(hello) 

def brcd_build_filter(spec, capcheck=None): 
    type = None 
    if isinstance(spec, tuple): 
     type, criteria = spec 
     # brocades want the netconf prefix on subtree filter attribute 
     rep = new_ele("filter", {'nc:type':type}) 
     if type == "xpath": 
      rep.attrib["select"] = criteria 
     elif type == "subtree": 
      rep.append(to_ele(criteria)) 
     else: 
      raise OperationError("Invalid filter type") 
    else: 
     rep = validated_element(spec, ("filter", qualify("filter")), 
           attrs=("type",)) 
    if type == "xpath" and capcheck is not None: 
     capcheck(":xpath") 
    return rep 

manager.transport.session.HelloHandler.build = brcd_build 
manager.operations.util.build_filter = brcd_build_filter 

Và sau đó trong netconftest.py:

#!/usr/bin/env python 

from brcd_ncclient import * 

manager.logging.basicConfig(filename='ncclient.log', level=manager.logging.DEBUG) 

manager.CAPABILITIES = ['urn:ietf:params:netconf:capability:writeable-running:1.0', 'urn:ietf:params:netconf:base:1.0'] 

with manager.connect(host='host', username='user', password='password') as m: 
    netironcfg = brcd_new_ele('netiron-config', BROCADE_1_0) 
    mplsconfig = brcd_sub_ele(netironcfg, 'mpls-config', BROCADE_1_0) 
    filterstr = to_xml(netironcfg) 
    c2 = m.get_config(source='running', filter=('subtree', filterstr)) 
    print c2 

này được tôi gần đến nơi tôi muốn trở thành. Tôi vẫn phải chỉnh sửa mã nguồn ban đầu để thay đổi thông báo-id được tạo ra với uuid1().urn bởi vì tôi đã không tìm ra hoặc không hiểu làm thế nào để thay đổi thuộc tính của đối tượng trước khi __init__ xảy ra khi chạy (vấn đề gà/trứng?) ; đây là mã vi phạm trong ncclient/operations/rpc.py:

class RPC(object): 
    DEPENDS = [] 
    REPLY_CLS = RPCReply 
    def __init__(self, session, async=False, timeout=30, raise_mode=RaiseMode.NONE): 
     self._session = session 
     try: 
      for cap in self.DEPENDS: 
       self._assert(cap) 
     except AttributeError: 
      pass 
     self._async = async 
     self._timeout = timeout 
     self._raise_mode = raise_mode 
     self._id = uuid1().urn # Keeps things simple instead of having a class attr with running ID that has to be locked 

tín dụng đi vào this recipe on ActiveState cho cuối cùng cluing tôi về những gì tôi thực sự muốn làm. Mã mà tôi đã đăng ban đầu tôi không nghĩ là không chính xác về mặt kỹ thuật - nếu những gì tôi muốn làm là bỏ ncclient của riêng tôi và thay đổi nó và/hoặc duy trì nó, đó không phải là điều tôi muốn làm gì cả, Ít nhất là không phải bây giờ.

Tôi sẽ chỉnh sửa tiêu đề câu hỏi của mình để phản ánh tốt hơn những gì tôi đã muốn ban đầu - nếu những người khác có ý tưởng tốt hơn hoặc sạch hơn, tôi hoàn toàn cởi mở.

Các vấn đề liên quan