Ejemplo n.º 1
0
    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')
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
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()