2013-01-05 11 views
6

[EDIT:私は、Python 2.7.3を実行している]実行時にパッケージの内容を上書きする方法は?

私は貿易によってネットワークエンジニアだ、と私はncclientにハッキングしてきた(ウェブサイト上のバージョンが古く、thisはバージョンでしたI BrocadeのNETCONFの実装と連携させるために取り組んできました。 Brocadeの機器で動作させるためには、いくつか調整が必要でしたが、パッケージを切り捨て、ソース自体を調整する必要がありました。これは私にとって「きれい」ではないと感じたので、私はそれを「正しい方法」にしてパッケージに存在するいくつかのものを無効にしようと決めた*。特に三つのこと:

  1. HelloHandlerクラスに属するビルド(いわゆる「静的メソッド」)、自身がRPCクラスの「._id」属性(元の実装SessionListener
  2. のサブクラスでありますBrocadeの箱はこれをあまり好きではなかったので、私の元の微調整では、これを変更していない静的な値に変更しました)。
  3. XMLフィルタを構築するutilの機能に小さな微調整は、これまでのところ、私はファイル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でタイムアウトエラーが発生します。私のサブクラスの定義(すなわち、hello交換用のXMLを変更するもの、つまりstaticmethod build)は無視され、元のncclient HelloHandler.build()メソッドが生成しているXMLをBrocadeボックスがどのように解釈するのかは分かりません。また、生成されたログファイルで、上書きしようとしている他のものも、メッセージID(静的な値1)やXMLフィルタのように無視されていることがわかります。

私はここで紛失しています。私はthis blog post/moduleを私の研究から見つけました、そして、私が欲しいものを正確に行うように見えるでしょうが、誰かが持っているモジュールを使うのではなく、私が手作業でやっていることを間違って理解したいと思っています。私自身でこれを理解する必要がないという言い訳としてすでに書かれています。

*「サルパッチ」で実際に悪いと誰かが私に説明することはできますか?私の研究では、サルのパッチが望ましくないことがわかりましたが、this answerthis answerはかなり混乱しています。私にとっては、これらのビットを無効にしたいという私の願望は、私自身のncclientのフォーク全体を維持する必要がなくなります。

**、ncclient.transport.session.HelloHandler.build()がデフォルトで生成し、このXMLを、もう少しコンテキストを与えるために、ブロケードボックスが好きていないようです:

<?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上記本に(ブロケードが似ていた:

<?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に定義されていないため、コードでNameErrorsが生成されます。実行しているコードを投稿しているわけではありません。つまり、 'manager'の' OPERATIONS'ディクテーションはあなたにこのようなことをさせるものです。あなたはそれを見ましたか? – BrenBarn

+0

'BROCADE_1_0'について' netconftest.py'を実行しているときに名前定義エラーが生成されていません。それらを定義する 'brcd_ncclient'をインポートしたためです。' OPERATIONS' dictは 'ncclient.operations 'の素晴らしいマップです。 rpc.Method'これは私が実際に変更したいものではありません。私が実行しているコードを投稿することがどういう意味なのか分かりません。私は実行しているコードを投稿しました。 –

+0

'brcd_ncclient'をインポートしても、名前はnetconftest.pyで利用できません。 'brcd_ncclient import *'を使用するか、 'brcd_ncclient.BROCADE_1_0'などで名前にアクセスする必要があります。 – BrenBarn

答えて

2

だから、再び、それは私が後だものに答えを見つけることは困難ですので、「メタ情報」は、それほど急いで削除されているべきではないことが判明私が欲しいものを完全に理解していないとき 聞く、質問する。私が本当にやりたかったのは、パッケージ内でのオーバーライドでした。ランタイムです。これは、ほとんど私がなりたい場所に私を取得

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

netconftest.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 

そして:ここ

は、私が(簡潔にするため削除コメント)にbrcd_ncclient.pyを変更したものです。私はまだメッセージのIDを変更するために元のソースコードを編集する必要があります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に行きます。私が最初に投稿したコードは、私が技術的に間違っているとは思わない - もし私がやりたいことが自分のncclientをフォークして変更したり、それを維持したりしていたら、少なくとも今はそうではありません。

私が最初に望んでいたものをよりよく反映するために、私の質問のタイトルを編集します。もし他の人々がより良い、またはよりクリーンなアイデアを持っていれば、私は完全にオープンです。

関連する問題