2013-01-05 16 views
6

[संपादित करें: मैं अजगर 2.7.3 चल रहा हूँ]रनटाइम पर किसी पैकेज में सामान को ओवरराइड कैसे करें?

मैं व्यापार के द्वारा एक नेटवर्क इंजीनियर हूं, और मैं ncclient पर हैकिंग कर रहा है (वेबसाइट पर संस्करण पुराना है, और this संस्करण था मैं ब्रोकैड के नेटकॉनएफ के कार्यान्वयन के साथ काम करने के लिए इसे बंद कर दिया गया है)। हमारे ब्रोकैड उपकरणों के साथ काम करने के लिए मुझे कुछ बदलाव करना पड़ा, लेकिन मुझे पैकेज को फोर्क करना पड़ा और स्रोत को खुद को बदलना पड़ा। यह मुझे "साफ" महसूस नहीं करता था इसलिए मैंने फैसला किया कि मैं इसे "सही तरीके से" करने की कोशिश करना चाहता हूं और पैकेज में मौजूद कुछ चीजों को ओवरराइड करना चाहता हूं; विशेष रूप से तीन बातें:

  1. ए 'स्थिर विधि "कहा जाता है का निर्माण() जो HelloHandler वर्ग है, जो खुद" ._id "SessionListener
  2. का एक उपवर्ग आरपीसी वर्ग की विशेषता (मूल कार्यान्वयन है के अंतर्गत आता है यूयूड का इस्तेमाल किया गया, और ब्रोकैड बक्से को यह बहुत पसंद नहीं आया, इसलिए मेरे मूल tweaks में मैंने इसे एक स्थिर मूल्य में बदल दिया जो कभी नहीं बदला)।
  3. एक util कार्य करने के लिए एक छोटा सा ट्वीक कि XML फिल्टर बनाता विशेषताओं

अब तक मैं एक फ़ाइल 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 

और फिर मेरी फाइल netconftest.py में मेरे पास है:

#!/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' 

जब भी मैं अपनी netconftest.py फ़ाइल चलाता हूं, मुझे टाइमआउट त्रुटियां मिलती हैं क्योंकि लॉग फ़ाइल ncclient.log I में देख सकते हैं कि मेरी सबक्लास परिभाषाएं (अर्थात् वह है जो हैलो एक्सचेंज के लिए एक्सएमएल को बदलता है - staticmethod build) को अनदेखा किया जा रहा है और ब्रोकैड बॉक्स को यह नहीं पता कि एक्सएमएल की व्याख्या कैसे करें, मूल ncclient HelloHandler.build() विधि उत्पन्न हो रही है **। मैं जेनरेट किए गए लॉगफाइल में भी देख सकता हूं कि अन्य चीजें जो मैं ओवरराइड करने की कोशिश कर रहा हूं उन्हें भी अनदेखा किया जा रहा है, जैसे संदेश-आईडी (1 का स्थिर मूल्य) और साथ ही एक्सएमएल फ़िल्टर।

तो, मैं यहां एक नुकसान का प्रकार हूं। मुझे अपने शोध से this blog post/module मिल गया, और ऐसा लगता है कि मैं वही कर सकता हूं, लेकिन मैं वास्तव में यह समझने में सक्षम होना चाहता हूं कि मैं इसे किसी मॉड्यूल का उपयोग करने के बजाय हाथ से कर रहा हूं, पहले से ही यह पता लगाने के लिए एक बहाना के रूप में लिखा है।

* क्या कोई मुझे बता सकता है कि यह "बंदर पैचिंग" है और वास्तव में बुरा है? मैंने अपने शोध में देखा है कि बंदर पैचिंग वांछनीय नहीं है, लेकिन this answer और this answer मुझे थोड़ा उलझन में डाल रहे हैं। मेरे लिए, इन बिट्स को ओवरराइड करने की मेरी इच्छा मुझे अपने स्वयं के नक्षत्र के पूरे कांटे को बनाए रखने से रोकती है।

थोड़ा और संदर्भ, इस एक्सएमएल, जो ncclient.transport.session.HelloHandler.build() डिफ़ॉल्ट रूप से उत्पन्न करता है देने के लिए **, ब्रोकेड बॉक्स की तरह प्रतीत नहीं होता:

<?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> 

मेरी अधिरोहित build() विधि के प्रयोजन के चालू करने के लिए है इस में एक्सएमएल (जो ब्रोकेड की तरह ऊपर:

<?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

आपका कोड नामकरण उत्पन्न करेगा क्योंकि 'BROCADE_1_0' जैसे नाम nfconftest.py में परिभाषित नहीं हैं। आप जो कोड चला रहे हैं उसे पोस्ट नहीं कर रहे हैं। ऐसा कहा जाता है, ऐसा लगता है कि 'प्रबंधक' में 'ऑपरेशंस' का अर्थ आपको इस तरह की चीज करने के लिए है। क्या तुमने उस पर देखा? – BrenBarn

+0

'BROCADE_1_0' के बारे में' netconftest.py' के रनों के दौरान कोई नाम त्रुटियां उत्पन्न नहीं की जा रही हैं क्योंकि मैंने 'brcd_ncclient' आयात किया है जो उन्हें परिभाषित करता है ....' ऑपरेशन 'dict 'ncclient.operations के लिए केवल एक फैंसी मानचित्र है। rpc.Method' और यह वह नहीं है जिसे मैं वास्तव में बदलना चाहता हूं। मुझे यकीन नहीं है कि मैं जो कोड चला रहा हूं उसे पोस्ट करने के बारे में आपका क्या मतलब है। मैंने जो कोड चलाया है उसे पोस्ट किया है। –

+0

'brcd_ncclient' आयात करने से नाम netconftest.py में उपलब्ध नहीं होंगे। आपको 'brcd_ncclient import * से 'का उपयोग करना होगा, या' brcd_ncclient.BROCADE_1_0', आदि के माध्यम से नामों का उपयोग करना होगा। – BrenBarn

उत्तर

2

तो यह पता चला है कि "मेटा जानकारी" इतनी जल्दी से हटा नहीं किया जाना चाहिए था, क्योंकि फिर, यह है कि मैं क्या कर रहा हूँ के बाद के लिए जवाब मिल मुश्किल है जब मैं पूरी तरह से समझ नहीं पा रहा हूं कि मैं क्या चाहता हूं पूछना।मैं वास्तव में क्या करना चाहता था पैकेज रनटाइम पर सामान को ओवरराइड करना था।

यहाँ है कि मैं क्या (संक्षिप्तता के लिए निकाली गई टिप्पणियां) को brcd_ncclient.py बदल गया है:

#!/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 

और फिर 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 

यह मैं जहाँ मैं होना चाहता हूँ करने के लिए लगभग हो जाता है। मुझे अभी भी uuid1().urn के साथ उत्पन्न होने से संदेश-आईडी को बदलने के लिए मूल स्रोत कोड को संपादित करना है क्योंकि मुझे पता नहीं चला है कि __init__ रनटाइम (चिकन/अंडा समस्या?) से पहले किसी ऑब्जेक्ट के गुणों को बदलने का तरीका नहीं समझता है। ; यहाँ 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 

क्रेडिट अंत में मुझे क्या मैं सच में करना चाहता था पर में cluing के लिए this recipe on ActiveState को जाता है। जिस कोड को मैंने मूल रूप से पोस्ट किया था, मुझे नहीं लगता कि तकनीकी रूप से गलत था - अगर मैं जो करना चाहता था वह मेरे अपने नुकीले से कांटा गया था और इसमें बदलाव आया था और/या इसे बनाए रखा था, जो मैं बिल्कुल नहीं करना चाहता था, कम से कम अभी नहीं।

मैं अपने प्रश्न शीर्षक को बेहतर रूप से प्रतिबिंबित करने के लिए संपादित करूंगा जो मूल रूप से चाहता था - अगर अन्य लोगों के पास बेहतर या साफ विचार हैं, तो मैं पूरी तरह से खुला हूं।

संबंधित मुद्दे