[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:
- A „statische Methode“ genannt build(), die zur HelloHandler Klasse gehört, die selbst eine Unterklasse von SessionListener ist
- 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).
- 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>
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
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. –
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