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

Removes old round-trip-time API endpoint

parent 0bcc8044
No related branches found
No related tags found
No related merge requests found
......@@ -57,7 +57,6 @@ def main(global_config, **settings):
# add routes of the aggregator API
config.add_route('aggregator_config', '/aggregator/config')
config.add_route('aggregator_controller', '/aggregator/control')
config.add_route('round_trip_time_query', '/query/round-trip-time')
# add routes of the WHOAMI API
config.add_route('whoami_endpoints', '/whoami/endpoints')
......
......@@ -43,10 +43,6 @@ MALFORMED_FLAG = 'malformed' # Attribute for storing the flag, which shows whet
COMMENT_ATTRIBUTE = 'comment'
COMMENT_VALUE = 'Aggregator is running in a malformed state - it uses an old version of the configuration. Please, restart it so that the updated configuration is used.'
# the attributes of the JSON response body that are expected when querying round trip time
ROUND_TRIP_ATTRIBUTES = ('media_service', 'start_timestamp', 'end_timestamp')
URL_REGEX = compile(
r'^https?://' # http:// or https://
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain, e.g. example.domain.com
......@@ -108,25 +104,6 @@ def validate_action_content(content):
return content
def validate_round_trip_query_params(params):
"""
A utility function to validate a dictionary of parameters.
:param params: the params dict to validate
:return: the validated parameters dictionary
:raise AssertionError: if the argument is not a valid json content
"""
global ROUND_TRIP_ATTRIBUTES
assert len(params) == len(ROUND_TRIP_ATTRIBUTES), "Content mustn't contain more attributes than the required ones."
for attribute in ROUND_TRIP_ATTRIBUTES:
assert attribute in params, "Required attribute not found in the request content."
return params
def validate_conf_file(conf_file_path):
"""
Validates the aggregator's configuration file - checks for existence of the file path, whether it can be parsed as a configuration file and
......
......@@ -23,12 +23,10 @@
"""
from pyramid.view import view_defaults, view_config
from pyramid.httpexceptions import HTTPBadRequest, HTTPInternalServerError
from influxdb import InfluxDBClient
from urllib.parse import urlparse
from pyramid.httpexceptions import HTTPBadRequest
from subprocess import Popen
from clmcservice.aggregationapi.utilities import validate_config_content, validate_action_content, validate_round_trip_query_params, \
CONF_OBJECT, CONF_FILE_ATTRIBUTE, AGGREGATOR_CONFIG_SECTION, CONFIG_ATTRIBUTES, ROUND_TRIP_ATTRIBUTES, RUNNING_FLAG, PROCESS_ATTRIBUTE, MALFORMED_FLAG, COMMENT_ATTRIBUTE, COMMENT_VALUE
from clmcservice.aggregationapi.utilities import validate_config_content, validate_action_content, \
CONF_OBJECT, CONF_FILE_ATTRIBUTE, AGGREGATOR_CONFIG_SECTION, CONFIG_ATTRIBUTES, RUNNING_FLAG, PROCESS_ATTRIBUTE, MALFORMED_FLAG, COMMENT_ATTRIBUTE, COMMENT_VALUE
import os
import os.path
import sys
......@@ -252,105 +250,3 @@ class AggregatorController(object):
# check if the process is started before trying to terminate it - process.poll() only returns something if the process has terminated, hence we check for a None value
return process is not None and process.poll() is None
@view_defaults(route_name='round_trip_time_query', renderer='json')
class RoundTripTimeQuery(object):
# TODO This API endpoint has not been tested, neither has the formula used to calculate round trip time.
"""
A class-based view for querying the round trip time in a given range.
"""
def __init__(self, request):
"""
Initialises the instance of the view with the request argument.
:param request: client's call request
"""
self.request = request
@view_config(request_method="GET")
def get(self):
"""
A GET API call for the averaged round trip time of a specific media service over a given time range.
:return: A JSON response with the round trip time and its contributing parts.
"""
params = {}
for attribute in ROUND_TRIP_ATTRIBUTES:
if attribute in self.request.params:
params[attribute] = self.request.params.get(attribute)
try:
params = validate_round_trip_query_params(params)
conf = self.request.registry.settings[CONF_OBJECT]
if conf is None:
raise HTTPBadRequest("You must configure the aggregator before making a round trip time query. Send a PUT request to /aggregator/config with a JSON body of the configuration.")
aggregator_config_data = {config_attribute: conf[AGGREGATOR_CONFIG_SECTION][config_attribute] for config_attribute in CONFIG_ATTRIBUTES}
aggregator_config_data['aggregator_report_period'] = int(aggregator_config_data['aggregator_report_period'])
media_service = params.get(ROUND_TRIP_ATTRIBUTES[0])
start_timestamp = params.get(ROUND_TRIP_ATTRIBUTES[1])
end_timestamp = params.get(ROUND_TRIP_ATTRIBUTES[2])
influx_db_name = aggregator_config_data.get(CONFIG_ATTRIBUTES[1])
influx_db_url = aggregator_config_data.get(CONFIG_ATTRIBUTES[2])
url_object = urlparse(influx_db_url)
try:
db_client = InfluxDBClient(host=url_object.hostname, port=url_object.port, database=influx_db_name, timeout=10)
query = 'SELECT mean(*) FROM "{0}"."autogen"."e2e_delays" WHERE time >= {1} and time < {2} and sf_instance = \'{3}\''.format(
influx_db_name, start_timestamp, end_timestamp, media_service)
log.info("Executing query: {0}".format(query))
result = db_client.query(query)
actual_result = next(result.get_points(), None)
if actual_result is None:
return {"result": None}
else:
forward_latency = actual_result.get("mean_delay_forward")
reverse_latency = actual_result.get("mean_delay_reverse")
service_delay = actual_result.get("mean_delay_service")
request_size = actual_result.get("mean_avg_request_size")
response_size = actual_result.get("mean_avg_response_size")
bandwidth = actual_result.get("mean_avg_bandwidth")
rtt = self.calculate_round_trip_time(forward_latency, reverse_latency, service_delay, request_size, response_size, bandwidth)
return {"result": rtt}
except Exception as e:
msg = "Cannot instantiate connection with database {0} on url {1}.".format(influx_db_name, influx_db_url)
log.info(msg)
log.error(type(e))
log.error(e)
log.error(e.args)
raise HTTPInternalServerError(msg)
except AssertionError:
raise HTTPBadRequest('Bad request content - must be in JSON format: {"media_service": value, "start_timestamp": value, "end_timestamp": value}.')
@staticmethod
def calculate_round_trip_time(forward_latency, reverse_latency, service_delay, request_size, response_size, bandwidth, packet_size=1500, packet_header_size=50):
"""
Calculates the round trip time given the list of arguments.
:param forward_latency: network latency in forward direction (s)
:param reverse_latency: network latency in reverse direction (s)
:param service_delay: media service delay (s)
:param request_size: request size (bytes)
:param response_size: response size (bytes)
:param bandwidth: network bandwidth (Mb/s)
:param packet_size: size of packet (bytes)
:param packet_header_size: size of the header of the packet (bytes)
:return: the calculated round trip time
"""
forward_data_delay = (8/10**6) * (request_size / bandwidth) * (packet_size / (packet_size - packet_header_size))
reverse_data_delay = (8/10**6) * (response_size / bandwidth) * (packet_size / (packet_size - packet_header_size))
return forward_latency + forward_data_delay + service_delay + reverse_latency + reverse_data_delay
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment