[EDIT: I am running Python 2.7.3]
I trade in the network, and I hacked into ncclient (the version on the website is outdated, and this was the version I was working on) so that it works with the Brocade NETCONF implementation. There are some settings that I had to make to make it work with our Brocade equipment, but I had to refuse the package and make changes to the source code. This did not seem “clean” to me, so I decided to try “correctly” and redefine a couple of things that exist in the package *; three things:
- A "static method" called build (), which belongs to the HelloHandler class, which itself is a subclass of SessionListener
- Attribute "._id" of RPC class (the original implementation used in uuid and Brocade blocks didn’t really like, so in my initial tricks I just changed it to a static value that never changed).
- A small tweak to the util function, which builds the attributes of an XML filter
So far, I have this code in the brcd_ncclient.py file:
#!/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 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
And then in my netconftest.py file I have:
#!/usr/bin/env python from ncclient import manager from brcd_ncclient import * manager.logging.basicConfig(filename='ncclient.log', level=manager.logging.DEBUG)
Whenever I run my netconftest.py file, I get timeout errors because in the ncclient.log log ncclient.log I see that my subclass definitions (namely the one that modifies XML for greetings - staticmethod build )) are ignored, and the Brocade field does not know how to interpret the XML that the source ncclient HelloHandler.build() generates. I also see in the generated log file that other things I'm trying to override are also ignored, for example, the message identifier (static value 1), as well as XML filters.
So, I'm a little confused. I found this blog post / module from my research, and it seems to be doing what I want, but I would really like to be able to understand what I'm doing wrong by doing it manually, instead of using the module, which someone has already written as an excuse not to come up with this on their own.
* Can someone explain to me if this "beheading of the monkeys" is really bad? I have seen in my research that correcting monkeys is undesirable, but this answer and this answer confuse me quite a bit. For me, my desire to override these bits would not prevent me from supporting the whole fork of my own ncclient.
** To give a little more context, this XML, which ncclient.transport.session.HelloHandler.build() generates by default, seems like the Brocade box doesn't like:
<?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>
The purpose of my overridden build() method is to turn the above XML into this (which Brocade does:
<?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>