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] == '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] == '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) 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) 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) else: raise exc.NotFoundException()
def handle_dispatch(connection, cert, dispatch, peername): cert = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert) if not util.cert_matches( cfm.get_collective_member(peername)['fingerprint'], cert): connection.close() return if dispatch[0:2] != b'\x01\x03': # magic value to indicate msgpack # We only support msgpack now # The magic should preclude any pickle, as the first byte can never be # under 0x20 or so. connection.close() return dispatch = msgpack.unpackb(dispatch[2:], raw=False) configmanager = cfm.ConfigManager(dispatch['tenant']) nodes = dispatch['nodes'] inputdata = dispatch['inputdata'] operation = dispatch['operation'] pathcomponents = dispatch['path'] routespec = nested_lookup(noderesources, pathcomponents) inputdata = msg.get_input_message(pathcomponents, operation, inputdata, nodes, dispatch['isnoderange'], configmanager) plugroute = routespec.routeinfo plugpath = None nodesbyhandler = {} passvalues = [] nodeattr = configmanager.get_node_attributes(nodes, plugroute['pluginattrs']) 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: 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] try: for hfunc in nodesbyhandler: passvalues.append( hfunc(nodes=nodesbyhandler[hfunc], element=pathcomponents, configmanager=configmanager, inputdata=inputdata)) for res in itertools.chain(*passvalues): _forward_rsp(connection, res) except Exception as res: _forward_rsp(connection, res) connection.sendall('\x00\x00\x00\x00\x00\x00\x00\x00')
def handle_nodegroup_request(configmanager, inputdata, pathcomponents, operation): iscollection = False routespec = None if len(pathcomponents) < 2: if operation == "create": inputdata = msg.InputAttributes(pathcomponents, inputdata) 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")
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")
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:] 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: 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 or operation == "delete": raise exc.InvalidArgumentException() if operation == "create": inputdata = msg.InputAttributes(pathcomponents, inputdata) 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) 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) 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: hfunc = getattr(pluginmap[plugpath], operation) 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()
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()
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()
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()