From 62e8f857bf5dd03f54539b5eee2bd383d0541ff3 Mon Sep 17 00:00:00 2001 From: Patrick Tasse Date: Fri, 3 Oct 2025 20:08:45 +0200 Subject: [PATCH] Support generic data endpoint Add --get-data and --parameters arguments to cli. Implement fetch_data to invoke /obj endpoint. Add ObjectModel support for the response. Signed-off-by: Patrick Tasse --- README.md | 4 +++ tsp/model_type.py | 1 + tsp/object_model.py | 66 +++++++++++++++++++++++++++++++++++++++++++++ tsp/response.py | 3 +++ tsp/tsp_client.py | 31 +++++++++++++++++++-- tsp_cli_client | 29 ++++++++++++++++++-- 6 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 tsp/object_model.py diff --git a/README.md b/README.md index 7e8f7bd..f075fe2 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ usage: tsp_cli_client [-h] [--ip IP] [--port PORT] [--list-experiment UUID] [--list-experiments] [--delete-experiment UUID] [--list-outputs UUID] [--list-output OUTPUT_ID] [--get-tree OUTPUT_ID] + [--get-data OUTPUT_ID] [--get-virtual-table-columns OUTPUT_ID] [--get-virtual-table-lines OUTPUT_ID] [--table-line-index INDEX] [--table-line-count COUNT] @@ -118,6 +119,7 @@ optional arguments: --list-outputs UUID Get details on the given trace --list-output OUTPUT_ID Get details on the given output of a trace + --get-data OUTPUT_ID Get the data object of an output of type DATA using parameters provided by --parameters --get-tree OUTPUT_ID Get the tree of an output of type DATA_TREE --get-virtual-table-columns OUTPUT_ID Get the columns of an output of type DATA_TREE @@ -164,6 +166,7 @@ optional arguments: --config-id CONFIG_ID id of configuration --params PARAMS comma separated key value pairs (key1=val1,key2=val2) + --parameters PARAMS parameters as JSON string '{"key": "value"}' --get-health Get the health status of the server --get-identifier Identify important information regarding the server and the system --list-output-configuration-sources OUTPUT_ID @@ -195,6 +198,7 @@ Examples: ./tsp_cli_client --delete-experiment UUID [--do-delete-traces] ./tsp_cli_client --list-outputs UUID ./tsp_cli_client --list-output OUTPUT_ID --uuid UUID + ./tsp_cli_client --get-data OUTPUT_ID --uuid UUID --parameters '{"key1":"value1","key2":2}' ./tsp_cli_client --get-tree OUTPUT_ID --uuid UUID ./tsp_cli_client --get-virtual-table-columns OUTPUT_ID --uuid UUID ./tsp_cli_client --get-virtual-table-lines --table-line-index INDEX --table-line-count COUNT --table-column-ids IDs --table-search-direction DIRECTION --table-search-expression COLUMN_ID EXPRESSION diff --git a/tsp/model_type.py b/tsp/model_type.py index 1d9e1ee..0a36687 100644 --- a/tsp/model_type.py +++ b/tsp/model_type.py @@ -35,6 +35,7 @@ class ModelType(Enum): TIME_GRAPH_ARROW = "time_graph_arrow" XY_TREE = "xy_tree" XY = "xy" + DATA = "data" DATA_TREE = "data_tree" VIRTUAL_TABLE_HEADER = "virtual_table_header" VIRTUAL_TABLE = "virtual_table" diff --git a/tsp/object_model.py b/tsp/object_model.py new file mode 100644 index 0000000..fb0372f --- /dev/null +++ b/tsp/object_model.py @@ -0,0 +1,66 @@ +# The MIT License (MIT) +# +# Copyright (C) 2025 - Ericsson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Object model file.""" + +import json + +OBJECT_KEY = "object" +NEXT_KEY = "next" +PREVIOUS_KEY = "previous" + +class ObjectModel: + ''' + Object model that will be returned by the server + ''' + + def __init__(self, params): + ''' + Constructor + ''' + if OBJECT_KEY in params: + self.object = params.get(OBJECT_KEY) + del params[OBJECT_KEY] + else: + self.object = "" + + if NEXT_KEY in params: + self.next = params.get(NEXT_KEY) + del params[NEXT_KEY] + else: + self.next = "" + + if PREVIOUS_KEY in params: + self.previous = params.get(PREVIOUS_KEY) + del params[PREVIOUS_KEY] + else: + self.previous = "" + + def print(self): + ''' + Print the Object model + ''' + print("\"object\": {0}".format(json.dumps(self.object, indent=2))) + if self.previous is not None: + print("\"previous\": {0}".format(json.dumps(self.previous))) + if self.next is not None: + print("\"next\": {0}".format(json.dumps(self.next))) diff --git a/tsp/response.py b/tsp/response.py index c27433d..4f81e09 100644 --- a/tsp/response.py +++ b/tsp/response.py @@ -27,6 +27,7 @@ from enum import Enum from tsp.model_type import ModelType +from tsp.object_model import ObjectModel from tsp.output_descriptor import OutputDescriptor from tsp.virtual_table_header_model import VirtualTableHeaderModel from tsp.virtual_table_model import VirtualTableModel @@ -96,6 +97,8 @@ def __init__(self, params, model_type): self.model = EntryModel(params.get(MODEL_KEY)) elif self.model_type == ModelType.XY: self.model = XYModel(params.get(MODEL_KEY)) + elif self.model_type == ModelType.DATA: + self.model = ObjectModel(params.get(MODEL_KEY)) elif self.model_type == ModelType.DATA_TREE: self.model = EntryModel(params.get(MODEL_KEY), self.model_type) elif self.model_type == ModelType.VIRTUAL_TABLE_HEADER: diff --git a/tsp/tsp_client.py b/tsp/tsp_client.py index 3b5e318..7bb8f66 100644 --- a/tsp/tsp_client.py +++ b/tsp/tsp_client.py @@ -46,6 +46,7 @@ headers_form = {'content-type': 'application/x-www-form-urlencoded', 'Accept': APPLICATION_JSON} +GET_DATA_FAILED = "failed to get data: {0} {1}" GET_TREE_FAILED = "failed to get tree: {0}" GET_STATES_FAILED = "failed to get states: {0}" GET_ARROWS_FAILED = "failed to get arrows: {0}" @@ -262,13 +263,39 @@ def fetch_experiment_output(self, exp_uuid, output_id): print(GET_TREE_FAILED.format(response.status_code)) return TspClientResponse(None, response.status_code, response.text) + def fetch_data(self, exp_uuid, output_id, parameters=None): + ''' + Fetch Data, Model extends ObjectModel + :param exp_uuid: Experiment UUID + :param output_id: Output ID + :param parameters: Query object + :returns: :class: `TspClientResponse ` object ObjectModel + :rtype: TspClientResponse + ''' + api_url = '{0}experiments/{1}/outputs/data/{2}/obj'.format( + self.base_url, exp_uuid, output_id) + + params = parameters + if parameters is None: + params = {} + + response = requests.post(api_url, json=params, headers=headers) + + if response.status_code == 200: + return TspClientResponse(GenericResponse(json.loads(response.content.decode('utf-8')), + ModelType.DATA), + response.status_code, response.text) + else: # pragma: no cover + print(GET_DATA_FAILED.format(response.status_code, response.text)) + return TspClientResponse(None, response.status_code, response.text) + def fetch_datatree(self, exp_uuid, output_id, parameters=None): ''' - Fetch Time Graph tree, Model extends TimeGraphEntry + Fetch Data tree, Model extends EntryModel :param exp_uuid: Experiment UUID :param output_id: Output ID :param parameters: Query object - :returns: :class: `TspClientResponse ` object Timegraph entries response + :returns: :class: `TspClientResponse ` object EntryModel :rtype: TspClientResponse ''' api_url = '{0}experiments/{1}/outputs/data/{2}/tree'.format( diff --git a/tsp_cli_client b/tsp_cli_client index 19b4c38..10760c4 100755 --- a/tsp_cli_client +++ b/tsp_cli_client @@ -158,12 +158,14 @@ if __name__ == "__main__": help="Get details on the given trace", metavar="UUID") parser.add_argument("--list-output", dest="list_output", help="Get details on the given output of a trace", metavar="OUTPUT_ID") + parser.add_argument("--get-data", dest="get_data", + help="Get the data object of an output of type DATA using parameters provided by --parameters", metavar="OUTPUT_ID") parser.add_argument("--get-tree", dest="get_tree", help="Get the tree of an output of type DATA_TREE", metavar="OUTPUT_ID") parser.add_argument("--get-virtual-table-columns", dest="get_virtual_table_columns", - help="Get the columns of an output of type DATA_TREE", metavar="OUTPUT_ID") + help="Get the columns of an output of type TABLE", metavar="OUTPUT_ID") parser.add_argument("--get-virtual-table-lines", dest="get_virtual_table_lines", - help="Get the tree lines of an output of type DATA_TREE", metavar="OUTPUT_ID") + help="Get the tree lines of an output of type TABLE", metavar="OUTPUT_ID") parser.add_argument("--table-line-index", dest="table_line_index", help="The index of the table line to start fetching", metavar="TABLE_LINE_INDEX") parser.add_argument("--table-line-count", dest="table_line_count", @@ -210,6 +212,7 @@ if __name__ == "__main__": parser.add_argument("--type-id", dest="type_id", help="id of configuration source type") parser.add_argument("--config-id", dest="config_id", help="id of configuration") parser.add_argument("--params", dest="params", help="semicolon separated key value pairs (key1=val1;key2=val2)") + parser.add_argument("--parameters", dest="parameters", help="parameters as JSON string '{\"key\": \"value\"}'") parser.add_argument("--get-health", dest="get_health", action='store_true', help="Get the health status of the server") parser.add_argument("--get-identifier", dest="get_identifier", action='store_true', help="Get important information regarding the trace server and the system") parser.add_argument("--list-output-configuration-sources", dest="list_output_configuration_sources", @@ -379,6 +382,28 @@ if __name__ == "__main__": print(TRACE_MISSING) sys.exit(1) + if options.get_data: + if options.uuid is not None: + + params = None + if options.parameters is not None: + s = options.parameters + if not s.startswith('{') or not s.endswith('}'): + s = '{' + s + '}' + params = {TspClient.PARAMETERS_KEY: json.loads(s)} + response = tsp_client.fetch_data( + options.uuid, options.get_data, params) + + if response.status_code == 200: + model = response.model.model + model.print() + sys.exit(0) + else: + sys.exit(1) + else: + print(TRACE_MISSING) + sys.exit(1) + if options.get_tree: __get_tree(options.uuid, options.get_tree, "DATA_TREE")