New global option to adapt output format 31/13531/5
authorhernandezchu <chernandez@cttc.es>
Wed, 14 Jun 2023 15:20:28 +0000 (17:20 +0200)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Fri, 23 Jun 2023 09:06:27 +0000 (11:06 +0200)
Change-Id: I1135848fe16082218739036bc21be594f0808b31
Signed-off-by: hernandezchu <chernandez@cttc.es>
osmclient/cli_commands/ns.py
osmclient/cli_commands/vim.py
osmclient/cli_commands/vnf.py
osmclient/common/print_output.py [new file with mode: 0644]
osmclient/scripts/osm.py
requirements-test.txt
requirements.in
requirements.txt

index f598e35..441ae05 100755 (executable)
@@ -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")
index ff1bcc6..b2a073d 100755 (executable)
@@ -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)
index 6e10834..6c86ff7 100755 (executable)
@@ -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=<VNFD_NAME>,vdur.ip-address=<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 (file)
index 0000000..e5bc7f7
--- /dev/null
@@ -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.'
+        )
index 74bb84b..0a17948 100755 (executable)
@@ -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",
index 295394e..54dab3b 100644 (file)
@@ -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
index 02b5ed3..3da59a6 100644 (file)
 
 Click
 jinja2
+jsonpath_ng
 packaging
 prettytable
 python-magic
 pyyaml==5.4.1
-requests
+requests==2.30.0
 verboselogs
index 500b7ad..8e53ce7 100644 (file)
@@ -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