def walk(self, oid): """Walk over children of a given OID This is roughly equivalent to snmpwalk. It will automatically try to be a snmpbulkwalk if possible. :param oid: The SNMP object identifier """ # SNMP is a complicated mess of things. Will endeavor to shield caller # from as much as possible, assuming reasonable defaults when possible. # there may come a time where we add more parameters to override the # automatic behavior (e.g. DES is weak, so it's likely to be # overriden, but some devices only support DES) tp = _get_transport(self.server) ctx = snmp.ContextData(self.context) resolvemib = False if '::' in oid: resolvemib = True mib, field = oid.split('::') obj = snmp.ObjectType(snmp.ObjectIdentity(mib, field)) else: obj = snmp.ObjectType(snmp.ObjectIdentity(oid)) walking = snmp.bulkCmd(self.eng, self.authdata, tp, ctx, 0, 10, obj, lexicographicMode=False, lookupMib=resolvemib) try: for rsp in walking: errstr, errnum, erridx, answers = rsp if errstr: errstr = str(errstr) finerr = errstr + ' while trying to connect to ' \ '{0}'.format(self.server) if errstr in ('Unknown USM user', 'unknownUserName', 'wrongDigest', 'Wrong SNMP PDU digest'): raise exc.TargetEndpointBadCredentials(finerr) # need to do bad credential versus timeout raise exc.TargetEndpointUnreachable(finerr) elif errnum: raise exc.ConfluentException(errnum.prettyPrint() + ' while trying to connect to ' '{0}'.format(self.server)) for ans in answers: if not obj[0].isPrefixOf(ans[0]): # PySNMP returns leftovers in a bulk command # filter out such leftovers break yield ans except snmperr.WrongValueError: raise exc.TargetEndpointBadCredentials('Invalid SNMPv3 password')
def walk(self, oid): """Walk over children of a given OID This is roughly equivalent to snmpwalk. It will automatically try to be a snmpbulkwalk if possible. :param oid: The SNMP object identifier """ # SNMP is a complicated mess of things. Will endeavor to shield caller # from as much as possible, assuming reasonable defaults when possible. # there may come a time where we add more parameters to override the # automatic behavior (e.g. DES is weak, so it's likely to be # overriden, but some devices only support DES) tp = _get_transport(self.server) ctx = snmp.ContextData(self.context) if '::' in oid: mib, field = oid.split('::') obj = snmp.ObjectType(snmp.ObjectIdentity(mib, field)) else: obj = snmp.ObjectType(snmp.ObjectIdentity(oid)) walking = snmp.bulkCmd(self.eng, self.authdata, tp, ctx, 0, 10, obj, lexicographicMode=False) for rsp in walking: errstr, errnum, erridx, answers = rsp if errstr: raise exc.TargetEndpointUnreachable(str(errstr)) elif errnum: raise exc.ConfluentException(errnum.prettyPrint()) for ans in answers: yield ans
def handle_node_request(configmanager, inputdata, operation, pathcomponents, autostrip=True): iscollection = False routespec = None if pathcomponents[0] == 'noderange': if len(pathcomponents) > 3 and pathcomponents[2] == 'nodes': # transform into a normal looking node request # this does mean we don't see if it is a valid # child, but that's not a goal for the noderange # facility anyway isnoderange = False pathcomponents = pathcomponents[2:] elif len(pathcomponents) == 3 and pathcomponents[2] == 'abbreviate': return abbreviate_noderange(configmanager, inputdata, operation) else: isnoderange = True else: isnoderange = False try: nodeorrange = pathcomponents[1] if not isnoderange and not configmanager.is_node(nodeorrange): raise exc.NotFoundException("Invalid Node") if isnoderange and not (len(pathcomponents) == 3 and pathcomponents[2] == 'abbreviate'): try: nodes = noderange.NodeRange(nodeorrange, configmanager).nodes except Exception as e: raise exc.NotFoundException("Invalid Noderange: " + str(e)) else: nodes = (nodeorrange, ) except IndexError: # doesn't actually have a long enough path # this is enumerating a list of nodes or just empty noderange if isnoderange and operation == "retrieve": return iterate_collections([]) elif isnoderange and operation == "create": inputdata = msg.InputAttributes(pathcomponents, inputdata) return create_noderange(inputdata.attribs, configmanager) elif isnoderange or operation == "delete": raise exc.InvalidArgumentException() if operation == "create": inputdata = msg.InputAttributes(pathcomponents, inputdata) return create_node(inputdata.attribs, configmanager) allnodes = list(configmanager.list_nodes()) try: allnodes.sort(key=noderange.humanify_nodename) except TypeError: allnodes.sort() return iterate_collections(allnodes) if (isnoderange and len(pathcomponents) == 3 and pathcomponents[2] == 'nodes'): # this means that it's a list of relevant nodes nodes = list(nodes) try: nodes.sort(key=noderange.humanify_nodename) except TypeError: nodes.sort() return iterate_collections(nodes) if len(pathcomponents) == 2: iscollection = True else: try: routespec = nested_lookup(noderesources, pathcomponents[2:]) except KeyError: raise exc.NotFoundException("Invalid element requested") if isinstance(routespec, dict): iscollection = True elif isinstance(routespec, PluginCollection): iscollection = False # it is a collection, but plugin defined elif routespec is None: raise exc.InvalidArgumentException( 'Custom interface required for resource') if iscollection: if operation == "delete": return delete_node_collection(pathcomponents, configmanager, isnoderange) elif operation == "retrieve": return enumerate_node_collection(pathcomponents, configmanager) else: raise Exception("TODO here") del pathcomponents[0:2] passvalues = queue.Queue() plugroute = routespec.routeinfo inputdata = msg.get_input_message(pathcomponents, operation, inputdata, nodes, isnoderange, configmanager) if 'handler' in plugroute: # fixed handler definition, easy enough if isinstance(plugroute['handler'], str): hfunc = getattr(pluginmap[plugroute['handler']], operation) else: hfunc = getattr(plugroute['handler'], operation) passvalue = hfunc(nodes=nodes, element=pathcomponents, configmanager=configmanager, inputdata=inputdata) if isnoderange: return passvalue elif isinstance(passvalue, console.Console): return [passvalue] else: return stripnode(passvalue, nodes[0]) elif 'pluginattrs' in plugroute: nodeattr = configmanager.get_node_attributes( nodes, plugroute['pluginattrs'] + ['collective.manager']) plugpath = None nodesbymanager = {} nodesbyhandler = {} badcollnodes = [] for node in nodes: for attrname in plugroute['pluginattrs']: if attrname in nodeattr[node]: plugpath = nodeattr[node][attrname]['value'] elif 'default' in plugroute: plugpath = plugroute['default'] if plugpath in dispatch_plugins: cfm.check_quorum() manager = nodeattr[node].get('collective.manager', {}).get('value', None) if manager: if collective.get_myname() != manager: if manager not in nodesbymanager: nodesbymanager[manager] = set([node]) else: nodesbymanager[manager].add(node) continue elif list(cfm.list_collective()): badcollnodes.append(node) if plugpath is not None: try: hfunc = getattr(pluginmap[plugpath], operation) except KeyError: nodesbyhandler[BadPlugin(node, plugpath).error] = [node] continue if hfunc in nodesbyhandler: nodesbyhandler[hfunc].append(node) else: nodesbyhandler[hfunc] = [node] if badcollnodes: raise exc.ConfluentException( 'collective management active, ' 'collective.manager must be set for {0}'.format( ','.join(badcollnodes))) workers = greenpool.GreenPool() numworkers = 0 for hfunc in nodesbyhandler: numworkers += 1 workers.spawn( addtoqueue, passvalues, hfunc, { 'nodes': nodesbyhandler[hfunc], 'element': pathcomponents, 'configmanager': configmanager, 'inputdata': inputdata }) for manager in nodesbymanager: numworkers += 1 workers.spawn( addtoqueue, passvalues, dispatch_request, { 'nodes': nodesbymanager[manager], 'manager': manager, 'element': pathcomponents, 'configmanager': configmanager, 'inputdata': inputdata, 'operation': operation }) if isnoderange or not autostrip: return iterate_queue(numworkers, passvalues) else: if numworkers > 0: return iterate_queue(numworkers, passvalues, nodes[0]) else: raise exc.NotImplementedException()