From aed088424374a99c0efcf004792bc83f56f41c94 Mon Sep 17 00:00:00 2001
From: Nikolay Stanchev <ns17@it-innovation.soton.ac.uk>
Date: Tue, 10 Jul 2018 16:16:37 +0100
Subject: [PATCH] Updates the graph build API endpoint to also include service
 function chain and service function chain instance

---
 src/service/clmcservice/graphapi/tests.py     | 20 +++++++++++++++++--
 src/service/clmcservice/graphapi/utilities.py | 12 +++++++++++
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/service/clmcservice/graphapi/tests.py b/src/service/clmcservice/graphapi/tests.py
index ddb3870..5fcffdc 100644
--- a/src/service/clmcservice/graphapi/tests.py
+++ b/src/service/clmcservice/graphapi/tests.py
@@ -163,6 +163,10 @@ class TestGraphAPI(object):
         assert sf_i_names == {"nginx_1", "minio_1"}, "The graph must contain 2 service function instances - nginx_1 and minio_1"
         endpoints = set([node["name"] for node in graph_db.nodes.match("Endpoint", uuid=request_id)])
         assert endpoints == {"minio_1_ep1", "nginx_1_ep1", "nginx_1_ep2"}
+        sfc_i_names = set([node["name"] for node in graph_db.nodes.match("ServiceFunctionChainInstance")])
+        assert sfc_i_names == {"test_sfc1_1"}
+        sfc_names = set([node["name"] for node in graph_db.nodes.match("ServiceFunctionChain")])
+        assert sfc_names == {"test_sfc1"}
 
         # check the appropriate edges have been created
         self.check_exist_relationship(
@@ -174,7 +178,11 @@ class TestGraphAPI(object):
                 ("nginx_1", "ServiceFunctionInstance", "nginx_1_ep1", "Endpoint", "realisedBy"),
                 ("nginx_1", "ServiceFunctionInstance", "nginx_1_ep2", "Endpoint", "realisedBy"),
                 ("minio_1", "ServiceFunctionInstance", "minio", "ServiceFunction", "instanceOf"),
-                ("nginx_1", "ServiceFunctionInstance", "nginx", "ServiceFunction", "instanceOf")
+                ("nginx_1", "ServiceFunctionInstance", "test_sfc1_1", "ServiceFunctionChainInstance", "utilizedBy"),
+                ("minio_1", "ServiceFunctionInstance", "test_sfc1_1", "ServiceFunctionChainInstance", "utilizedBy"),
+                ("nginx", "ServiceFunction", "test_sfc1", "ServiceFunctionChain", "utilizedBy"),
+                ("minio", "ServiceFunction", "test_sfc1", "ServiceFunctionChain", "utilizedBy"),
+                ("test_sfc1_1", "ServiceFunctionChainInstance", "test_sfc1", "ServiceFunctionChain", "instanceOf"),
             ), graph_db, request_id
         )
 
@@ -207,6 +215,9 @@ class TestGraphAPI(object):
         for ep in ("minio_2_ep1", "apache_1_ep1"):
             assert graph_db.nodes.match("Endpoint", name=ep, uuid=request_id).first() is not None, "Endpoint {0} must have been added to the graph".format(ep)
 
+        assert graph_db.nodes.match("ServiceFunctionChainInstance", name="test_sfc2_1").first() is not None, "Service function chain instance test_sfc2_1 must have been added to the graph"
+        assert graph_db.nodes.match("ServiceFunctionChain", name="test_sfc2").first() is not None, "Service function chain test_sfc2 must have been added to the graph"
+
         # check the appropriate edges have been created
         self.check_exist_relationship(
             (
@@ -215,7 +226,12 @@ class TestGraphAPI(object):
                 ("minio_2", "ServiceFunctionInstance", "minio_2_ep1", "Endpoint", "realisedBy"),
                 ("apache_1", "ServiceFunctionInstance", "apache_1_ep1", "Endpoint", "realisedBy"),
                 ("minio_2", "ServiceFunctionInstance", "minio", "ServiceFunction", "instanceOf"),
-                ("apache_1", "ServiceFunctionInstance", "apache", "ServiceFunction", "instanceOf")
+                ("apache_1", "ServiceFunctionInstance", "apache", "ServiceFunction", "instanceOf"),
+                ("minio_2", "ServiceFunctionInstance", "test_sfc2_1", "ServiceFunctionChainInstance", "utilizedBy"),
+                ("apache_1", "ServiceFunctionInstance", "test_sfc2_1", "ServiceFunctionChainInstance", "utilizedBy"),
+                ("minio", "ServiceFunction", "test_sfc2", "ServiceFunctionChain", "utilizedBy"),
+                ("apache", "ServiceFunction", "test_sfc2", "ServiceFunctionChain", "utilizedBy"),
+                ("test_sfc2_1", "ServiceFunctionChainInstance", "test_sfc2", "ServiceFunctionChain", "instanceOf")
             ), graph_db, request_id
         )
 
diff --git a/src/service/clmcservice/graphapi/utilities.py b/src/service/clmcservice/graphapi/utilities.py
index 93bcd09..a0a29d6 100644
--- a/src/service/clmcservice/graphapi/utilities.py
+++ b/src/service/clmcservice/graphapi/utilities.py
@@ -189,6 +189,14 @@ def build_temporal_graph(request_id, from_timestamp, to_timestamp, json_queries,
 
     log.info("Building graph for service function chain {0} from database {1} with retention policy {2}".format(sfc_i, db, rp))
 
+    sfc = "_".join(sfc_i.split('_')[: -1])  # assumes sfc_i is always in the form <sfc>_<num>
+    # create a node for the service function chain if it doesn't exist
+    service_function_chain_node = find_or_create_node(graph, "ServiceFunctionChain", name=sfc)
+    # create a node for the service function chain instance if it doesn't exist
+    service_function_chain_instance_node = find_or_create_node(graph, "ServiceFunctionChainInstance", name=sfc_i)
+    # create a instanceOf edge if it doesn't exist
+    find_or_create_edge(graph, "instanceOf", service_function_chain_instance_node, service_function_chain_node)
+
     compute_nodes = set()  # a set is used to keep track of all compute nodes that are found while building the graph, which is then used to retrieve the network latencies
 
     # traverse the list of service functions
@@ -203,6 +211,8 @@ def build_temporal_graph(request_id, from_timestamp, to_timestamp, json_queries,
 
         # create a node for the service function if it doesn't exist
         service_function_node = find_or_create_node(graph, "ServiceFunction", name=service_function)
+        # crate a utilizedBy edge between the service function and the service function chain
+        find_or_create_edge(graph, "utilizedBy", service_function_node, service_function_chain_node)
 
         log.info("Executing query: {0}".format(query_to_execute))
         result = influx_client.query(query_to_execute)  # execute the query
@@ -222,6 +232,8 @@ def build_temporal_graph(request_id, from_timestamp, to_timestamp, json_queries,
             service_function_instance_node = find_or_create_node(graph, "ServiceFunctionInstance", name=tags["sf_i"])
             # create an edge between the instance and the service function (if it is not already created)
             find_or_create_edge(graph, "instanceOf", service_function_instance_node, service_function_node)
+            # crate a utilizedBy edge between the service function instance and the service function chain instance
+            find_or_create_edge(graph, "utilizedBy", service_function_instance_node, service_function_chain_instance_node)
 
             # create an Endpoint node from the tag value (if it is not already created)
             ipendpoint_node = find_or_create_node(graph, "Endpoint", name=tags["ipendpoint"], response_time=response_time, uuid=request_id)
-- 
GitLab