Skip to content

Commit adeeb35

Browse files
committed
Add APIs to support configurable output (data provider)
- Add configuration service per output (data provider) This addition enables clients to create derived data providers from an existing data provider. - Add unit tests - Add cli to invoke new endpoints - Update README.md for new commands Signed-off-by: Bernd Hufmann <[email protected]>
1 parent 2fe93af commit adeeb35

File tree

4 files changed

+282
-1
lines changed

4 files changed

+282
-1
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ usage: tsp_cli_client [-h] [--ip IP] [--port PORT]
8989
[--params PARAMS]
9090
[--get-health]
9191
[--get-identifier]
92+
[--list-output-configuration-sources OUTPUT_ID]
93+
[--list-output-configuration-source TYPE_ID]
94+
[--create-output OUTPUT_ID]
95+
[--delete-output DERIVED_OUTPUT_ID]
96+
[--output-id OUTPUT_ID]
97+
[--json-file JSON_FILE]
9298

9399
CLI client to send Trace Server Protocol commands to a Trace Server.
94100

@@ -160,6 +166,18 @@ optional arguments:
160166
--params PARAMS comma separated key value pairs (key1=val1,key2=val2)
161167
--get-health Get the health status of the server
162168
--get-identifier Identify important information regarding the server and the system
169+
--list-output-configuration-sources OUTPUT_ID
170+
Get available configuration sources for a given experiment and output
171+
--list-output-configuration-source TYPE_ID
172+
Get configuration source for a given experiment, output and type
173+
--create-output OUTPUT_ID
174+
Create derived output provided by --param or --json-file
175+
--delete-output DERIVED_OUTPUT_ID
176+
Delete derived output
177+
--output-id OUTPUT_ID
178+
The output ID
179+
--json-file JSON_FILE
180+
JSON file with parameter
163181
```
164182

165183
Examples:
@@ -190,6 +208,10 @@ Examples:
190208
./tsp_cli_client --load-configuration --type-id TYPE_ID --params key1:value1
191209
./tsp_cli_client --update-configuration --type-id TYPE_ID --config-id CONFIG_ID --params key1=value1,key2=value2
192210
./tsp_cli_client --delete-configuration CONFIGURATION_ID --type-id TYPE_ID
211+
./tsp_cli_client --list-output-configuration-sources OUTPUT_ID --uuid UUID
212+
./tsp_cli_client --list-output-configuration-source TYPE_ID --output-id OUTPUT_ID --uuid UUID
213+
./tsp_cli_client --create-output OUTPUT_ID --uuid UUID --json-file absolute-path-to-json-file
214+
./tsp_cli_client --delete-output DERIVED_OUTPUT_ID --output-id OUTPUT_ID --uuid UUID
193215
./tsp_cli_client --get-health
194216
./tsp_cli_client --get-identifier
195217
```

test_tsp.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
from tsp.response import ResponseStatus
3434
from tsp.tsp_client import TspClient
3535
from tsp.virtual_table_tag import VirtualTableTag
36+
from tsp.configuration_source import ConfigurationSource
37+
from tsp.configuration_source_set import ConfigurationSourceSet
38+
from tsp.output_descriptor import OutputDescriptor
3639

3740
STATISTICS_DP_ID = (
3841
"org.eclipse.tracecompass.analysis.timing.core.segmentstore.SegmentStoreStatisticsDataProvider:"
@@ -44,6 +47,8 @@
4447
)
4548
TIMEGRAPH_DP_ID = "org.eclipse.tracecompass.internal.analysis.os.linux.core.threadstatus.ThreadStatusDataProvider"
4649

50+
INANDOUT_DP_ID = "org.eclipse.tracecompass.incubator.inandout.core.analysis.inAndOutdataProviderFactory"
51+
4752
REQUESTED_TIME_START = 1332170682440133097
4853
REQUESTED_TIME_END = 1332170692664579801
4954
REQUESTED_TIME_LENGTH = 10
@@ -53,6 +58,8 @@
5358

5459
CONFIG_SOURCE_TYPE = 'org.eclipse.tracecompass.tmf.core.config.xmlsourcetype'
5560

61+
INANDOUT_CONFIG_SOURCE_TYPE = 'org.eclipse.tracecompass.incubator.internal.inandout.core.config'
62+
5663
# pylint: disable=too-many-public-methods
5764

5865

@@ -693,6 +700,81 @@ def test_put_configuration(self, extension):
693700

694701
self.tsp_client.delete_configuration(CONFIG_SOURCE_TYPE, self.name)
695702

703+
def test_fetch_output_configuration_sources(self, kernel):
704+
"""Expect at least one configuration source ."""
705+
706+
traces = []
707+
response = self.tsp_client.open_trace(os.path.basename(kernel), kernel)
708+
traces.append(response.model.UUID)
709+
response = self.tsp_client.open_experiment(
710+
os.path.basename(kernel), traces)
711+
assert response.status_code == 200
712+
experiment_uuid = response.model.UUID
713+
714+
response = self.tsp_client.fetch_output_configuration_sources(experiment_uuid, INANDOUT_DP_ID)
715+
assert response.status_code == 200
716+
assert isinstance(response.model, ConfigurationSourceSet)
717+
assert response.model.configuration_source_set
718+
assert len(response.model.configuration_source_set) > 0
719+
720+
response = self.tsp_client.fetch_output_configuration_source(experiment_uuid, INANDOUT_DP_ID, INANDOUT_CONFIG_SOURCE_TYPE)
721+
assert response.status_code == 200
722+
assert response.model
723+
assert isinstance(response.model, ConfigurationSource)
724+
725+
assert response.model.schema != None
726+
727+
def test_create_delete_derived_output(self, kernel):
728+
"""Expect a data provider descriptor after creating it."""
729+
730+
traces = []
731+
response = self.tsp_client.open_trace(os.path.basename(kernel), kernel)
732+
traces.append(response.model.UUID)
733+
response = self.tsp_client.open_experiment(
734+
os.path.basename(kernel), traces)
735+
assert response.status_code == 200
736+
experiment_uuid = response.model.UUID
737+
738+
params = {
739+
"name": "My new InAndOut",
740+
"description": "My special configuration",
741+
"sourceTypeId": "org.eclipse.tracecompass.incubator.internal.inandout.core.config",
742+
"parameters": {
743+
"specifiers": [{
744+
"label": "latency",
745+
"inRegex": "(\\S*)_entry",
746+
"outRegex": "(\\S*)_exit",
747+
"contextInRegex": "(\\S*)_entry",
748+
"contextOutRegex": "(\\S*)_exit",
749+
"classifier": "CPU"
750+
}]
751+
}
752+
}
753+
754+
response = self.tsp_client.create_derived_output(experiment_uuid, INANDOUT_DP_ID, params)
755+
assert response.status_code == 200
756+
assert response.model
757+
assert isinstance(response.model, OutputDescriptor)
758+
assert response.model.parent_id == INANDOUT_DP_ID
759+
760+
derived_id = response.model.id
761+
762+
response = self.tsp_client.fetch_experiment_outputs(experiment_uuid)
763+
assert response.status_code == 200
764+
assert response.model
765+
assert len(response.model.descriptors) > 0
766+
assert [desc for desc in response.model.descriptors if desc.id == derived_id]
767+
768+
response = self.tsp_client.fetch_experiment_output(
769+
experiment_uuid, derived_id)
770+
assert response.status_code == 200
771+
assert response.model.id == derived_id
772+
773+
response = self.tsp_client.delete_derived_output(experiment_uuid, INANDOUT_DP_ID, derived_id)
774+
assert response.status_code == 200
775+
assert response.model
776+
assert isinstance(response.model, OutputDescriptor)
777+
696778
def test_fetch_health(self):
697779
"""Expect a successful health response"""
698780
response = self.tsp_client.fetch_health()

tsp/tsp_client.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
GET_TREE_FAILED = "failed to get tree: {0}"
5050
GET_STATES_FAILED = "failed to get states: {0}"
5151
GET_ARROWS_FAILED = "failed to get arrows: {0}"
52+
GET_CONFIG_SOURCE_TYPES = "failed to get config source type(s): {} {}"
5253

5354

5455
# pylint: disable=consider-using-f-string,missing-timeout
@@ -474,6 +475,86 @@ def fetch_xy(self, exp_uuid, output_id, parameters):
474475
print("failed to get xy: {0}".format(response.status_code))
475476
return TspClientResponse(None, response.status_code, response.text)
476477

478+
479+
def fetch_output_configuration_sources(self, exp_uuid, output_id):
480+
'''
481+
Fetch all configuration source types for a given experiment and output
482+
:param exp_uuid Experiment UUID
483+
:param output_id Output ID
484+
:returns :class:`TspClientResponse <ConfigurationSourceSet>` object
485+
:rtype: TspClientResponse
486+
'''
487+
api_url = '{0}experiments/{1}/outputs/{2}/configTypes'.format(
488+
self.base_url, exp_uuid, output_id)
489+
response = requests.get(api_url, headers=headers)
490+
if response.status_code == 200:
491+
return TspClientResponse(ConfigurationSourceSet(json.loads(response.content.decode('utf-8'))),
492+
response.status_code, response.text)
493+
else: # pragma: no cover
494+
print(GET_CONFIG_SOURCE_TYPES.format(response.status_code, response.text))
495+
return TspClientResponse(None, response.status_code, response.text)
496+
497+
def fetch_output_configuration_source(self, exp_uuid, output_id, type_id):
498+
'''
499+
Fetch a single configuration source type for a given experiment, output and type
500+
:param exp_uuid Experiment UUID
501+
:param output_id Output ID
502+
:param type_id the ID of the configuration source type
503+
:returns :class:`TspClientResponse <ConfigurationSource>` object
504+
:rtype: TspClientResponse
505+
'''
506+
api_url = '{0}experiments/{1}/outputs/{2}/configTypes/{3}'.format(
507+
self.base_url, exp_uuid, output_id, type_id)
508+
response = requests.get(api_url, headers=headers)
509+
if response.status_code == 200:
510+
return TspClientResponse(ConfigurationSource(json.loads(response.content.decode('utf-8'))),
511+
response.status_code, response.text)
512+
else: # pragma: no cover
513+
print(GET_CONFIG_SOURCE_TYPES.format(response.status_code, response.text))
514+
return TspClientResponse(None, response.status_code, response.text)
515+
516+
def create_derived_output(self, exp_uuid, output_id, params):
517+
'''
518+
Create a derived output for a given experiment, output and parameters
519+
:param exp_uuid Experiment UUID
520+
:param output_id Output ID
521+
:param params output query params (JSON)
522+
:returns :class:`TspClientResponse <OutputDescriptor>` object
523+
:rtype: TspClientResponse
524+
'''
525+
api_url = '{0}experiments/{1}/outputs/{2}'.format(
526+
self.base_url, exp_uuid, output_id)
527+
528+
response = requests.post(api_url, json=params, headers=headers)
529+
530+
if response.status_code == 200:
531+
return TspClientResponse(OutputDescriptor(json.loads(response.content.decode('utf-8'))),
532+
response.status_code, response.text)
533+
else: # pragma: no cover
534+
print("failed to create derived output: {} {}".format(response.status_code, response.text))
535+
return TspClientResponse(None, response.status_code, response.text)
536+
537+
def delete_derived_output(self, exp_uuid, output_id, derived_output_id):
538+
'''
539+
Create a derived output for a given experiment, output and parameters
540+
:param exp_uuid Experiment UUID
541+
:param output_id Output ID
542+
:param derived_output_id the ID of the derived output
543+
:returns :class:`TspClientResponse <OutputDescriptor>` object
544+
:rtype: TspClientResponse
545+
'''
546+
api_url = '{0}experiments/{1}/outputs/{2}/{3}'.format(
547+
self.base_url, exp_uuid, output_id, derived_output_id)
548+
549+
response = requests.delete(api_url, headers=headers_form)
550+
551+
if response.status_code == 200:
552+
return TspClientResponse(OutputDescriptor(json.loads(response.content.decode('utf-8'))),
553+
response.status_code, response.text)
554+
else: # pragma: no cover
555+
print("delete derived output failed: {} {}".format(response.status_code, response.text))
556+
return TspClientResponse(None, response.status_code, response.text)
557+
477558
def fetch_configuration_sources(self):
478559
'''
479560
Fetch Extensions (loaded files)

tsp_cli_client

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"""Manual CLI script file."""
2828

2929
import argparse
30+
import json
3031
import sys
3132

3233
from os.path import os
@@ -193,6 +194,14 @@ if __name__ == "__main__":
193194
parser.add_argument("--params", dest="params", help="semicolon separated key value pairs (key1=val1;key2=val2)")
194195
parser.add_argument("--get-health", dest="get_health", action='store_true', help="Get the health status of the server")
195196
parser.add_argument("--get-identifier", dest="get_identifier", action='store_true', help="Get important information regarding the trace server and the system")
197+
parser.add_argument("--list-output-configuration-sources", dest="list_output_configuration_sources",
198+
help="Get available configuration sources for a given experiment and output", metavar="OUTPUT_ID")
199+
parser.add_argument("--list-output-configuration-source", dest="list_output_configuration_source",
200+
help="Get configuration source for a given experiment, output and type", metavar="TYPE_ID")
201+
parser.add_argument("--create-output", dest="create_output", help="Create derived output provided by --param or --json-file", metavar="OUTPUT_ID")
202+
parser.add_argument("--delete-output", dest="delete_output", help="Delete derived output", metavar="DERIVED_OUTPUT_ID")
203+
parser.add_argument("--output-id", dest="output_id", help="The output ID")
204+
parser.add_argument("--json-file", dest="json_file", help="JSON file with parameter")
196205

197206
argcomplete.autocomplete(parser)
198207
options = parser.parse_args()
@@ -509,7 +518,6 @@ if __name__ == "__main__":
509518
sys.exit(1)
510519

511520

512-
513521
if options.load_configuration:
514522
if options.type_id is not None:
515523
if options.params is not None:
@@ -573,6 +581,94 @@ if __name__ == "__main__":
573581
else:
574582
print("No source typeId provided to delete this configuration")
575583

584+
if options.list_output_configuration_sources:
585+
if not options.uuid:
586+
print(TRACE_MISSING)
587+
sys.exit(1)
588+
589+
response = tsp_client.fetch_output_configuration_sources(options.uuid, options.list_output_configuration_sources)
590+
if response.status_code == 200:
591+
configuration_source_set = response.model
592+
if not configuration_source_set or len(configuration_source_set.configuration_source_set) == 0:
593+
print('No configuration sources available')
594+
else:
595+
print('Successfully listed configuration sources')
596+
print('-----------------------------------------')
597+
print(configuration_source_set.to_json())
598+
sys.exit(0)
599+
else:
600+
sys.exit(1)
601+
602+
if options.list_output_configuration_source:
603+
if not options.uuid:
604+
print(TRACE_MISSING)
605+
sys.exit(1)
606+
607+
if not options.output_id:
608+
print("No output ID provided")
609+
sys.exit(1)
610+
611+
response = tsp_client.fetch_output_configuration_source(options.uuid, options.output_id, options.list_output_configuration_source)
612+
if response.status_code == 200:
613+
configuration_source = response.model
614+
if not configuration_source:
615+
print('No configuration sources available')
616+
else:
617+
print('Successfully listed configuration sources')
618+
print('-----------------------------------------')
619+
print(configuration_source.to_json())
620+
sys.exit(0)
621+
else:
622+
sys.exit(1)
623+
624+
if options.create_output:
625+
if not options.uuid:
626+
print(TRACE_MISSING)
627+
sys.exit(1)
628+
629+
if not options.params and not options.json_file:
630+
print("No parameters provided with --param or --json-file")
631+
sys.exit(1)
632+
633+
params = {}
634+
if options.params is not None:
635+
params = __parse_params(options.params)
636+
637+
if options.json_file is not None:
638+
with open(options.json_file, 'r') as file:
639+
params = json.loads(file.read())
640+
641+
if (params is not None):
642+
response = tsp_client.create_derived_output(options.uuid, options.create_output, params)
643+
if response.status_code == 200:
644+
print('Successfully created derived output')
645+
print('-----------------------------------')
646+
print(response.model.to_json())
647+
sys.exit(0)
648+
else:
649+
sys.exit(1)
650+
else:
651+
print("Invalid params provided")
652+
sys.exit(1)
653+
654+
if options.delete_output:
655+
if not options.uuid:
656+
print(TRACE_MISSING)
657+
sys.exit(1)
658+
659+
if not options.output_id:
660+
print("No parent output ID provided")
661+
sys.exit(1)
662+
663+
response = tsp_client.delete_derived_output(options.uuid, options.output_id, options.delete_output)
664+
if response.status_code == 200:
665+
print('Successfully deleted derived output')
666+
print('-----------------------------------')
667+
print(response.model.to_json())
668+
sys.exit(0)
669+
else:
670+
sys.exit(1)
671+
576672
if options.get_health:
577673
response = tsp_client.fetch_health()
578674
if response.status_code == 200:

0 commit comments

Comments
 (0)