Constructs ========== PyDME tries to provide a minimal set of constructs, that should be enough to achieve most of the tasks that would otherwise be achieved using the REST API. Node ---- A Node represents the nexus node that one would be communicating with. This could be a standalone, leaf or spine. A Node object can be instantiated by specifying the REST URL for communicating with the underlying node. >>> from pydme import Node >>> nxsw = Node('https://192.168.10.1') It is also possible to provide DME meta data file to when the Node object is instantiated. >>> nxsw = Node('https://192.168.10.1', 'path/to/dme-meta.json') The default way is to not provide the DME meta file so that PyDME will automatically get the version of the device and gets the proper DME meta file based on that version and uses it. For more information, refer to Node documentation. API Objects ----------- Once a Node has been instantiated, a variety of API objects can be spawned from that. There are two classes of these objects: - Methods - Managed objects All these objects support one, or many REST operations. The objects are local instances and objects don't interact with the underlying physical node. In order to interact, one of the supported REST construct has to be invoked on them. There are utmost three REST constructs supported on these objects: - GET - POST - DELETE Methods ------- Any REST request that does not operate on managed objects is modeled as a method. The following are some of the methods that are currently supported: Login ~~~~~ This method supports a simple password based login. >>> nxsw.methods.Login('admin', 'password').POST() LoginRefresh ~~~~~~~~~~~~ This method refreshes an existing session. >>> nxsw.methods.LoginRefresh().GET() Managed Objects --------------- DME managed objects can be instantiated fromt the Node object using a local Managed Information Tree (MIT). Each invocation of `mit` property on the Node object will result in a different local MIT which can be used as a local cache. For instance, a local topSystem object can be instantiated as follows: >>> mit = nxsw.mit >>> mit.topSystem() Please note that at this point this object is only locally instantiated. At this point, you would have noticed that . notation is used to chain object containment hierarchy. The same . notation is also used for accessing properties of an object. >>> user = nxsw.mit.topSystem().snmpEntity(). ... snmpInst().snmpLocalUser('test') >>> user.ipv4AclName = '4acl' >>> print user.ipv4AclName 4acl >>> print user.Xml When using . notation for a child object, one should specify the class name, followed by a paranthesis that takes naming properties as either arguments, or keyword arguments. One can also specify non naming properties as keyword arguments. >>> top = nxsw.mit.topSystem() >>> user = top.snmpEntity().snmpInst().snmpLocalUser('test') >>> print user.Xml >>> user = top.snmpEntity().snmpInst(). ... snmpLocalUser(userName='test') >>> print user.Xml >>> user = top.snmpEntity().snmpInst(). ... snmpLocalUser('test', ipv4AclName="4acl") >>> print user.Xml POST ~~~~ Local managed objects are posted to underlying node using POST() method on the object. The following example shows posting of a new snmpLocaluser to NX-OS device. >>> nxsw.mit.topSystem().snmpEntity().snmpInst(). ... snmpLocalUser('test').POST() DELETE ~~~~~~ Local managed objects can be deleted from the underlying node using DELETE() method on that object. An snmpLocalUser object can be deleted as shown below: >>> nxsw.mit.topSystem().snmpEntity().snmpInst(). ... snmpLocalUser('test').DELETE() Please note that the local cached managed objects still remain even though it is deleted from NX-OS device. To update the local objects, if needed, GET() method can be used as shown below. GET ~~~ Local managed objects can be fetched from the underlying node using GET() method on that object. GET() takes other option to affect the scope of the query. We'll look at them later. To begin with, an snmpLocalUser can be fetched as follows: >>> bd = nxsw.mit.topSystem().snmpEntity().snmpInst(). ... snmpLocalUser('test') >>> result = bd.GET() >>> type(result) >>> print len(result) 1 >>> print result[0].Dn sys/snmp/inst/lclUser-test Please note that the GET() method returs a list. The monadic nature of list is taken advantage to represent the result of a query that can fetch 0, 1 or more objects. It should also be noted that the local managed object is automatically updated with the fetched values. >>> print bd.Xml GET() method can be combined with various options to result in more powerful queries like fetching objects of a certain class, or subtree, etc. For instance, all users can be queries as follows: >>> from pydme import options >>> result = nxsw.mit.GET(**options.subtreeClass('snmpLocalUser')) >>> for user in result: ... print user.Dn ... sys/snmp/inst/lclUser-admin sys/snmp/inst/lclUser-test The entire subtree of snmpEntity can be queried as follows: >>> result = nxsw.mit.polUni().snmpEntity().GET(**options.subtree) >>> for entity in result: ... print entity.Dn ... sys/snmp/inst/lclUser-admin/group-network-admin sys/snmp/inst/lclUser-admin sys/snmp/inst/lclUser-test sys/snmp/inst/rmon/event-4 sys/snmp/inst/rmon/event-2 sys/snmp/inst/rmon/event-5 sys/snmp/inst/rmon/event-1 sys/snmp/inst/rmon/event-3 sys/snmp/inst/rmon sys/snmp/inst/traps/aaa/serverstatechange sys/snmp/inst/traps/aaa sys/snmp/inst/traps/bfd/sessiondown sys/snmp/inst/traps/bfd/sessionup sys/snmp/inst/traps/bfd sys/snmp/inst/traps/bridge/newroot sys/snmp/inst/traps/bridge/topologychange sys/snmp/inst/traps/bridge sys/snmp/inst/traps/callhome/eventnotify sys/snmp/inst/traps/callhome/smtpsendfail sys/snmp/inst/traps/callhome sys/snmp/inst/traps/cfs/mergefailure sys/snmp/inst/traps/cfs/statechangenotif sys/snmp/inst/traps/cfs sys/snmp/inst/traps/config/ccmCLIRunningConfigChanged sys/snmp/inst/traps/config sys/snmp/inst/traps/entity/entityfanstatuschange sys/snmp/inst/traps/entity/entitymibchange sys/snmp/inst/traps/entity/cefcMIBEnableStatusNotification sys/snmp/inst/traps/entity/entitymoduleinserted sys/snmp/inst/traps/entity/entitymoduleremoved sys/snmp/inst/traps/entity/entitymodulestatuschange sys/snmp/inst/traps/entity/entitypoweroutchange sys/snmp/inst/traps/entity/entitypowerstatuschange sys/snmp/inst/traps/entity/entitysensor sys/snmp/inst/traps/entity/entityunrecognisedmodule sys/snmp/inst/traps/entity sys/snmp/inst/traps/featurecontrol/ciscoFeatOpStatusChange sys/snmp/inst/traps/featurecontrol/FeatureOpStatusChange sys/snmp/inst/traps/featurecontrol sys/snmp/inst/traps/generic/coldStart sys/snmp/inst/traps/generic/warmStart sys/snmp/inst/traps/generic sys/snmp/inst/traps/hsrp/statechange sys/snmp/inst/traps/hsrp sys/snmp/inst/traps/ip/sla sys/snmp/inst/traps/ip sys/snmp/inst/traps/license/notifylicenseexpiry sys/snmp/inst/traps/license/notifylicenseexpirywarning sys/snmp/inst/traps/license/notifylicensefilemissing sys/snmp/inst/traps/license/notifynolicenseforfeature sys/snmp/inst/traps/license sys/snmp/inst/traps/link/cerrdisableinterfaceeventrev1 sys/snmp/inst/traps/link/cieLinkDown sys/snmp/inst/traps/link/cieLinkUp sys/snmp/inst/traps/link/ciscoxcvrmonstatuschg sys/snmp/inst/traps/link/cmnmacmovenotification sys/snmp/inst/traps/link/delayedlinkstatechange sys/snmp/inst/traps/link/extendedlinkDown sys/snmp/inst/traps/link/extendedlinkUp sys/snmp/inst/traps/link/linkDown sys/snmp/inst/traps/link/linkUp sys/snmp/inst/traps/link sys/snmp/inst/traps/lldp/lldpRemTablesChange sys/snmp/inst/traps/lldp sys/snmp/inst/traps/mmode/cseMaintModeChangeNotify sys/snmp/inst/traps/mmode/cseNormalModeChangeNotify sys/snmp/inst/traps/mmode sys/snmp/inst/traps/msdp/msdpBackwardTransition sys/snmp/inst/traps/msdp sys/snmp/inst/traps/pim/pimNeighborLoss sys/snmp/inst/traps/pim sys/snmp/inst/traps/poe/controlenable sys/snmp/inst/traps/poe/policenotify sys/snmp/inst/traps/poe sys/snmp/inst/traps/portsecurity/accesssecuremacviolation sys/snmp/inst/traps/portsecurity/trunksecuremacviolation sys/snmp/inst/traps/portsecurity sys/snmp/inst/traps/rf/redundancyframework sys/snmp/inst/traps/rf sys/snmp/inst/traps/rmon/fallingAlarm sys/snmp/inst/traps/rmon/hcFallingAlarm sys/snmp/inst/traps/rmon/hcRisingAlarm sys/snmp/inst/traps/rmon/risingAlarm sys/snmp/inst/traps/rmon sys/snmp/inst/traps/snmp/authentication sys/snmp/inst/traps/snmp sys/snmp/inst/traps/stormcontrol/cpscEventRev1 sys/snmp/inst/traps/stormcontrol sys/snmp/inst/traps/stpx/inconsistency sys/snmp/inst/traps/stpx/loopinconsistency sys/snmp/inst/traps/stpx/rootinconsistency sys/snmp/inst/traps/stpx sys/snmp/inst/traps/sysmgr/cseFailSwCoreNotifyExtended sys/snmp/inst/traps/sysmgr sys/snmp/inst/traps/system/Clockchangenotification sys/snmp/inst/traps/system sys/snmp/inst/traps/upgrade/UpgradeJobStatusNotify sys/snmp/inst/traps/upgrade/UpgradeOpNotifyOnCompletion sys/snmp/inst/traps/upgrade sys/snmp/inst/traps/vsan/vsanPortMembershipChange sys/snmp/inst/traps/vsan/vsanStatusChange sys/snmp/inst/traps/vsan sys/snmp/inst/traps/vtp/notifs sys/snmp/inst/traps/vtp/vlancreate sys/snmp/inst/traps/vtp/vlandelete sys/snmp/inst/traps/vtp sys/snmp/inst/traps sys/snmp/inst sys/snmp/servershutdown sys/snmp Multiple options can be combined with & operator, and filters can be used as follows: >>> for user in nxsw.mit.topSystem().GET( ... **options.subtreeClass('snmpLocalUser') & ... options.filter(filters.Eq('snmpLocalUser.userName', 'test'))): ... print user.Dn ... sys/snmp/inst/lclUser-test Managed Object Iterators ------------------------ Local MIT provides a construct of object iterators. On a given object, . notation can be used with (immediate) child class name without a following paranthesis to access all children of that class. For instance: >>> mit = nxsw.mit >>> mit.topSystem().snmpEntity().snmpInst().snmpLocalUser('test1') >>> mit.topSystem().snmpEntity().snmpInst().snmpLocalUser('test2') >>> mit.topSystem().snmpEntity().snmpInst().snmpLocalUser('test3') >>> for user in mit.topSystem().snmpEntity().snmpInst().snmpLocalUser: ... print user.Dn ... sys/snmp/inst/lclUser-test1 sys/snmp/inst/lclUser-test2 sys/snmp/inst/lclUser-test3 The use of iterators becomes more obvious when one is walking through a subtree that is fetched from a node. >>> inst = nxsw.mit.topSystem().snmpEntity().snmpInst() >>> inst.GET(**options.subtree) >>> for user in inst.snmpLocalUser: ... print user.userName, user.Dn, user.modTs ... admin sys/snmp/inst/lclUser-admin 2019-12-11T20:21:27.694+00:00 test sys/snmp/inst/lclUser-test 2019-12-11T23:52:18.686+00:00 There is also a way to access all the children of a given object using Children property. >>> inst = nxsw.mit.topSystem().snmpEntity().snmpInst() >>> inst.GET(**options.subtree) >>> for child in inst.Children: ... print child.Dn ... sys/snmp/inst/lclUser-admin sys/snmp/inst/lclUser-test sys/snmp/inst/rmon sys/snmp/inst/traps Event Subscription ------------------------ Listening to events of a particular MO and all its children can be derived from DME managed objects of the node. For instance, to listen to all the physical interface events, when changing mtu and description of an interface: >>> nxsw.startWsListener() >>> _, subscriptionId = nxsw.methods.ResolveClass('l1PhysIf'). ... GET(**options.subscribe & options.subtree) >>> nxsw.waitForWsMo(subscriptionId) >>> if nxsw.hasWsMo(subscriptionId): ... print nxsw.popWsMo(subscriptionId).Xml ... Example code ------------- Complete code examples are provided `here `_ These examples assume that user knows the path from topSystem to the managed object. In case, it is not known, `buildMoTree `_ can be used which can determine the parents of the given managed object which include the name paremeters as well. This utility can also provide the properties of the managed object and its children. - example: python buildMoTree.py ./dme-9.3.5-meta.json rtctrlRttP (where rtctrlRttP is the managed object) .. image:: ./mo_p.png :height: 300 :width: 600 Supported Version ----------------- PyDME is supported on N9K running version 9.3(5) or above. The DME model documentation is `here `_