Skip to content
Snippets Groups Projects
Commit 4bf7cc89 authored by Nikolay Stanchev's avatar Nikolay Stanchev
Browse files

Updates graph build API endpoint - timestamps are now passed in the JSON body...

Updates graph build API endpoint - timestamps are now passed in the JSON body and not in the URL query string
parent 861166d8
No related branches found
No related tags found
No related merge requests found
...@@ -118,15 +118,9 @@ class TestGraphAPI(object): ...@@ -118,15 +118,9 @@ class TestGraphAPI(object):
"request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size)"}) "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size)"})
body = dumps(dict(service_function_chain="sfc", service_function_chain_instance="sfc_1", service_functions=service_functions)) body = dumps(dict(service_function_chain="sfc", service_function_chain_instance="sfc_1", service_functions=service_functions))
request = testing.DummyRequest() request = testing.DummyRequest()
request.params["from_timestamp"] = 12341412
request.params["to_timestamp"] = 12341412
request.body = body.encode(request.charset) request.body = body.encode(request.charset)
error_raised = False with pytest.raises(HTTPBadRequest, message="A bad request error must have been raised in case of missing timestamp parameters."):
try:
GraphAPI(request).build_temporal_graph() GraphAPI(request).build_temporal_graph()
except HTTPBadRequest:
error_raised = True
assert error_raised, "A bad request error must have been raised in case of invalid URL parameters."
# Create a valid build request and send it to the API endpoint # Create a valid build request and send it to the API endpoint
service_functions = dict(nginx={"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)", service_functions = dict(nginx={"measurement_name": "nginx", "response_time_field": "mean(avg_processing_time)",
...@@ -134,10 +128,10 @@ class TestGraphAPI(object): ...@@ -134,10 +128,10 @@ class TestGraphAPI(object):
minio={"measurement_name": "minio_http", "response_time_field": "mean(total_processing_time)/mean(total_requests_count)", minio={"measurement_name": "minio_http", "response_time_field": "mean(total_processing_time)/mean(total_requests_count)",
"request_size_field": "mean(total_requests_size)/mean(total_requests_count)", "response_size_field": "mean(total_response_size)/mean(total_requests_count)"}) "request_size_field": "mean(total_requests_size)/mean(total_requests_count)", "response_size_field": "mean(total_response_size)/mean(total_requests_count)"})
build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_premium", service_functions=service_functions) build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_premium", service_functions=service_functions)
build_json_body["from"] = from_timestamp
build_json_body["to"] = to_timestamp
body = dumps(build_json_body) body = dumps(build_json_body)
request = testing.DummyRequest() request = testing.DummyRequest()
request.params["from"] = from_timestamp
request.params["to"] = to_timestamp
request.body = body.encode(request.charset) request.body = body.encode(request.charset)
response = GraphAPI(request).build_temporal_graph() response = GraphAPI(request).build_temporal_graph()
graph_subresponse = response.pop("graph") graph_subresponse = response.pop("graph")
...@@ -193,10 +187,10 @@ class TestGraphAPI(object): ...@@ -193,10 +187,10 @@ class TestGraphAPI(object):
apache={"measurement_name": "apache", "response_time_field": "mean(avg_processing_time)", apache={"measurement_name": "apache", "response_time_field": "mean(avg_processing_time)",
"request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size)"}) "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size)"})
build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_non_premium", service_functions=service_functions) build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_non_premium", service_functions=service_functions)
build_json_body["from"] = from_timestamp
build_json_body["to"] = to_timestamp
body = dumps(build_json_body) body = dumps(build_json_body)
request = testing.DummyRequest() request = testing.DummyRequest()
request.params["from"] = from_timestamp
request.params["to"] = to_timestamp
request.body = body.encode(request.charset) request.body = body.encode(request.charset)
response = GraphAPI(request).build_temporal_graph() response = GraphAPI(request).build_temporal_graph()
graph_subresponse = response.pop("graph") graph_subresponse = response.pop("graph")
...@@ -330,10 +324,10 @@ class TestGraphAPI(object): ...@@ -330,10 +324,10 @@ class TestGraphAPI(object):
minio={"measurement_name": "minio_http", "response_time_field": "mean(total_processing_time)/mean(total_requests_count)", minio={"measurement_name": "minio_http", "response_time_field": "mean(total_processing_time)/mean(total_requests_count)",
"request_size_field": "mean(total_requests_size)/mean(total_requests_count)", "response_size_field": "mean(total_response_size)/mean(total_requests_count)"}) "request_size_field": "mean(total_requests_size)/mean(total_requests_count)", "response_size_field": "mean(total_response_size)/mean(total_requests_count)"})
build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_premium", service_functions=service_functions) build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_premium", service_functions=service_functions)
build_json_body["from"] = from_timestamp
build_json_body["to"] = to_timestamp
body = dumps(build_json_body) body = dumps(build_json_body)
request = testing.DummyRequest() request = testing.DummyRequest()
request.params["from"] = from_timestamp
request.params["to"] = to_timestamp
request.body = body.encode(request.charset) request.body = body.encode(request.charset)
response = GraphAPI(request).build_temporal_graph() response = GraphAPI(request).build_temporal_graph()
graph_subresponse = response.pop("graph") graph_subresponse = response.pop("graph")
...@@ -401,10 +395,10 @@ class TestGraphAPI(object): ...@@ -401,10 +395,10 @@ class TestGraphAPI(object):
apache={"measurement_name": "apache", "response_time_field": "mean(avg_processing_time)", apache={"measurement_name": "apache", "response_time_field": "mean(avg_processing_time)",
"request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size)"}) "request_size_field": "mean(avg_request_size)", "response_size_field": "mean(avg_response_size)"})
build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_non_premium", service_functions=service_functions) build_json_body = dict(service_function_chain="test_sfc", service_function_chain_instance="test_sfc_non_premium", service_functions=service_functions)
build_json_body["from"] = from_timestamp
build_json_body["to"] = to_timestamp
body = dumps(build_json_body) body = dumps(build_json_body)
request = testing.DummyRequest() request = testing.DummyRequest()
request.params["from"] = from_timestamp
request.params["to"] = to_timestamp
request.body = body.encode(request.charset) request.body = body.encode(request.charset)
response = GraphAPI(request).build_temporal_graph() response = GraphAPI(request).build_temporal_graph()
graph_subresponse = response.pop("graph") graph_subresponse = response.pop("graph")
......
...@@ -29,8 +29,7 @@ import logging ...@@ -29,8 +29,7 @@ import logging
GRAPH_ROUND_TRIP_TIME_URL_PARAMS = ("startpoint", "endpoint") GRAPH_ROUND_TRIP_TIME_URL_PARAMS = ("startpoint", "endpoint")
GRAPH_BUILD_URL_PARAMS = ("from", "to") GRAPH_BUILD_QUERY_PARAMS = {"from", "to", "service_function_chain", "service_function_chain_instance", "service_functions"}
GRAPH_BUILD_QUERY_PARAMS = {"service_function_chain", "service_function_chain_instance", "service_functions"}
GRAPH_BUILD_SF_QUERY_PARAMS = {"response_time_field", "request_size_field", "response_size_field", "measurement_name"} GRAPH_BUILD_SF_QUERY_PARAMS = {"response_time_field", "request_size_field", "response_size_field", "measurement_name"}
INFLUX_QUERY_TEMPLATE = 'SELECT {0} AS mean_response_time, {1} AS mean_request_size, {2} AS mean_response_size FROM "{3}"."{4}".{5} WHERE "flame_sfc"=\'{6}\' and "flame_sfci"=\'{7}\' and time>={8} and time<{9} GROUP BY "flame_sfe", "flame_location", "flame_sf"' INFLUX_QUERY_TEMPLATE = 'SELECT {0} AS mean_response_time, {1} AS mean_request_size, {2} AS mean_response_size FROM "{3}"."{4}".{5} WHERE "flame_sfc"=\'{6}\' and "flame_sfci"=\'{7}\' and time>={8} and time<{9} GROUP BY "flame_sfe", "flame_location", "flame_sf"'
...@@ -100,33 +99,12 @@ def validate_json_queries_body(body): ...@@ -100,33 +99,12 @@ def validate_json_queries_body(body):
assert type(query_data) == dict, "Each service function must be associated with a respective JSON object." assert type(query_data) == dict, "Each service function must be associated with a respective JSON object."
assert GRAPH_BUILD_SF_QUERY_PARAMS == set(query_data.keys()), "Invalid query data for service function {0} in the JSON query document".format(sf) assert GRAPH_BUILD_SF_QUERY_PARAMS == set(query_data.keys()), "Invalid query data for service function {0} in the JSON query document".format(sf)
return body assert type(body["from"]) == int, "'from' parameter must be a timestamp integer"
assert body["from"] > 0, "'from' parameter must be a positive timestamp integer"
assert type(body["to"]) == int, "'to' parameter must be a timestamp integer"
def validate_graph_url_params(params): assert body["to"] > body["from"], "'to' parameter timestamp must be greater than 'from' parameter timestamp"
"""
Validates the request url parameters used in building a temporal graph.
:param params: the parameters dictionary to validate
:return: the validated parameters
:raise AssertionError: for invalid parameters
"""
global GRAPH_BUILD_URL_PARAMS return body
url_params = {}
for param in GRAPH_BUILD_URL_PARAMS:
assert param in params, "Incorrect url parameters - required url query parameter '{0}' is not found in the request parameters.".format(param)
url_params[param] = params[param]
try:
# convert timestamps to integers
url_params['from'] = int(url_params['from'])
url_params['to'] = int(url_params['to'])
except ValueError:
assert False, "Invalid URL timestamp parameters"
return url_params
def validate_graph_rtt_params(params): def validate_graph_rtt_params(params):
......
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
""" """
from clmcservice.graphapi.utilities import validate_json_queries_body, validate_graph_url_params, \ from clmcservice.graphapi.utilities import validate_json_queries_body, RTT_CYPHER_QUERY_TEMPLATE, \
build_network_graph, delete_network_graph, build_temporal_subgraph, delete_temporal_subgraph, validate_graph_rtt_params, RTT_CYPHER_QUERY_TEMPLATE build_network_graph, delete_network_graph, build_temporal_subgraph, delete_temporal_subgraph, validate_graph_rtt_params
from influxdb import InfluxDBClient from influxdb import InfluxDBClient
from py2neo import Graph from py2neo import Graph
from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPServiceUnavailable, HTTPNotImplemented from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPServiceUnavailable, HTTPNotImplemented
...@@ -57,9 +57,8 @@ class GraphAPI(object): ...@@ -57,9 +57,8 @@ class GraphAPI(object):
def build_temporal_graph(self): def build_temporal_graph(self):
""" """
An API endpoint to build a temporal graph and store it in neo4j based on the posted JSON query document. An API endpoint to build a temporal graph and store it in neo4j based on the posted JSON query document.
The request parameters must also include URL query parameters defining the time range for which the graph must be generated.
:raises HTTPBadRequest: if request body is not a valid JSON with the queries per service function or if request URL doesn't contain the required URL query parameters :raises HTTPBadRequest: if request body is not a valid JSON with the queries per service function
:return: A JSON document containing the posted request body, along with meta data about the built graph (time range and uuid, which can then be reused for other API calls) :return: A JSON document containing the posted request body, along with meta data about the built graph (time range and uuid, which can then be reused for other API calls)
""" """
...@@ -69,11 +68,6 @@ class GraphAPI(object): ...@@ -69,11 +68,6 @@ class GraphAPI(object):
except AssertionError as e: except AssertionError as e:
raise HTTPBadRequest("Bad request content: {0}".format(e.args)) raise HTTPBadRequest("Bad request content: {0}".format(e.args))
try:
params = validate_graph_url_params(self.request.params)
except AssertionError as e:
raise HTTPBadRequest("Request URL format is incorrect: {0}".format(e.args))
graph = Graph(host=self.request.registry.settings['neo4j_host'], password=self.request.registry.settings['neo4j_password']) graph = Graph(host=self.request.registry.settings['neo4j_host'], password=self.request.registry.settings['neo4j_password'])
influx_client = InfluxDBClient(host=self.request.registry.settings['influx_host'], port=self.request.registry.settings['influx_port'], timeout=10) influx_client = InfluxDBClient(host=self.request.registry.settings['influx_host'], port=self.request.registry.settings['influx_port'], timeout=10)
...@@ -81,8 +75,8 @@ class GraphAPI(object): ...@@ -81,8 +75,8 @@ class GraphAPI(object):
if database_name not in [db["name"] for db in influx_client.get_list_database()]: if database_name not in [db["name"] for db in influx_client.get_list_database()]:
raise HTTPBadRequest("Database for service function chain {0} not found.".format(database_name)) raise HTTPBadRequest("Database for service function chain {0} not found.".format(database_name))
from_timestamp = params['from'] * 10**9 from_timestamp = json_queries['from'] * 10**9
to_timestamp = params['to'] * 10**9 to_timestamp = json_queries['to'] * 10**9
request_id = str(uuid4()) request_id = str(uuid4())
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment