Beispiel #1
0
def dump_macinfo(macaddr):
    macaddr = macaddr.replace('-', ':')
    info = _macmap.get(macaddr, None)
    if info is None:
        raise exc.NotFoundException('{0} not found in mac table of '
                                    'any known switches'.format(macaddr))
    return _dump_locations(info, macaddr,
                           _nodesbymac.get(macaddr, (None, ))[0])
Beispiel #2
0
def enumerate_nodegroup_collection(collectionpath, configmanager):
    nodegroup = collectionpath[1]
    if not configmanager.is_nodegroup(nodegroup):
        raise exc.NotFoundException(
            'Invalid nodegroup: {0} not found'.format(nodegroup))
    del collectionpath[0:2]
    collection = nested_lookup(nodegroupresources, collectionpath)
    return iterate_resources(collection)
Beispiel #3
0
def _get_mac_from_query(pathcomponents):
    _, queryparms, _, _ = _parameterize_path(pathcomponents[1:])
    if 'by-mac' not in queryparms:
        raise exc.InvalidArgumentException('Must target using "by-mac"')
    mac = queryparms['by-mac'].replace('-', ':')
    if mac not in known_info:
        raise exc.NotFoundException('{0} not found'.format(mac))
    return mac
Beispiel #4
0
def enumerate_node_collection(collectionpath, configmanager):
    if collectionpath == ['nodes']:  # it is just '/node/', need to list nodes
        allnodes = list(configmanager.list_nodes())
        try:
            allnodes.sort(key=noderange.humanify_nodename)
        except TypeError:
            allnodes.sort()
        return iterate_collections(allnodes)
    nodeorrange = collectionpath[1]
    if collectionpath[0] == 'nodes' and not configmanager.is_node(nodeorrange):
        raise exc.NotFoundException("Invalid element requested")
    collection = nested_lookup(noderesources, collectionpath[2:])
    if len(collectionpath) == 2 and collectionpath[0] == 'noderange':
        collection['nodes'] = {}
    if not isinstance(collection, dict):
        raise exc.NotFoundException("Invalid element requested")
    return iterate_resources(collection)
Beispiel #5
0
def nested_lookup(nestdict, key):
    try:
        currloc = nestdict
        for currk in key:
            currloc = seek_element(currloc, currk)
        return currloc
    except TypeError:
        raise exc.NotFoundException("Invalid element requested")
Beispiel #6
0
def nested_lookup(nestdict, key):
    try:
        currloc = nestdict
        for i in range(len(key)):
            currk = key[i]
            currloc = seek_element(currloc, currk, len(key) - i)
        return currloc
    except TypeError:
        raise exc.NotFoundException("Invalid element requested")
Beispiel #7
0
def _handle_neighbor_query(pathcomponents, configmanager):
    choices, parms, listrequested, childcoll = _parameterize_path(
        pathcomponents)
    if not childcoll:  # this means it's a single entry with by-peerid
        # guaranteed
        if (parms['by-peerid'] not in _neighbypeerid and
                _neighbypeerid.get('!!vintage', 0) < util.monotonic_time() - 60):
            list(update_neighbors(configmanager))
        if parms['by-peerid'] not in _neighbypeerid:
            raise exc.NotFoundException('No matching peer known')
        return _dump_neighbordatum(_neighbypeerid[parms['by-peerid']])
    if not listrequested:  # the query is for currently valid choices
        return [msg.ChildCollection(x + '/') for x in sorted(list(choices))]
    if listrequested not in multi_selectors | single_selectors:
        raise exc.NotFoundException('{0} is not found'.format(listrequested))
    if 'by-switch' in parms:
        update_switch_data(parms['by-switch'], configmanager)
    else:
        list(update_neighbors(configmanager))
    return list_info(parms, listrequested)
Beispiel #8
0
def handle_deployment(configmanager, inputdata, pathcomponents, operation):
    if len(pathcomponents) == 1:
        yield msg.ChildCollection('distributions/')
        yield msg.ChildCollection('profiles/')
        yield msg.ChildCollection('importing/')
        return
    if pathcomponents[1] == 'distributions':
        if len(pathcomponents) == 2 and operation == 'retrieve':
            for dist in osimage.list_distros():
                yield msg.ChildCollection(dist + '/')
            return
        if len(pathcomponents) == 3:
            distname = pathcomponents[-1]
            if 'operation' == 'update':
                if inputdata.get('rescan', False):
                    osimage.rescan_dist(distname)
    if pathcomponents[1] == 'profiles':
        if len(pathcomponents) == 2 and operation == 'retrieve':
            for prof in osimage.list_profiles():
                yield msg.ChildCollection(prof + '/')
            return
        if len(pathcomponents) == 3:
            profname = pathcomponents[-1]
            if operation == 'update' and 'updateboot' in inputdata:
                osimage.update_boot(profname)
                yield msg.KeyValueData({'updated': profname})
                return
    if pathcomponents[1] == 'importing':
        if len(pathcomponents) == 2 or not pathcomponents[-1]:
            if operation == 'retrieve':
                for imp in osimage.list_importing():
                    yield imp
                return
            elif operation == 'create':
                importer = osimage.MediaImporter(inputdata['filename'],
                                                 configmanager)
                yield msg.KeyValueData({
                    'target': importer.targpath,
                    'name': importer.importkey
                })
                return
        elif len(pathcomponents) == 3:
            if operation == 'retrieve':
                for res in osimage.get_importing_status(pathcomponents[-1]):
                    yield res
                return
            elif operation == 'delete':
                for res in osimage.remove_importing(pathcomponents[-1]):
                    yield res
                return
    raise exc.NotFoundException('Unrecognized request')
Beispiel #9
0
def remove_updates(nodes, tenant, element):
    if len(element) < 5:
        raise exc.InvalidArgumentException()
    upid = element[-1]
    for node in nodes:
        try:
            upd = updatesbytarget[(node, tenant)][upid]
        except KeyError:
            raise exc.NotFoundException('No active update matches request')
        upd.cancel()
        del updatesbytarget[(node, tenant)][upid]
        yield msg.DeletedResource(
            'nodes/{0}/inventory/firmware/updates/active/{1}'.format(
                node, upid))
Beispiel #10
0
def list_updates(nodes, tenant, element):
    showmode = False
    if len(element) > 4:
        showmode = True
        upid = element[-1]
    for node in nodes:
        if showmode:
            try:
                updater = updatesbytarget[(node, tenant)][upid]
            except KeyError:
                raise exc.NotFoundException('No matching update process found')
            yield msg.KeyValueData(updater.progress, name=node)
        else:
            for updateid in updatesbytarget.get((node, tenant), {}):
                yield msg.ChildCollection(updateid)
Beispiel #11
0
def handle_read_api_request(pathcomponents):
    # TODO(jjohnson2): This should be more generalized...
    #  odd indexes into components are 'by-'*, even indexes
    # starting at 2 are parameters to previous index
    subcats, queryparms, indexof, coll = _parameterize_path(pathcomponents[1:])
    if len(pathcomponents) == 1:
        dirlist = [msg.ChildCollection(x + '/') for x in sorted(list(subcats))]
        dirlist.append(msg.ChildCollection('rescan'))
        return dirlist
    if not coll:
        return show_info(queryparms['by-mac'])
    if not indexof:
        return [msg.ChildCollection(x + '/') for x in sorted(list(subcats))]
    if indexof not in list_info:
        raise exc.NotFoundException('{0} is not found'.format(indexof))
    return list_info[indexof](queryparms)
Beispiel #12
0
def remove_updates(nodes, tenant, element, type='firmware'):
    if len(element) < 5 and element[:2] != ['media', 'uploads']:
        raise exc.InvalidArgumentException()
    upid = element[-1]
    if type == 'firmware':
        myparty = updatesbytarget
    else:
        myparty = uploadsbytarget
    for node in nodes:
        try:
            upd = myparty[(node, tenant)][upid]
        except KeyError:
            raise exc.NotFoundException('No active update matches request')
        upd.cancel()
        del myparty[(node, tenant)][upid]
        yield msg.DeletedResource(
            'nodes/{0}/inventory/firmware/updates/active/{1}'.format(
                node, upid))
Beispiel #13
0
def handle_nodegroup_request(configmanager, inputdata, pathcomponents,
                             operation):
    iscollection = False
    routespec = None
    if len(pathcomponents) < 2:
        if operation == "create":
            inputdata = msg.InputAttributes(pathcomponents, inputdata)
            return create_group(inputdata.attribs, configmanager)
        allgroups = list(configmanager.get_groups())
        try:
            allgroups.sort(key=noderange.humanify_nodename)
        except TypeError:
            allgroups.sort()
        return iterate_collections(allgroups)
    elif len(pathcomponents) == 2:
        iscollection = True
    else:
        try:
            routespec = nested_lookup(nodegroupresources, pathcomponents[2:])
            if isinstance(routespec, dict):
                iscollection = True
            elif isinstance(routespec, PluginCollection):
                iscollection = False  # it is a collection, but plugin defined
        except KeyError:
            raise exc.NotFoundException("Invalid element requested")
    if iscollection:
        if operation == "delete":
            return delete_nodegroup_collection(pathcomponents, configmanager)
        elif operation == "retrieve":
            return enumerate_nodegroup_collection(pathcomponents,
                                                  configmanager)
        else:
            raise Exception("TODO")
    plugroute = routespec.routeinfo
    inputdata = msg.get_input_message(pathcomponents[2:], operation, inputdata)
    if 'handler' in plugroute:  # fixed handler definition
        hfunc = getattr(pluginmap[plugroute['handler']], operation)
        return hfunc(nodes=None,
                     element=pathcomponents,
                     configmanager=configmanager,
                     inputdata=inputdata)
    raise Exception("unknown case encountered")
Beispiel #14
0
def _parameterize_path(pathcomponents):
    listrequested = False
    childcoll = True
    if len(pathcomponents) % 2 == 1:
        listrequested = pathcomponents[-1]
        pathcomponents = pathcomponents[:-1]
    pathit = iter(pathcomponents)
    keyparams = {}
    validselectors = multi_selectors | single_selectors
    for key, val in zip(pathit, pathit):
        if key not in validselectors:
            raise exc.NotFoundException('{0} is not valid here'.format(key))
        keyparams[key] = val
        validselectors.discard(key)
        if key == 'by-switch':
            validselectors.add('by-port')
        if key in single_selectors:
            childcoll = False
            validselectors = set([])
    return validselectors, keyparams, listrequested, childcoll
Beispiel #15
0
 def __init__(self,
              node,
              configmanager,
              username,
              datacallback=None,
              skipreplay=False,
              direct=True,
              width=80,
              height=24):
     self.registered = False
     self.tenant = configmanager.tenant
     if not configmanager.is_node(node):
         raise exc.NotFoundException("Invalid node")
     self.username = username
     self.node = node
     self.configmanager = configmanager
     self.direct = direct  # true if client is directly connected versus
     # relay
     self.width = width
     self.height = height
     self.connect_session()
     self.registered = True
     self._evt = None
     self.node = node
     self.write = self.conshdl.write
     if datacallback is None:
         self.reaper = eventlet.spawn_after(15, self.destroy)
         self.databuffer = collections.deque([])
         self.data_handler = self.got_data
         if not skipreplay:
             self.databuffer.extend(self.conshdl.get_recent())
     else:
         self.data_handler = datacallback
         if not skipreplay:
             for recdata in self.conshdl.get_recent():
                 if recdata:
                     datacallback(recdata)
     self.conshdl.attachsession(self)
Beispiel #16
0
def _parameterize_path(pathcomponents):
    listrequested = False
    childcoll = True
    if len(pathcomponents) % 2 == 1:
        listrequested = pathcomponents[-1]
        pathcomponents = pathcomponents[:-1]
    pathit = iter(pathcomponents)
    keyparams = {}
    validselectors = multi_selectors | node_selectors | single_selectors
    for key, val in zip(pathit, pathit):
        if key not in validselectors:
            raise exc.NotFoundException('{0} is not valid here'.format(key))
        if key == 'by-type':
            keyparams[key] = servicebyname.get(val, '!!!!invalid-type')
        else:
            keyparams[key] = val
        validselectors.discard(key)
        if key in single_selectors:
            childcoll = False
            validselectors = set([])
        elif key in node_selectors:
            validselectors = single_selectors | set([])
    return validselectors, keyparams, listrequested, childcoll
Beispiel #17
0
def handle_api_request(configmanager, inputdata, operation, pathcomponents):
    if operation == 'retrieve':
        return handle_read_api_request(pathcomponents)
    elif (operation in ('update', 'create')
          and pathcomponents == ['discovery', 'rescan']):
        if inputdata != {'rescan': 'start'}:
            raise exc.InvalidArgumentException()
        rescan()
        return (msg.KeyValueData({'rescan': 'started'}), )
    elif (operation in ('update', 'create')):
        if 'node' not in inputdata:
            raise exc.InvalidArgumentException('Missing node name in input')
        _, queryparms, _, _ = _parameterize_path(pathcomponents[1:])
        if 'by-mac' not in queryparms:
            raise exc.InvalidArgumentException('Must target using "by-mac"')
        mac = queryparms['by-mac'].replace('-', ':')
        if mac not in known_info:
            raise exc.NotFoundException('{0} not found'.format(mac))
        info = known_info[mac]
        handler = info['handler'].NodeHandler(info, configmanager)
        eval_node(configmanager, handler, info, inputdata['node'], manual=True)
        return [msg.AssignedResource(inputdata['node'])]
    raise exc.NotImplementedException('Unable to {0} to {1}'.format(
        operation, '/'.join(pathcomponents)))
Beispiel #18
0
def handle_read_api_request(pathcomponents):
    # TODO(jjohnson2): discovery core.py api handler design, apply it here
    # to make this a less tangled mess as it gets extended
    if len(pathcomponents) == 1:
        return [msg.ChildCollection('macs/')]
    elif len(pathcomponents) == 2:
        return [
            msg.ChildCollection(x) for x in (  # 'by-node/',
                'by-mac/', 'by-switch/', 'rescan')
        ]
    if False and pathcomponents[2] == 'by-node':
        # TODO: should be list of node names, and then under that 'by-mac'
        if len(pathcomponents) == 3:
            return [
                msg.ChildCollection(x.replace(':', '-'))
                for x in sorted(list(_nodesbymac))
            ]
        elif len(pathcomponents) == 4:
            macaddr = pathcomponents[-1].replace('-', ':')
            return dump_macinfo(macaddr)
    elif pathcomponents[2] == 'by-mac':
        if len(pathcomponents) == 3:
            return [
                msg.ChildCollection(x.replace(':', '-'))
                for x in sorted(list(_macmap))
            ]
        elif len(pathcomponents) == 4:
            return dump_macinfo(pathcomponents[-1])
    elif pathcomponents[2] == 'by-switch':
        if len(pathcomponents) == 3:
            return [
                msg.ChildCollection(x + '/')
                for x in sorted(list(_macsbyswitch))
            ]

        if len(pathcomponents) == 4:
            return [msg.ChildCollection('by-port/')]
        if len(pathcomponents) == 5:
            switchname = pathcomponents[-2]
            if switchname not in _macsbyswitch:
                raise exc.NotFoundException(
                    'No known macs for switch {0}'.format(switchname))
            return [
                msg.ChildCollection(x.replace('/', '-') + '/')
                for x in sorted(list(_macsbyswitch[switchname]))
            ]
        if len(pathcomponents) == 6:
            return [msg.ChildCollection('by-mac/')]
        if len(pathcomponents) == 7:
            switchname = pathcomponents[-4]
            portname = pathcomponents[-2]
            try:
                if portname not in _macsbyswitch[switchname]:
                    portname = portname.replace('-', '/')
                maclist = _macsbyswitch[switchname][portname]
            except KeyError:
                raise exc.NotFoundException('No known macs for switch {0} '
                                            'port {1}'.format(
                                                switchname, portname))
            return [
                msg.ChildCollection(x.replace(':', '-'))
                for x in sorted(maclist)
            ]
        if len(pathcomponents) == 8:
            return dump_macinfo(pathcomponents[-1])
    raise exc.NotFoundException('Unrecognized path {0}'.format(
        '/'.join(pathcomponents)))
Beispiel #19
0
def retrieve_nodegroup(nodegroup, element, configmanager, inputdata):
    try:
        grpcfg = configmanager.get_nodegroup_attributes(nodegroup)
    except KeyError:
        if not configmanager.is_nodegroup(nodegroup):
            raise exc.NotFoundException(
                'Invalid nodegroup: {0} not found'.format(nodegroup))
        raise
    if element == 'all':
        theattrs = set(allattributes.node).union(set(grpcfg))
        theattrs.add('nodes')
        for attribute in sorted(theattrs):
            if attribute == 'groups':
                continue
            if attribute == 'nodes':
                yield msg.ListAttributes(
                    kv={'nodes': list(grpcfg.get('nodes', []))},
                    desc="The nodes belonging to this group")
                continue
            if attribute in grpcfg:
                val = grpcfg[attribute]
            else:
                val = {'value': None}
            if attribute.startswith('secret.'):
                yield msg.CryptedAttributes(
                    kv={attribute: val},
                    desc=allattributes.node[attribute]['description'])
            elif isinstance(val, list):
                yield msg.ListAttributes(kv={attribute: val},
                                         desc=allattributes.node.get(
                                             attribute,
                                             {}).get('description', ''))
            else:
                yield msg.Attributes(kv={attribute: val},
                                     desc=allattributes.node.get(
                                         attribute, {}).get('description', ''))
    if element == 'current':
        for attribute in sorted(list(grpcfg)):
            currattr = grpcfg[attribute]
            if attribute == 'nodes':
                desc = 'The nodes belonging to this group'
            elif attribute == 'noderange':
                desc = 'A dynamic noderange that this group refers to in noderange expansion'
            else:
                try:
                    desc = allattributes.node[attribute]['description']
                except KeyError:
                    desc = ''
            if 'value' in currattr or 'expression' in currattr:
                yield msg.Attributes(kv={attribute: currattr}, desc=desc)
            elif 'cryptvalue' in currattr:
                yield msg.CryptedAttributes(kv={attribute: currattr},
                                            desc=desc)
            elif isinstance(currattr, set):
                yield msg.ListAttributes(kv={attribute: list(currattr)},
                                         desc=desc)
            elif isinstance(currattr, list):
                yield msg.ListAttributes(kv={attribute: currattr}, desc=desc)
            else:
                print attribute
                print repr(currattr)
                raise Exception("BUGGY ATTRIBUTE FOR NODEGROUP")
Beispiel #20
0
def handle_node_request(configmanager,
                        inputdata,
                        operation,
                        pathcomponents,
                        autostrip=True):
    if log.logfull:
        raise exc.TargetResourceUnavailable(
            'Filesystem full, free up space and restart confluent service')
    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
    msginputdata = 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=msginputdata)
        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)
                    continue
            if plugpath:
                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]
        for bn in badcollnodes:
            nodesbyhandler[BadCollective(bn).error] = [bn]
        workers = greenpool.GreenPool()
        numworkers = 0
        for hfunc in nodesbyhandler:
            numworkers += 1
            workers.spawn(
                addtoqueue, passvalues, hfunc, {
                    'nodes': nodesbyhandler[hfunc],
                    'element': pathcomponents,
                    'configmanager': configmanager,
                    'inputdata': msginputdata
                })
        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,
                    'isnoderange': isnoderange
                })
        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()
Beispiel #21
0
 def strip_node(self, node):
     raise exc.NotFoundException(self.error)
Beispiel #22
0
def show_info(mac):
    mac = mac.replace('-', ':')
    if mac not in known_info:
        raise exc.NotFoundException(mac + ' not a known mac address')
    for i in send_discovery_datum(known_info[mac]):
        yield i
Beispiel #23
0
def handle_path(path,
                operation,
                configmanager,
                inputdata=None,
                autostrip=True):
    """Given a full path request, return an object.

    The plugins should generally return some sort of iterator.
    An exception is made for console/session, which should return
    a class with connect(), read(), write(bytes), and close()
    """
    pathcomponents = path.split('/')
    del pathcomponents[0]  # discard the value from leading /
    if pathcomponents[-1] == '':
        del pathcomponents[-1]
    if not pathcomponents:  # root collection list
        return enumerate_collections(rootcollections)
    elif pathcomponents[0] == 'noderange':
        return handle_node_request(configmanager, inputdata, operation,
                                   pathcomponents, autostrip)
    elif pathcomponents[0] == 'deployment':
        return handle_deployment(configmanager, inputdata, pathcomponents,
                                 operation)
    elif pathcomponents[0] == 'nodegroups':
        return handle_nodegroup_request(configmanager, inputdata,
                                        pathcomponents, operation)
    elif pathcomponents[0] == 'nodes':
        # single node request of some sort
        return handle_node_request(configmanager, inputdata, operation,
                                   pathcomponents, autostrip)
    elif pathcomponents[0] == 'discovery':
        return disco.handle_api_request(configmanager, inputdata, operation,
                                        pathcomponents)
    elif pathcomponents[0] == 'networking':
        return macmap.handle_api_request(configmanager, inputdata, operation,
                                         pathcomponents)
    elif pathcomponents[0] == 'version':
        return (msg.Attributes(kv={'version': confluent.__version__}), )
    elif pathcomponents[0] == 'usergroups':
        # TODO: when non-administrator accounts exist,
        # they must only be allowed to see their own user
        try:
            usergroup = pathcomponents[1]
        except IndexError:  # it's just users/
            if operation == 'create':
                inputdata = msg.get_input_message(pathcomponents,
                                                  operation,
                                                  inputdata,
                                                  configmanager=configmanager)
                create_usergroup(inputdata.attribs, configmanager)
            return iterate_collections(configmanager.list_usergroups(),
                                       forcecollection=False)
        if usergroup not in configmanager.list_usergroups():
            raise exc.NotFoundException("Invalid usergroup %s" % usergroup)
        if operation == 'retrieve':
            return show_usergroup(usergroup, configmanager)
        elif operation == 'delete':
            return delete_usergroup(usergroup, configmanager)
        elif operation == 'update':
            inputdata = msg.get_input_message(pathcomponents,
                                              operation,
                                              inputdata,
                                              configmanager=configmanager)
            update_usergroup(usergroup, inputdata.attribs, configmanager)
            return show_usergroup(usergroup, configmanager)
    elif pathcomponents[0] == 'users':
        # TODO: when non-administrator accounts exist,
        # they must only be allowed to see their own user
        try:
            user = pathcomponents[1]
        except IndexError:  # it's just users/
            if operation == 'create':
                inputdata = msg.get_input_message(pathcomponents,
                                                  operation,
                                                  inputdata,
                                                  configmanager=configmanager)
                create_user(inputdata.attribs, configmanager)
            return iterate_collections(configmanager.list_users(),
                                       forcecollection=False)
        if user not in configmanager.list_users():
            raise exc.NotFoundException("Invalid user %s" % user)
        if operation == 'retrieve':
            return show_user(user, configmanager)
        elif operation == 'delete':
            return delete_user(user, configmanager)
        elif operation == 'update':
            inputdata = msg.get_input_message(pathcomponents,
                                              operation,
                                              inputdata,
                                              configmanager=configmanager)
            update_user(user, inputdata.attribs, configmanager)
            return show_user(user, configmanager)
    elif pathcomponents[0] == 'events':
        try:
            element = pathcomponents[1]
        except IndexError:
            if operation != 'retrieve':
                raise exc.InvalidArgumentException('Target is read-only')
            return (msg.ChildCollection('decode'), )
        if element != 'decode':
            raise exc.NotFoundException()
        if operation == 'update':
            return alerts.decode_alert(inputdata, configmanager)
    elif pathcomponents[0] == 'discovery':
        return handle_discovery(pathcomponents[1:], operation, configmanager,
                                inputdata)
    else:
        raise exc.NotFoundException()
Beispiel #24
0
def handle_read_api_request(pathcomponents, configmanager):
    # TODO(jjohnson2): discovery core.py api handler design, apply it here
    # to make this a less tangled mess as it gets extended
    if len(pathcomponents) == 1:
        return [
            msg.ChildCollection('macs/'),
            msg.ChildCollection('neighbors/')
        ]
    elif pathcomponents[1] == 'neighbors':
        if len(pathcomponents) == 3 and pathcomponents[-1] == 'by-switch':
            return [
                msg.ChildCollection(x + '/')
                for x in list_switches(configmanager)
            ]
        else:
            return _handle_neighbor_query(pathcomponents[2:], configmanager)
    elif len(pathcomponents) == 2:
        if pathcomponents[-1] == 'macs':
            return [
                msg.ChildCollection(x) for x in (  # 'by-node/',
                    'by-mac/', 'by-switch/', 'rescan')
            ]
        elif pathcomponents[-1] == 'neighbors':
            return [msg.ChildCollection('by-switch/')]
        else:
            raise exc.NotFoundException(
                'Unknown networking resource {0}'.format(pathcomponents[-1]))
    if False and pathcomponents[2] == 'by-node':
        # TODO: should be list of node names, and then under that 'by-mac'
        if len(pathcomponents) == 3:
            return [
                msg.ChildCollection(x.replace(':', '-'))
                for x in util.natural_sort(list(_nodesbymac))
            ]
        elif len(pathcomponents) == 4:
            macaddr = pathcomponents[-1].replace('-', ':')
            return dump_macinfo(macaddr)
    elif pathcomponents[2] == 'by-mac':
        if len(pathcomponents) == 3:
            return [
                msg.ChildCollection(x.replace(':', '-'))
                for x in sorted(list(_apimacmap))
            ]
        elif len(pathcomponents) == 4:
            return dump_macinfo(pathcomponents[-1])
    elif pathcomponents[2] == 'by-switch':
        if len(pathcomponents) == 3:
            return [
                msg.ChildCollection(x + '/')
                for x in list_switches(configmanager)
            ]
        if len(pathcomponents) == 4:
            return [msg.ChildCollection('by-port/')]
        if len(pathcomponents) == 5:
            switchname = pathcomponents[-2]
            if switchname not in _macsbyswitch:
                raise exc.NotFoundException(
                    'No known macs for switch {0}'.format(switchname))
            return [
                msg.ChildCollection(x.replace('/', '-') + '/')
                for x in util.natural_sort(list(_macsbyswitch[switchname]))
            ]
        if len(pathcomponents) == 6:
            return [msg.ChildCollection('by-mac/')]
        if len(pathcomponents) == 7:
            switchname = pathcomponents[-4]
            portname = pathcomponents[-2]
            try:
                if portname not in _macsbyswitch[switchname]:
                    portname = portname.replace('-', '/')
                maclist = _macsbyswitch[switchname][portname]
            except KeyError:
                foundsomemacs = False
                if switchname in _macsbyswitch:
                    try:
                        matcher = re.compile(portname)
                    except Exception:
                        raise exc.InvalidArgumentException(
                            'Invalid regular expression specified')
                    maclist = []
                    for actualport in _macsbyswitch[switchname]:
                        if bool(matcher.match(actualport)):
                            foundsomemacs = True
                            maclist = maclist + _macsbyswitch[switchname][
                                actualport]
                if not foundsomemacs:
                    raise exc.NotFoundException('No known macs for switch {0} '
                                                'port {1}'.format(
                                                    switchname, portname))
            return [
                msg.ChildCollection(x.replace(':', '-'))
                for x in sorted(maclist)
            ]
        if len(pathcomponents) == 8:
            return dump_macinfo(pathcomponents[-1])
    elif pathcomponents[2] == 'rescan':
        return [msg.KeyValueData({'scanning': mapupdating.locked()})]
    raise exc.NotFoundException('Unrecognized path {0}'.format(
        '/'.join(pathcomponents)))
Beispiel #25
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 = []
    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'])
        plugpath = None
        if 'default' in plugroute:
            plugpath = plugroute['default']
        nodesbyhandler = {}
        for node in nodes:
            for attrname in plugroute['pluginattrs']:
                if attrname in nodeattr[node]:
                    plugpath = nodeattr[node][attrname]['value']
            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]
        for hfunc in nodesbyhandler:
            passvalues.append(
                hfunc(nodes=nodesbyhandler[hfunc],
                      element=pathcomponents,
                      configmanager=configmanager,
                      inputdata=inputdata))
        if isnoderange or not autostrip:
            return itertools.chain(*passvalues)
        else:
            if len(passvalues) > 0:
                if isinstance(passvalues[0], console.Console):
                    return passvalues[0]
                else:
                    return stripnode(passvalues[0], nodes[0])
            else:
                raise exc.NotImplementedException()
Beispiel #26
0
def nested_lookup(nestdict, key):
    try:
        return reduce(seek_element, key, nestdict)
    except TypeError:
        raise exc.NotFoundException("Invalid element requested")