예제 #1
0
    def delete_node(cls, team_id, label, node, detach=False):
        team = TeamController._get({"Team": {"id": team_id}})
        neo = Neo4jClient()
        query = 'MATCH(n:{topic}_{label}{{name: "{name}"}})'.format(
            topic=team.kafka_topic, label=label, name=node)

        # First we check if the node has dependencies
        has_deps = query + "-[r:DEPENDS_ON]->() RETURN count(r)"
        count = neo.query(has_deps,
                          returns=(int, ))[0][0]  # return is weird : [[100]]

        if count and not detach:
            msg = (
                "Can not delete node {node} because it still has {count} relationships"
            )
            raise RequirementsNotSatisfiedError(
                msg.format(node=node, count=count))

        # We can delete the node and its relationships
        query += " DETACH DELETE n"

        try:
            # Neo4j returns nothing when deleting a node
            neo.query(query)
        except TransactionException as e:
            raise RequirementsNotSatisfiedError(str(e))

        return {}
예제 #2
0
    def get_label_nodes(cls,
                        team_id,
                        label,
                        name=None,
                        limit=None,
                        random=False):
        team = TeamController._get({"Team": {"id": team_id}})

        neo = Neo4jClient()
        query = "MATCH (n:{}_{}) WITH n".format(team.kafka_topic, label)

        if random:
            query += ", rand() as r ORDER BY r"

        if name:
            query += " WHERE n.name CONTAINS '{0}'".format(name)

        query += " RETURN distinct(n.name)"

        try:
            limit = int(limit)
            query += " LIMIT {0}".format(limit)
        except (TypeError, ValueError):
            pass

        results = neo.query(query, returns=(str, ))
        return [r[0] for r in results]
예제 #3
0
    def count_node_dependencies(cls, team_id, label, node):
        team = TeamController._get({"Team": {"id": team_id}})

        neo = Neo4jClient()
        query = ("MATCH(n:{0}_{1}{{name: '{2}'}}) "
                 "OPTIONAL MATCH (n)-[:DEPENDS_ON]->(m) "
                 "RETURN count(m)").format(team.kafka_topic, label, node)
        sequence = neo.query(query, data_contents=DATA_GRAPH)

        return {"count": sequence[0][0]}
예제 #4
0
    def get_labels(cls, team_id):
        """
        This function returns the list of labels for a team. The labels can be
        found in 2 places : in the configuration or directly in Neo4j.

        Having a label in Neo4j does not mean it's present in the config, and
        having a label in the config does not mean it has been created in Neo4j.
        """
        team = TeamController._get({"Team": {"id": team_id}})

        # Get labels per team
        neo = Neo4jClient()
        query = (
            "CALL db.labels() YIELD label "
            "WITH split(label, '_')[0] AS Team, split(label, '_')[1] AS Label "
            "RETURN Team, collect(Label) AS Labels "
            "ORDER BY Team")
        results = neo.query(query, returns=(str, list))

        # Get the label for the current team
        labels_per_teams = {r[0]: r[1] for r in results}

        # Pick the wanted team's labels
        team_labels = labels_per_teams.get(team.kafka_topic, [])

        # Get the number of nodes per label
        labels = {}
        if team_labels:
            query = cls._build_query_count_nodes(team.kafka_topic, team_labels)
            results = neo.query(query, returns=(str, int))

            # Merge the Neo4j and DB labels
            labels = {
                r[0]: {
                    "name": r[0],
                    "nodes_count": r[1],
                    "qos_query": None
                }
                for r in results
            }

        # No config: return the list of labels
        try:
            config = ConfigController.get_current_config(team_id)
        except NotFoundError:
            return list(labels.values())

        # Add the QoS query for each label
        qos_queries = {l: d["qos"] for l, d in config["data"].items()}
        for label, query in qos_queries.items():
            if label not in labels:
                labels[label] = {"name": label, "nodes_count": 0}
            labels[label]["qos_query"] = query

        return list(labels.values())
예제 #5
0
    def get_label_nodes(cls,
                        team_id,
                        label,
                        name=None,
                        limit=None,
                        random=False):
        team = TeamController._get({"Team": {"id": team_id}})

        neo = Neo4jClient()
        query = cls._build_query_nodes(team.kafka_topic, label, random, name,
                                       limit)

        results = neo.query(query, returns=(str, ))
        return [r[0] for r in results]
예제 #6
0
    def get_label_node(cls, team_id, label, node):
        team = TeamController._get({"Team": {"id": team_id}})

        neo = Neo4jClient()
        query = "MATCH(n:{0}_{1}{{name: '{2}'}}) RETURN n".format(
            team.kafka_topic, label, node)
        result = neo.query(query)

        try:
            data = list(result)[0][0]["data"]
        except IndexError:
            raise NotFoundError("Node {} does not exist".format(node))

        return data
예제 #7
0
    def get_labels(cls, team_id):
        """
        This function returns the list of labels for a team. The labels can be
        found in 2 places : in the configuration or directly in Neo4j.

        Having a label in Neo4j does not mean it's present in the config, and
        having a label in the config does not mean it has been created in Neo4j.
        """
        team = TeamController._get({"Team": {"id": team_id}})

        # Get labels per team
        neo = Neo4jClient()
        query = """CALL db.labels() YIELD label
        WITH split(label, '_')[0] AS Team, split(label, '_')[1] AS Label
        RETURN Team, collect(Label) AS Labels
        ORDER BY Team"""
        results = neo.query(query, returns=(str, list))

        # Get the label for the current team
        labels_per_teams = {r[0]: r[1] for r in results}

        # Pick the wanted team's labels
        team_labels = labels_per_teams.get(team.kafka_topic, [])

        # Construct the cypher to get the number of nodes per label
        # TODO : add cache for this feature
        labels = {}
        if team_labels:
            query = ("MATCH (n:{team}_{label}) "
                     'WITH "{label}" AS Label, count(n) AS Count '
                     "RETURN Label, Count")
            query = query.format(team=team.kafka_topic, label=team_labels[0])

            for label in team_labels[1:]:
                union = ("\nUNION MATCH (n:{team}_{label}) "
                         'WITH "{label}" AS Label, count(n) AS Count '
                         "RETURN Label, Count")
                query += union.format(team=team.kafka_topic, label=label)

            results = neo.query(query, returns=(str, int))

            # Merge the Neo4j and DB labels
            labels = {
                r[0]: {
                    "name": r[0],
                    "nodes_count": r[1],
                    "qos_query": None
                }
                for r in results
            }
        try:
            config = ConfigController.get_current_config(team_id)
        except NotFoundError:
            return list(labels.values())

        qos_queries = {l: d["qos"] for l, d in config["data"].items()}

        for label, query in qos_queries.items():
            if label not in labels:
                labels[label] = {"name": label, "nodes_count": 0}
            labels[label]["qos_query"] = query

        return list(labels.values())
예제 #8
0
    def get_node_dependencies(cls,
                              team_id,
                              label,
                              node,
                              filter_on_config=False):
        team = TeamController._get({"Team": {"id": team_id}})
        query = """
        MATCH(n:{topic}_{label}{{name: "{name}"}})
        OPTIONAL MATCH (n)-[r]->(m) {where}
        RETURN n,r,m
        ORDER BY m.name LIMIT 10
        """

        # Filter the dependencies with the labels declared in the configuration
        where = ""
        if filter_on_config:
            label_config = ConfigController.get_label_config(team_id, label)
            regex = r"^.*(\[[A-Za-z]+(, [A-Za-z]+)*?\])$"
            match = re.search(regex, label_config["qos"])
            if match:
                deps = match.group(1)[1:-1].split(", ")
                where += "WHERE '{}_{}' IN LABELS(m)".format(
                    team.kafka_topic, deps[0])
                for dep in deps[1:]:
                    where += " OR '{}_{}' IN LABELS(m)".format(
                        team.kafka_topic, dep)

        neo = Neo4jClient()
        query = query.format(topic=team.kafka_topic,
                             label=label,
                             name=node,
                             where=where)
        sequence = neo.query(query, data_contents=DATA_GRAPH)

        dependencies = {
            "dependencies": {},
            "graph": {
                "nodes": [],
                "relationships": []
            }
        }

        if sequence.graph:
            for g in sequence.graph:

                # Handle the nodes
                for node in g["nodes"]:
                    title = node["labels"][0][len(team.kafka_topic) + 1:]
                    if title not in dependencies["dependencies"]:
                        dependencies["dependencies"][title] = []

                    # Id is required to make data unique later
                    node["properties"]["id"] = node["id"]
                    dependencies["dependencies"][title].append(
                        node["properties"])

                    # Add the node data in the whole graph
                    dependencies["graph"]["nodes"].append({
                        "id":
                        node["id"],
                        "label":
                        node["properties"].get("name", "unknown"),
                        "title":
                        title,
                    })

                # Handle the relationships
                for rel in g["relationships"]:
                    dependencies["graph"]["relationships"].append({
                        "id":
                        rel["id"],
                        "from":
                        rel["startNode"],
                        "to":
                        rel["endNode"],
                        "arrows":
                        "to",
                    })

        dependencies = cls.make_unique(dependencies)
        return dependencies