From 9ba58bde6883dee6e6e6034232af0ff57772b70b Mon Sep 17 00:00:00 2001 From: hernandezchu Date: Wed, 14 Jun 2023 17:20:28 +0200 Subject: [PATCH] New global option to adapt output format Change-Id: I1135848fe16082218739036bc21be594f0808b31 Signed-off-by: hernandezchu --- osmclient/cli_commands/ns.py | 25 ++++++++-- osmclient/cli_commands/vim.py | 25 ++++++++-- osmclient/cli_commands/vnf.py | 40 ++++++++++++---- osmclient/common/print_output.py | 80 ++++++++++++++++++++++++++++++++ osmclient/scripts/osm.py | 5 ++ requirements-test.txt | 2 +- requirements.in | 3 +- requirements.txt | 8 ++++ 8 files changed, 170 insertions(+), 18 deletions(-) create mode 100644 osmclient/common/print_output.py diff --git a/osmclient/cli_commands/ns.py b/osmclient/cli_commands/ns.py index f598e35..441ae05 100755 --- a/osmclient/cli_commands/ns.py +++ b/osmclient/cli_commands/ns.py @@ -15,6 +15,7 @@ import click from osmclient.common.exceptions import ClientException +from osmclient.common import print_output from osmclient.cli_commands import utils from prettytable import PrettyTable import yaml @@ -37,8 +38,15 @@ logger = logging.getLogger("osmclient") is_flag=True, help="get more details of the NS (project, vim, deployment status, configuration status.", ) +@click.option( + "-o", + default="table", + is_eager=True, + callback=print_output.validate_command_output, + help="adapt the output as table, yaml, csv, json, jsonpath", +) @click.pass_context -def ns_list(ctx, filter, long): +def ns_list(ctx, filter, long, o): """list all NS instances \b @@ -295,7 +303,8 @@ def ns_list(ctx, filter, long): ] ) table.align = "l" - print(table) + # print(table) + print_output.print_output(o, table.field_names, table._rows) print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"') print( 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"' @@ -310,8 +319,15 @@ def ns_list(ctx, filter, long): multiple=True, help="restricts the information to the fields in the filter", ) +@click.option( + "-o", + default="table", + is_eager=True, + callback=print_output.validate_command_output, + help="adapt the output as table, yaml, csv, json, jsonpath", +) @click.pass_context -def ns_show(ctx, name, literal, filter): +def ns_show(ctx, name, literal, filter, o): """shows the info of a NS instance NAME: name or ID of the NS instance @@ -337,7 +353,8 @@ def ns_show(ctx, name, literal, filter): if not filter or k in filter: table.add_row([k, utils.wrap_text(json.dumps(v, indent=2), width=100)]) table.align = "l" - print(table) + print_output.print_output(o, table.field_names, table._rows) + # print(table) @click.command(name="ns-create", short_help="creates a new Network Service instance") diff --git a/osmclient/cli_commands/vim.py b/osmclient/cli_commands/vim.py index ff1bcc6..b2a073d 100755 --- a/osmclient/cli_commands/vim.py +++ b/osmclient/cli_commands/vim.py @@ -14,6 +14,7 @@ # under the License. import click +from osmclient.common import print_output from osmclient.cli_commands import utils from prettytable import PrettyTable import yaml @@ -303,8 +304,15 @@ def vim_delete(ctx, name, force, wait): is_flag=True, help="get more details of the NS (project, vim, deployment status, configuration status.", ) +@click.option( + "-o", + default="table", + is_eager=True, + callback=print_output.validate_command_output, + help="get more details of the NS (project, vim, deployment status, configuration status.", +) @click.pass_context -def vim_list(ctx, filter, long): +def vim_list(ctx, filter, long, o): """list all VIM accounts""" logger.debug("") if filter: @@ -348,7 +356,8 @@ def vim_list(ctx, filter, long): [vim["name"], vim["uuid"], vim["_admin"].get("operationalState", "-")] ) table.align = "l" - print(table) + # print(table) + print_output.print_output(o, table.field_names, table._rows) @click.command(name="vim-show", short_help="shows the details of a VIM account") @@ -359,8 +368,15 @@ def vim_list(ctx, filter, long): help="restricts the information to the fields in the filter", ) @click.option("--literal", is_flag=True, help="print literally, no pretty table") +@click.option( + "-o", + default="table", + is_eager=True, + callback=print_output.validate_command_output, + help="adapt the output as table, yaml, csv, json, jsonpath", +) @click.pass_context -def vim_show(ctx, name, filter, literal): +def vim_show(ctx, name, filter, literal, o): """shows the details of a VIM account NAME: name or ID of the VIM account @@ -380,4 +396,5 @@ def vim_show(ctx, name, filter, literal): if not filter or k in filter: table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)]) table.align = "l" - print(table) + # print(table) + print_output.print_output(o, table.field_names, table._rows) diff --git a/osmclient/cli_commands/vnf.py b/osmclient/cli_commands/vnf.py index 6e10834..6c86ff7 100755 --- a/osmclient/cli_commands/vnf.py +++ b/osmclient/cli_commands/vnf.py @@ -15,6 +15,7 @@ import click from osmclient.common.exceptions import ClientException +from osmclient.common import print_output from osmclient.cli_commands import utils from prettytable import PrettyTable import yaml @@ -26,7 +27,7 @@ import logging logger = logging.getLogger("osmclient") -def vnf_list(ctx, ns, filter, long): +def vnf_list(ctx, ns, filter, long, o): logger.debug("") if ns or filter: if ns: @@ -96,7 +97,8 @@ def vnf_list(ctx, ns, filter, long): ] ) table.align = "l" - print(table) + # print(table) + print_output.print_output(o, table.field_names, table._rows) @click.command(name="vnf-list", short_help="list all NF instances") @@ -110,11 +112,18 @@ def vnf_list(ctx, ns, filter, long): help="restricts the list to the NF instances matching the filter.", ) @click.option("--long", is_flag=True, help="get more details") +@click.option( + "-o", + default="table", + is_eager=True, + callback=print_output.validate_command_output, + help="adapt the output as table, yaml, csv, json, jsonpath", +) @click.pass_context -def vnf_list1(ctx, ns, filter, long): +def vnf_list1(ctx, ns, filter, long, o): """list all NF instances""" logger.debug("") - vnf_list(ctx, ns, filter, long) + vnf_list(ctx, ns, filter, long, o) @click.command(name="nf-list", short_help="list all NF instances") @@ -128,8 +137,15 @@ def vnf_list1(ctx, ns, filter, long): help="restricts the list to the NF instances matching the filter.", ) @click.option("--long", is_flag=True, help="get more details") +@click.option( + "-o", + default="table", + # is_eager=True, + # callback=print_output.validate_command_output, + help="adapt the output as table, yaml, csv, json, jsonpath", +) @click.pass_context -def nf_list(ctx, ns, filter, long): +def nf_list(ctx, ns, filter, long, o): """list all NF instances \b @@ -178,7 +194,7 @@ def nf_list(ctx, ns, filter, long): --filter vnfd-ref=,vdur.ip-address= """ logger.debug("") - vnf_list(ctx, ns, filter, long) + vnf_list(ctx, ns, filter, long, o) @click.command(name="vnf-show", short_help="shows the info of a VNF instance") @@ -190,8 +206,15 @@ def nf_list(ctx, ns, filter, long): help="restricts the information to the fields in the filter", ) @click.option("--kdu", default=None, help="KDU name (whose status will be shown)") +@click.option( + "-o", + default="table", + is_eager=True, + callback=print_output.validate_command_output, + help="adapt the output as table, yaml, csv, json, jsonpath", +) @click.pass_context -def vnf_show(ctx, name, literal, filter, kdu): +def vnf_show(ctx, name, literal, filter, kdu, o): """shows the info of a VNF instance NAME: name or ID of the VNF instance @@ -272,4 +295,5 @@ def vnf_show(ctx, name, literal, filter, kdu): if not filter or k in filter: table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)]) table.align = "l" - print(table) + # print(table) + print_output.print_output(o, table.field_names, table._rows) diff --git a/osmclient/common/print_output.py b/osmclient/common/print_output.py new file mode 100644 index 0000000..e5bc7f7 --- /dev/null +++ b/osmclient/common/print_output.py @@ -0,0 +1,80 @@ +####################################################################################### +# Copyright ETSI Contributors and Others. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +####################################################################################### +import json +import yaml +import click +from prettytable import PrettyTable + +from jsonpath_ng import parse + + +def print_output(format, headers, rows): + if format == "table": + table = PrettyTable(headers) + for row in rows: + table.add_row(row) + print(table) + elif format == "json": + data = [] + for row in rows: + data.append(dict(zip(headers, row))) + json_data = json.dumps(data) + print(json_data) + elif format == "csv": + table = PrettyTable(headers) + for row in rows: + table.add_row(row) + print(table.get_csv_string()) + elif format == "yaml": + data = [] + for row in rows: + data.append(dict(zip(headers, row))) + yaml_string = yaml.safe_dump(data, sort_keys=False) + print(yaml_string) + elif format.startswith("jsonpath="): + # JSONPath expression + json_path_expression = format.partition("=")[-1] + json_path = parse(json_path_expression) + data = [] + for row in rows: + data.append(dict(zip(headers, row))) + # json_data = json.dumps(data) + # Apply JSONPath expression on the JSON object + results = [match.value for match in json_path.find(data)] + print(results) + else: + print("Valid values for -o are table, yaml, csv, json, jsonpath") + + +def validate_command_output(ctx, param, value): + allowed_commands = [ + "ns-list", + "ns-show", + "vim-list", + "vim-show", + "vnf-list", + "vnf-show", + ] # List of allowed commands + + if ctx.command.name in allowed_commands: + return value + # if param: + # print (value) + else: + raise click.BadParameter( + f'Option "{param.name}" is not allowed for this command.' + ) diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index 74bb84b..0a17948 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -78,6 +78,11 @@ from requests import RequestException count=True, help="increase verbosity (-v INFO, -vv VERBOSE, -vvv DEBUG)", ) +@click.option( + "-o", + "--output", + help="adapt output format (table, yaml, csv, json, jsonpath)", +) @click.option("--all-projects", default=None, is_flag=True, help="include all projects") @click.option( "--public/--no-public", diff --git a/requirements-test.txt b/requirements-test.txt index 295394e..54dab3b 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ####################################################################################### -coverage==7.2.5 +coverage==7.2.7 # via -r requirements-test.in mock==5.0.2 # via -r requirements-test.in diff --git a/requirements.in b/requirements.in index 02b5ed3..3da59a6 100644 --- a/requirements.in +++ b/requirements.in @@ -16,9 +16,10 @@ Click jinja2 +jsonpath_ng packaging prettytable python-magic pyyaml==5.4.1 -requests +requests==2.30.0 verboselogs diff --git a/requirements.txt b/requirements.txt index 500b7ad..8e53ce7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,14 +20,20 @@ charset-normalizer==3.1.0 # via requests click==8.1.3 # via -r requirements.in +decorator==5.1.1 + # via jsonpath-ng idna==3.4 # via requests jinja2==3.1.2 # via -r requirements.in +jsonpath-ng==1.5.3 + # via -r requirements.in markupsafe==2.1.3 # via jinja2 packaging==23.1 # via -r requirements.in +ply==3.11 + # via jsonpath-ng prettytable==3.7.0 # via -r requirements.in python-magic==0.4.27 @@ -36,6 +42,8 @@ pyyaml==5.4.1 # via -r requirements.in requests==2.30.0 # via -r requirements.in +six==1.16.0 + # via jsonpath-ng urllib3==2.0.2 # via requests verboselogs==1.7 -- 2.25.1