2013-01-05 10 views
6

[EDIT: Ich bin mit Python 2.7.3]Wie überschreibt man Sachen in einem Paket zur Laufzeit?

Ich bin ein Netzwerk-Ingenieur von Beruf, und ich habe auf der Website auf ncclient (die Version Hacking ist alt, und this war die Version I habe gearbeitet, um es mit Brocades Implementierung von NETCONF funktionieren zu lassen. Es gab einige Verbesserungen, die ich machen musste, um es mit unserer Brocade-Ausrüstung funktionieren zu lassen, aber ich musste das Paket abzweigen und Verbesserungen an der Quelle vornehmen. Das fühlte sich für mich nicht "sauber" an, also entschied ich, dass ich versuchen wollte, es "richtig zu machen" und ein paar Dinge, die im Paket existieren, außer Kraft zu setzen *; drei Dinge gesagt:

  1. A „statische Methode“ genannt build(), die zur HelloHandler Klasse gehört, die selbst eine Unterklasse von SessionListener ist
  2. Die „._id“ Attribut der RPC-Klasse (die ursprüngliche Implementierung UUID verwendet, und Brocade-Boxen haben das nicht sehr gefallen, also habe ich das in meinen ursprünglichen Tweaks einfach auf einen statischen Wert geändert, der sich nie geändert hat).
  3. Eine kleine zwicken auf eine util-Funktion, die XML-Filter baut Attribute

Bisher habe ich diesen Code in einer Datei brcd_ncclient.py haben:

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

Und dann in meiner Datei netconftest.py ich habe:

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

Immer wenn ich meine netconftest.py Datei ausführen, bekomme ich Timeout-Fehler, weil in der Protokolldatei ncclient.log ich Ich kann sehen, dass meine Unterklassendefinitionen (nämlich diejenige, die das XML für Hello-Austausch ändert - die staticmethod build) ignoriert werden und die Brocade-Box nicht weiß, wie das XML zu interpretieren ist, das die ursprüngliche Methode ncclient erzeugt **. Ich kann auch in der generierten Logdatei sehen, dass die anderen Dinge, die ich zu überschreiben versuche, ebenfalls ignoriert werden, wie die Message-ID (statischer Wert 1) sowie die XML-Filter.

So bin ich irgendwie ratlos hier. Ich habe this blog post/module aus meiner Forschung gefunden, und es scheint genau das zu tun, was ich will, aber ich würde wirklich gerne verstehen, was ich falsch mache, indem ich es manuell mache, anstatt ein Modul zu benutzen, das jemand hat schon als Ausrede geschrieben, um das nicht selbst herausfinden zu müssen.

* Kann mir jemand erklären, wenn das "Affenflicken" ist und ist eigentlich schlecht? Ich habe in meinen Nachforschungen gesehen, dass Affepatching nicht wünschenswert ist, aber this answer und this answer verwirren mich ziemlich. Für mich würde mein Wunsch, diese Bits außer Kraft zu setzen, mich davon abhalten, eine ganze Gabelung meines eigenen ncclient aufrechtzuerhalten.

** ein wenig mehr Kontext zu geben, diese XML, die ncclient.transport.session.HelloHandler.build() standardmäßig erzeugt, wird die Brocade-Box nicht zu mögen scheint:

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

Der Zweck meiner außer Kraft gesetzt build() Methode ist die drehen über XML in das (die der Brocade tut wie:

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

Ihr Code generiert NameErrors, weil Namen wie 'BROCADE_1_0' nicht in nfconftest.py definiert sind. Sie veröffentlichen nicht den Code, den Sie ausführen. Es sieht so aus, als ob das 'OPERATIONS'-Diktat in' manager' es dir erlaubt, so etwas zu tun. Hast du dir das angeschaut? – BrenBarn

+0

Während der Läufe von 'netconftest.py' zu' BROCADE_1_0' werden keine Namensfehler generiert, da ich 'brcd_ncclient' importiert habe, der sie definiert .... das' OPERATIONS'-Dict ist nur eine fancy map zu 'ncclient.operations. rpc.Method' und das ist nicht das, was ich wirklich ändern möchte. Ich bin mir nicht sicher, was Sie damit meinen, den Code zu veröffentlichen, den ich verwende. Ich habe den Code gepostet, den ich verwende. –

+0

Durch den Import von 'brcd_ncclient' werden die Namen in netconftest.py nicht verfügbar. Sie müssten 'from brcd_ncclient import *' verwenden oder über 'brcd_ncclient.BROCADE_1_0' usw. auf die Namen zugreifen. – BrenBarn

Antwort

2

so stellt sich heraus, dass die „Meta-Info“ sollte nicht so schnell entfernt worden sein, denn wieder ist es schwierig, Antworten zu finden, was ich nach wenn ich nicht ganz verstehe, was ich will Fragen.Was ich wirklich tun wollte, war, Sachen in einem Paket zu überschreiben zur Laufzeit.

Hier ist, was ich brcd_ncclient.py zu (Kommentare der Kürze entfernt) geändert haben:

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

Und dann in 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 

Dies bringt mich fast um, wo ich sein möchte. Ich muss noch den ursprünglichen Quellcode bearbeiten, um zu ändern, dass die Nachrichten-IDs mit uuid1().urn generiert werden, weil ich nicht herausgefunden habe oder nicht verstehe, wie man die Attribute eines Objekts ändert, bevor __init__ zur Laufzeit passiert (Huhn/Ei Problem?) ; hier ist der Code säumige in 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 

Kredit geht an this recipe on ActiveState für mich schließlich cluing in dem, was ich wirklich tun wollte. Der Code, den ich ursprünglich gepostet habe, ist meiner Meinung nach technisch nicht korrekt - wenn ich den eigenen NCCClient abzweigen und Änderungen daran vornehmen und/oder beibehalten würde, was ich überhaupt nicht machen wollte, zumindest jetzt nicht.

Ich werde meinen Fragetitel bearbeiten, um besser zu reflektieren, was ich ursprünglich wollte - wenn andere Leute bessere oder sauberere Ideen haben, bin ich völlig offen.

Verwandte Themen