diff --git a/docs/changes.rst b/docs/changes.rst index 4dfd1606..8ed0ef41 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -28,6 +28,13 @@ Released: not yet archive, and added install tests for various installation methods including this one. (see issues #590, #591). +* Enhance output formats to allow an additional format group TEXT with + a single format ``text``. This format outputs the command result as a + text string to the console and is use for simple commands like + ``server interop`` that only output one piece of data. (see issue #594) + +**Cleanup** + **Known issues:** * See `list of open issues`_. diff --git a/docs/pywbemcli/cmdshelp.rst b/docs/pywbemcli/cmdshelp.rst index c7a129c2..0330b2a7 100644 --- a/docs/pywbemcli/cmdshelp.rst +++ b/docs/pywbemcli/cmdshelp.rst @@ -106,8 +106,8 @@ Help text for ``pywbemcli``: -o, --output-format FORMAT Output format for the command result. The default and allowed output formats are command specific. The default output_format is None so that each command selects its - own default format. FORMAT is either a table format: - [table|plain|simple|grid|psql|rst|html] or CIM object format: [mof|xml|repr|txt]. + own default format. FORMAT is: table formats: [table|plain|simple|grid|psql|rst|html]; + CIM object formats: [mof|xml|repr|txt]]; TEXT formats: [text]. -l, --log COMP[=DEST[:DETAIL]],... Enable logging of the WBEM operations, defined by a list of log configuration strings diff --git a/docs/pywbemcli/generaloptions.rst b/docs/pywbemcli/generaloptions.rst index 9f235e26..f4eda0c3 100644 --- a/docs/pywbemcli/generaloptions.rst +++ b/docs/pywbemcli/generaloptions.rst @@ -185,9 +185,9 @@ Controlling output formats Pywbemcli supports multiple output formats for command results by using the :ref:`--output-format general option`. -The output formats fall into three groups (table formats, CIM object formats, -and a tree format); however, not all formats are supported or applicable for all -commands. For more details, see :ref:`Output formats`. +The output formats fall into several groups (table formats, CIM object formats, +text formats, and a tree format); however, not all formats are supported or +applicable for all commands. For more details, see :ref:`Output formats`. .. _`Other miscellaneous general options`: @@ -838,7 +838,7 @@ Pywbemcli supports multiple output formats to present command results. The outpu format can be selected with the ``--output-format``/``-o`` option. The allowed output formats are different for the various command groups and commands. -The output formats fall into three groups: +The output formats fall into several groups: * **Table formats** - The :ref:`Table formats` format the result as a table with rows and columns. Many of the result types allow table formatted @@ -858,15 +858,19 @@ The output formats fall into three groups: commands that return CIM objects support these output formats. * **ASCII tree format** - The :ref:`ASCII tree format` formats the result - as a tree, using ASCII characters to represent the tree. The only command - supporting the ASCII tree format is ``class tree``, and it supports only - that one output format. The tree format is not supported by any other - command today. + as a tree, using ASCII characters to represent the tree to show the + hierarchial relationship between CIM classes. The only command supporting the + ASCII tree format is ``class tree``, and it supports only that one output + format. The tree format is not supported by any other command today. + +* **TEXT format** - The :ref:`Text formats` is used for commands that output + small quantites of text (ex. the interop namespace name) and that could be + used as part of a command line redirection. When an unsupported output format is specified for a command response, it is -rejected with an exception. For example, the command -``class enumerate`` only supports the CIM object formats and will generate an -exception if the command ``pywbemcli -o table class enumerate`` is entered. +rejected with an exception. For example, the command ``class enumerate`` only +supports the :ref:`CIM object formats` and will generate an exception if the +command ``pywbemcli -o table class enumerate`` is entered. .. index:: single: output formats @@ -927,15 +931,15 @@ table = table|plain|simple|grid|psql|rst|html +----------+---------------+----------+----------------+--------------------------------------------+ | | get | 'mof' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ -|server | brand | 'simple' | table | | +|server | brand | 'text' | text | Alternate is table format | +----------+---------------+----------+----------------+--------------------------------------------+ | |centralinsts | 'simple' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ | | info | 'simple' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ -| | interop | 'simple' | table | | +| | interop | 'text' | text | Alternate is table format | +----------+---------------+----------+----------------+--------------------------------------------+ -| | namespaces | 'simple' | table | | +| | namespaces | 'simple' | table | Alternate is text format | +----------+---------------+----------+----------------+--------------------------------------------+ | | profiles | 'simple' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ @@ -1196,6 +1200,31 @@ This shows a very simple mock repository with 4 classes where CIM_Foo is the top level in the hierarchy, CIM_Foo_sub and CIM_Foo_sub2 are its subclasses, and CIM_Foo_sub_sub is the subclass of CIM_Foo_sub. +.. index:: pair: output formats; text formats + +.. _`Text formats`: + +Text formats +"""""""""""" + +The TEXT format group outputs the data returned from the command as text +to the console without any formatting except for formatting lists and +comma separated strings. It is useful for use with data that might be +redirected to other commands or output that is simple enough that a single +line of output is sufficient. + +.. code-block:: text + + $ pywbemcli --mock-server tests/unit/testmock/wbemserver_mock.py -o table server namespaces + Server Namespaces: + Namespace Name + ---------------- + interop + + $ pywbemcli --mock-server tests/unit/testmock/wbemserver_mock.py -o text server namespaces + interop + + .. _`Pywbemcli defined logging`: diff --git a/pywbemtools/pywbemcli/_cmd_class.py b/pywbemtools/pywbemcli/_cmd_class.py index ee190dc0..87675030 100644 --- a/pywbemtools/pywbemcli/_cmd_class.py +++ b/pywbemtools/pywbemcli/_cmd_class.py @@ -30,7 +30,7 @@ from .pywbemcli import cli from ._common import display_cim_objects, filter_namelist, \ resolve_propertylist, CMD_OPTS_TXT, GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, \ - TABLE_FORMATS, format_table, process_invokemethod, \ + output_format_is_table, format_table, process_invokemethod, \ raise_pywbem_error_exception, warning_msg, validate_output_format from ._common_options import add_options, propertylist_option, \ names_only_option, include_classorigin_class_option, namespace_option, \ @@ -586,7 +586,8 @@ def get_format_group(context, options): # This accounts for the fact that the results of a summary can be # either table or simply a string output - if context.output_format and context.output_format in TABLE_FORMATS: + if context.output_format and \ + output_format_is_table(context.output_format): return ['TABLE'] # Temporary hack. We need another format group, i.e. txt or str @@ -801,7 +802,7 @@ def cmd_class_find(context, classname_glob, options): rows.extend(ns_rows) context.spinner_stop() - if context.output_format in TABLE_FORMATS: + if output_format_is_table(context.output_format): headers = ['Namespace', 'Classname'] click.echo( format_table(rows, headers, diff --git a/pywbemtools/pywbemcli/_cmd_server.py b/pywbemtools/pywbemcli/_cmd_server.py index cb15a348..934b33ec 100644 --- a/pywbemtools/pywbemcli/_cmd_server.py +++ b/pywbemtools/pywbemcli/_cmd_server.py @@ -30,7 +30,8 @@ from .pywbemcli import cli from ._common import format_table, raise_pywbem_error_exception, \ - validate_output_format, CMD_OPTS_TXT, GENERAL_OPTS_TXT, SUBCMD_HELP_TXT + validate_output_format, display_text, output_format_is_table, \ + CMD_OPTS_TXT, GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, DEFAULT_TABLE_FORMAT from ._common_options import add_options, help_option from ._click_extensions import PywbemcliGroup, PywbemcliCommand @@ -226,19 +227,23 @@ def cmd_server_namespaces(context, options): """ Display namespaces in the current WBEM server """ - output_format = validate_output_format(context.output_format, 'TABLE') + output_format = validate_output_format( + context.output_format, + ['TABLE', 'TEXT'], default_format=DEFAULT_TABLE_FORMAT) try: namespaces = context.wbem_server.namespaces namespaces.sort() context.spinner_stop() + if output_format_is_table(output_format): + # create list for each row + rows = [[ns] for ns in namespaces] - # create list for each row - rows = [[ns] for ns in namespaces] - - click.echo(format_table(rows, ['Namespace Name'], - title='Server Namespaces:', - table_format=output_format)) + click.echo(format_table(rows, ['Namespace Name'], + title='Server Namespaces:', + table_format=output_format)) + else: + display_text(", ".join(namespaces)) except Error as er: raise click.ClickException('{}: {}'.format(er.__class__.__name__, er)) @@ -248,17 +253,15 @@ def cmd_server_interop(context): """ Display interop namespace in the current WBEM server """ - output_format = validate_output_format(context.output_format, 'TABLE') + + output_format = validate_output_format(context.output_format, 'TEXT') try: interop_ns = context.wbem_server.interop_ns context.spinner_stop() - rows = [[interop_ns]] + display_text(interop_ns, output_format) - click.echo(format_table(rows, ['Namespace Name'], - title='Server Interop Namespace:', - table_format=output_format)) except Error as er: raise_pywbem_error_exception(er) @@ -267,16 +270,14 @@ def cmd_server_brand(context): """ Display product and version info of the current WBEM server """ - output_format = validate_output_format(context.output_format, 'TABLE') + output_format = validate_output_format(context.output_format, 'TEXT') try: brand = context.wbem_server.brand context.spinner_stop() - rows = [[brand]] - click.echo(format_table(rows, ['WBEM server brand'], - title='Server brand:', - table_format=output_format)) + display_text(brand, output_format) + except Error as er: raise_pywbem_error_exception(er) diff --git a/pywbemtools/pywbemcli/_common.py b/pywbemtools/pywbemcli/_common.py index 5dd54b41..a554cc15 100644 --- a/pywbemtools/pywbemcli/_common.py +++ b/pywbemtools/pywbemcli/_common.py @@ -23,6 +23,12 @@ import re from textwrap import fill from operator import itemgetter +from collections import namedtuple +try: + from collections import OrderedDict +except ImportError: + from ordereddict import OrderedDict # pylint: disable=import-error + import six import click import tabulate @@ -36,38 +42,63 @@ from ._cimvalueformatter import cimvalue_to_fmtd_string +# Definitions of the components of the help Usage line used +# by pywbemcli +GENERAL_OPTS_TXT = '[GENERAL-OPTIONS]' +CMD_OPTS_TXT = '[COMMAND-OPTIONS]' +SUBCMD_HELP_TXT = "COMMAND [ARGS] " + CMD_OPTS_TXT + +DEFAULT_MAX_CELL_WIDTH = 100 + ############################################################## # -# general option output format definitions and support for +# General option output format definitions and support for # validating output formats # ############################################################## +# Definition of the format keywords within each format group TABLE_FORMATS = ('table', 'plain', 'simple', 'grid', 'psql', 'rst', 'html') -CIM_OBJECT_OUTPUT_FORMATS = ('mof', 'xml', 'repr', 'txt') +CIM_OBJECT_FORMATS = ('mof', 'xml', 'repr', 'txt') +TEXT_FORMATS = ('text',) -OUTPUT_FORMATS = TABLE_FORMATS + CIM_OBJECT_OUTPUT_FORMATS +# Definition of the default format for each format group +DEFAULT_CIM_FORMAT = CIM_OBJECT_FORMATS[0] +DEFAULT_TABLE_FORMAT = TABLE_FORMATS[2] +DEFAULT_TEXT_FORMAT = TEXT_FORMATS[0] -DEFAULT_CIM_OUTPUT_FORMAT = 'mof' -DEFAULT_TABLE_OUTPUT_FORMAT = 'simple' -FORMAT_GROUPS = ('CIM', 'TABLE') +# Dictionary that relates group names to list of formats keywords for that +# group and the default format for that group. The order of the dictionary +# entry determines the priority of selecting formats. +GROUPVALUES = namedtuple('GROUPVALUES', 'keywords default') +OUTPUT_FORMAT_GROUPS = OrderedDict( + [('CIM', GROUPVALUES(CIM_OBJECT_FORMATS, DEFAULT_CIM_FORMAT)), + ('TABLE', GROUPVALUES(TABLE_FORMATS, DEFAULT_TABLE_FORMAT)), + ('TEXT', GROUPVALUES(TEXT_FORMATS, DEFAULT_TEXT_FORMAT))]) -# Definitions of the components of the help Usage line used -# by pywbemcli -GENERAL_OPTS_TXT = '[GENERAL-OPTIONS]' -CMD_OPTS_TXT = '[COMMAND-OPTIONS]' -SUBCMD_HELP_TXT = "COMMAND [ARGS] " + CMD_OPTS_TXT - -DEFAULT_MAX_CELL_WIDTH = 100 +# All of the format strings +OUTPUT_FORMATS = tuple(item for fmts in OUTPUT_FORMAT_GROUPS.values() + for item in fmts.keywords) def output_format_is_table(output_format): - """ Return True if output format is a table form""" + """ + Return True if output format is a table form. + + Parameters: + + output_format (:term:`string`): + String containing the output_format keyvalue. + + Returns: + True: if `output_format` is one of the Table format keyword choises + False: if `output_format` is not a Table format. + """ return output_format in TABLE_FORMATS def validate_output_format(output_format, valid_format_groups, - default_format=None,): + default_format=None): """ Tests for valid format groups and provides a default format if the context.output_format is None. @@ -75,70 +106,74 @@ def validate_output_format(output_format, valid_format_groups, Parameters: output_format (:term:`string` or None): - The output format string provided by input (i.e. ContextObj) or - None if there is no defined format for this command execution. + The output format string to be validated (normally provided by input + (i.e. ContextObj)) or None if there is no defined format for this + command execution. valid_format_groups (list of :term:`string` or :term:`string`): - One or more strings in a list where the allowed strings are: - 'CIM', 'TABLE'. An empty list implies any output group if valid. - A single string may be used to designate a single group + One or more strings in a list where the allowed strings are: 'TABLE', + 'CIM', or 'TEXT'. An empty list implies any output group if valid. A + single string may be used to designate a single group default_format (:term:`string` or None): One of the valid format definitions or None. The format must be in the - OUTPUT_FORMAT list. If None, the default format for the first group is - returned + OUTPUT_FORMATS list. If None, the default format for the first group in + `valid_format_groups` is returned. This format keyword is returned if + `output_format` is None. Returns: - :term:`string` containing output format to be used. + :term:`string` containing output format keyword to be used. Raises: click.ClickException if format invalid for command """ + # These are asserts because they are coding errors in the input parameters # for this function if isinstance(valid_format_groups, six.string_types): valid_format_groups = [valid_format_groups] - assert all(element in FORMAT_GROUPS for element in valid_format_groups) + + # Code error if this assert fails + assert all(element in OUTPUT_FORMAT_GROUPS for element in + valid_format_groups) + if default_format: assert default_format in OUTPUT_FORMATS - # If valid = 1 assure that default in that group. - # confirm default matches group. - + # Confirm default matches group. # CIM object type has priority over Table if output_format: - # Do invalid message here but really should be assert??? - if 'CIM' in valid_format_groups: - if output_format in CIM_OBJECT_OUTPUT_FORMATS: - return output_format - if 'TABLE' in valid_format_groups: - if output_format in TABLE_FORMATS: - return output_format + # Do invalid message here but really should be assert because this + # is a error in the data defined for the validate call. + for group, value in OUTPUT_FORMAT_GROUPS.items(): + if group in valid_format_groups: + if output_format in value.keywords: + return output_format if not valid_format_groups: return output_format - else: + + else: # output_format is None if default_format: return default_format if valid_format_groups: - if valid_format_groups[0] == 'CIM': - return DEFAULT_CIM_OUTPUT_FORMAT - if valid_format_groups[0] == 'TABLE': - return DEFAULT_TABLE_OUTPUT_FORMAT - return DEFAULT_CIM_OUTPUT_FORMAT - return DEFAULT_CIM_OUTPUT_FORMAT + for group, value in OUTPUT_FORMAT_GROUPS.items(): + if valid_format_groups[0] == group: + return value.default + return OUTPUT_FORMAT_GROUPS['CIM'].default + return OUTPUT_FORMAT_GROUPS['CIM'].default valid_formats = "" - err_msg = "not allowed for this command" + for name, value in OUTPUT_FORMAT_GROUPS.items(): + fmt_list = value.keywords + if name in valid_format_groups: + if valid_formats: + valid_formats += "; " + valid_formats += '{0} formats: "({1})"'.format( + name, '", "'.join(fmt_list)) - valid_formats = "" - if 'TABLE' in valid_format_groups: - valid_formats += 'TABLE formats ({})'.format(','.join(TABLE_FORMATS)) - if 'CIM' in valid_format_groups: - valid_formats += 'CIM Object formats ({})'.format( - ','.join(CIM_OBJECT_OUTPUT_FORMATS)) - - raise click.ClickException('Output format "{}" {}. Only {} allowed.'. - format(output_format, err_msg, valid_formats)) + raise click.ClickException('Output format "{}" not allowed for this ' + 'command. Only {} allowed.'. + format(output_format, valid_formats)) ###################################################################### @@ -416,7 +451,7 @@ def filter_namelist(pattern, name_list, ignore_case=True): raise click.ClickException('Regex compile error. Regex={}. Er: {}: {}' .format(regex, ex.__class__.__name__, ex)) - new_list = [n for n in name_list for m in[compiled_regex.match(n)] if m] + new_list = [n for n in name_list for m in [compiled_regex.match(n)] if m] return new_list @@ -1027,7 +1062,7 @@ def display_cim_objects(context, cim_objects, output_format, summary=False, if isinstance(cim_objects, (list, tuple)): # Table format output is processed as a group - if output_format in TABLE_FORMATS: + if output_format_is_table(output_format): _print_objects_as_table(context, cim_objects, output_format) else: # Call to display each object @@ -1039,7 +1074,7 @@ def display_cim_objects(context, cim_objects, output_format, summary=False, # Display a single item. object_ = cim_objects # This allows passing single objects to the table formatter (i.e. not lists) - if output_format in TABLE_FORMATS: + if output_format_is_table(output_format): _print_objects_as_table(context, [object_], output_format) elif output_format == 'mof': try: @@ -1149,6 +1184,14 @@ def get_wbemurikeys(obj): return wbem_uri_keys +def display_text(text, output_format=None): # pylint: disable=unused-argument + """ + Display the text output format. Currently this simply outputs to + click.echo + """ + click.echo(text) + + class NoCaseList(object): """ This class simplifies working with lists of strings that are to be tested @@ -1604,7 +1647,7 @@ def format_table(rows, headers, title=None, table_format='simple', table_format = 'table' if table_format == 'table': table_format = 'psql' - if table_format not in TABLE_FORMATS: + if not output_format_is_table(table_format): raise click.ClickException('Invalid table format {}.' .format(table_format)) diff --git a/pywbemtools/pywbemcli/pywbemcli.py b/pywbemtools/pywbemcli/pywbemcli.py index b4d2a71a..c113ebc6 100644 --- a/pywbemtools/pywbemcli/pywbemcli.py +++ b/pywbemtools/pywbemcli/pywbemcli.py @@ -35,8 +35,7 @@ DEFAULT_LOG_DETAIL_LEVEL from ._context_obj import ContextObj, display_click_context -from ._common import GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, TABLE_FORMATS, \ - CIM_OBJECT_OUTPUT_FORMATS +from ._common import GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, OUTPUT_FORMAT_GROUPS from ._common_options import add_options, help_option from ._pywbem_server import PywbemServer from .config import DEFAULT_NAMESPACE, \ @@ -215,10 +214,11 @@ 'specific. ' 'The default output_format is None so that each command ' 'selects its own default format. ' - 'FORMAT is either a table format: [{tb}] or CIM object ' - 'format: [{ob}].'. - format(tb='|'.join(TABLE_FORMATS), - ob='|'.join(CIM_OBJECT_OUTPUT_FORMATS))) + 'FORMAT is: table formats: [{tb}]; CIM object ' + 'formats: [{ob}]]; TEXT formats: [{tx}].'. + format(tb='|'.join(OUTPUT_FORMAT_GROUPS['TABLE'][0]), + ob='|'.join(OUTPUT_FORMAT_GROUPS['CIM'][0]), + tx='|'.join(OUTPUT_FORMAT_GROUPS['TEXT'][0]))) @click.option('-l', '--log', type=str, metavar='COMP[=DEST[:DETAIL]],...', # defaulted in code envvar=PywbemServer.log_envvar, diff --git a/tests/unit/all_types_method_mock.py b/tests/unit/all_types_method_mock.py index a8a2f87d..888c4c82 100644 --- a/tests/unit/all_types_method_mock.py +++ b/tests/unit/all_types_method_mock.py @@ -6,7 +6,7 @@ # test that GLOBALS exist assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() def alltypes_callback(conn, object_name, methodname, **params): diff --git a/tests/unit/simple_mock_invokemethod.py b/tests/unit/simple_mock_invokemethod.py index 61864800..efc0dfa7 100644 --- a/tests/unit/simple_mock_invokemethod.py +++ b/tests/unit/simple_mock_invokemethod.py @@ -6,7 +6,7 @@ # test that GLOBALS exist assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() def fuzzy_callback(conn, object_name, methodname, **params): diff --git a/tests/unit/simple_python_mock_script.py b/tests/unit/simple_python_mock_script.py index 819ae263..b386c3bf 100644 --- a/tests/unit/simple_python_mock_script.py +++ b/tests/unit/simple_python_mock_script.py @@ -11,7 +11,7 @@ # test that GLOBALS exist assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() def build_classes(): diff --git a/tests/unit/test_class_cmds.py b/tests/unit/test_class_cmds.py index 6d3e1604..25e70a6b 100644 --- a/tests/unit/test_class_cmds.py +++ b/tests/unit/test_class_cmds.py @@ -681,7 +681,7 @@ class TST_MemberOfFamilyCollection { ['Verify class command enumerate table output fails).', {'args': ['enumerate'], 'general': ['--output-format', 'table']}, - {'stderr': ['CIM Object formats ', 'not allowed'], + {'stderr': ['Output format "table"', 'not allowed', 'Only CIM formats:'], 'rc': 1, 'test': 'innows'}, SIMPLE_MOCK_FILE, OK], @@ -915,7 +915,7 @@ class TST_MemberOfFamilyCollection { ['Verify class command enumerate table output fails).', {'args': ['get', 'CIM_Foo'], 'general': ['--output-format', 'table']}, - {'stderr': ['CIM Object formats ', 'not allowed'], + {'stderr': ['Output format "table" ', 'not allowed', 'Only CIM formats:'], 'rc': 1, 'test': 'innows'}, SIMPLE_MOCK_FILE, OK], @@ -1398,7 +1398,7 @@ class TST_MemberOfFamilyCollection { ['Verify class command refereces table output fails).', {'args': ['associators', 'TST_Person'], 'general': ['--output-format', 'table']}, - {'stderr': ['CIM Object formats ', 'not allowed'], + {'stderr': ['Output format "table" ', 'not allowed', 'Only CIM formats:'], 'rc': 1, 'test': 'innows'}, SIMPLE_MOCK_FILE, OK], diff --git a/tests/unit/test_general_options.py b/tests/unit/test_general_options.py index a465f45f..14a5e8df 100644 --- a/tests/unit/test_general_options.py +++ b/tests/unit/test_general_options.py @@ -41,8 +41,8 @@ # pylint: disable=line-too-long GENERAL_HELP = """Usage: pywbemcli [GENERAL-OPTIONS] COMMAND [ARGS] [COMMAND-OPTIONS] - Pywbemcli is a command line WBEM client that uses the DMTF CIM-XML protocol to communicate with WBEM servers. - Pywbemcli can: + Pywbemcli is a command line WBEM client that uses the DMTF CIM-XML protocol + to communicate with WBEM servers. Pywbemcli can: * Manage the information in WBEM servers CIM objects using the operations defined in the DMTF specification. It can manage CIM @@ -58,92 +58,146 @@ * Maintain a persistent list of named connections to WBEM servers and execute operations on them by name. - Pywbemcli implements command groups and commands to execute the CIM-XML operations defined by the DMTF CIM - Operations Over HTTP specification (DSP0200). + Pywbemcli implements command groups and commands to execute the CIM-XML + operations defined by the DMTF CIM Operations Over HTTP specification + (DSP0200). - The general options shown below can also be specified on any of the commands, positioned right after the 'pywbemcli' - command name. + The general options shown below can also be specified on any of the + commands, positioned right after the 'pywbemcli' command name. - The width of help texts of this command can be set with the PYWBEMCLI_TERMWIDTH environment variable. + The width of help texts of this command can be set with the + PYWBEMCLI_TERMWIDTH environment variable. For more detailed documentation, see: https://pywbemtools.readthedocs.io/en/stable/ General Options: - -n, --name NAME Use the WBEM server defined by the WBEM connection definition NAME. This option is - mutually exclusive with the --server and --mock-server options, since each defines a - WBEM server. Default: EnvVar PYWBEMCLI_NAME, or none. - - -m, --mock-server FILE Use a mock WBEM server that is automatically created in pywbemcli and populated with - CIM objects that are defined in the specified MOF file or Python script file. See the - pywbemcli documentation for more information. This option may be specified multiple - times, and is mutually exclusive with the --server and --name options, since each - defines a WBEM server. Default: EnvVar PYWBEMCLI_MOCK_SERVER, or none. - - -s, --server URL Use the WBEM server at the specified URL with format: [SCHEME://]HOST[:PORT]. SCHEME - must be "https" (default) or "http". HOST is a short or long hostname or literal - IPV4/v6 address. PORT defaults to 5989 for https and 5988 for http. This option is - mutually exclusive with the --mock-server and --name options, since each defines a - WBEM server. Default: EnvVar PYWBEMCLI_SERVER, or none. - - -u, --user TEXT User name for the WBEM server. Default: EnvVar PYWBEMCLI_USER, or none. - -p, --password TEXT Password for the WBEM server. Default: EnvVar PYWBEMCLI_PASSWORD, or prompted for if - --user specified. - - --verify / --no-verify If --verify, client verifies the X.509 server certificate presented by the WBEM server - during TLS/SSL handshake. If --no-verify client bypasses verification. Default: EnvVar + -n, --name NAME Use the WBEM server defined by the WBEM + connection definition NAME. This option is + mutually exclusive with the --server and + --mock-server options, since each defines a + WBEM server. Default: EnvVar PYWBEMCLI_NAME, + or none. + + -m, --mock-server FILE Use a mock WBEM server that is automatically + created in pywbemcli and populated with CIM + objects that are defined in the specified MOF + file or Python script file. See the pywbemcli + documentation for more information. This + option may be specified multiple times, and is + mutually exclusive with the --server and + --name options, since each defines a WBEM + server. Default: EnvVar PYWBEMCLI_MOCK_SERVER, + or none. + + -s, --server URL Use the WBEM server at the specified URL with + format: [SCHEME://]HOST[:PORT]. SCHEME must be + "https" (default) or "http". HOST is a short + or long hostname or literal IPV4/v6 address. + PORT defaults to 5989 for https and 5988 for + http. This option is mutually exclusive with + the --mock-server and --name options, since + each defines a WBEM server. Default: EnvVar + PYWBEMCLI_SERVER, or none. + + -u, --user TEXT User name for the WBEM server. Default: EnvVar + PYWBEMCLI_USER, or none. + + -p, --password TEXT Password for the WBEM server. Default: EnvVar + PYWBEMCLI_PASSWORD, or prompted for if --user + specified. + + --verify / --no-verify If --verify, client verifies the X.509 server + certificate presented by the WBEM server + during TLS/SSL handshake. If --no-verify + client bypasses verification. Default: EnvVar PYWBEMCLI_VERIFY, or "--verify". - --ca-certs CACERTS Certificates to be used for validating the certificate presented by the WBEM server - during TLS/SSL handshake: FILE: Use the certs in the specified PEM file; DIR: Use the - certs in the PEM files in the specified directory; "certifi" (pywbem 1.0 or later): - Use the certs provided by the certifi Python package; Default: EnvVar - PYWBEMCLI_CA_CERTS, or "certifi" (pywbem 1.0 or later), or the certs in the PEM files - in the first existing directory from from a list of system directories (pywbem before - 1.0). - - -c, --certfile FILE Path name of a PEM file containing a X.509 client certificate that is used to enable - TLS/SSL 2-way authentication by presenting the certificate to the WBEM server during - TLS/SSL handshake. Default: EnvVar PYWBEMCLI_CERTFILE, or none. - - -k, --keyfile FILE Path name of a PEM file containing a X.509 private key that belongs to the certificate - in the --certfile file. Not required if the private key is part of the --certfile - file. Default: EnvVar PYWBEMCLI_KEYFILE, or none. - - -t, --timeout INT Client-side timeout in seconds for operations with the WBEM server. Default: EnvVar + --ca-certs CACERTS Certificates to be used for validating the + certificate presented by the WBEM server + during TLS/SSL handshake: FILE: Use the certs + in the specified PEM file; DIR: Use the certs + in the PEM files in the specified directory; + "certifi" (pywbem 1.0 or later): Use the certs + provided by the certifi Python package; + Default: EnvVar PYWBEMCLI_CA_CERTS, or + "certifi" (pywbem 1.0 or later), or the certs + in the PEM files in the first existing + directory from from a list of system + directories (pywbem before 1.0). + + -c, --certfile FILE Path name of a PEM file containing a X.509 + client certificate that is used to enable + TLS/SSL 2-way authentication by presenting the + certificate to the WBEM server during TLS/SSL + handshake. Default: EnvVar PYWBEMCLI_CERTFILE, + or none. + + -k, --keyfile FILE Path name of a PEM file containing a X.509 + private key that belongs to the certificate in + the --certfile file. Not required if the + private key is part of the --certfile file. + Default: EnvVar PYWBEMCLI_KEYFILE, or none. + + -t, --timeout INT Client-side timeout in seconds for operations + with the WBEM server. Default: EnvVar PYWBEMCLI_TIMEOUT, or 30. - -U, --use-pull [yes|no|either] Determines whether pull operations are used for operations with the WBEM server that - return lists of instances, as follows: "yes" uses pull operations and fails if not - supported by the server; "no" uses traditional operations; "either" (default) uses - pull operations if supported by the server, and otherwise traditional operations. - Default: EnvVar PYWBEMCLI_USE_PULL, or "either". - - --pull-max-cnt INT Maximum number of instances to be returned by the WBEM server in each open or pull - response, if pull operations are used. This is a tuning parameter that does not affect - the external behavior of the commands. Default: EnvVar PYWBEMCLI_PULL_MAX_CNT, or 1000 + -U, --use-pull [yes|no|either] Determines whether pull operations are used + for operations with the WBEM server that + return lists of instances, as follows: "yes" + uses pull operations and fails if not + supported by the server; "no" uses traditional + operations; "either" (default) uses pull + operations if supported by the server, and + otherwise traditional operations. Default: + EnvVar PYWBEMCLI_USE_PULL, or "either". + + --pull-max-cnt INT Maximum number of instances to be returned by + the WBEM server in each open or pull response, + if pull operations are used. This is a tuning + parameter that does not affect the external + behavior of the commands. Default: EnvVar + PYWBEMCLI_PULL_MAX_CNT, or 1000 + + -T, --timestats Show time statistics of WBEM server + operations. - -T, --timestats Show time statistics of WBEM server operations. -d, --default-namespace NAMESPACE - Default namespace, to be used when commands do not specify the --namespace command - option. Default: EnvVar PYWBEMCLI_DEFAULT_NAMESPACE, or root/cimv2. - - -o, --output-format FORMAT Output format for the command result. The default and allowed output formats are - command specific. The default output_format is None so that each command selects its - own default format. FORMAT is either a table format: - [table|plain|simple|grid|psql|rst|html] or CIM object format: [mof|xml|repr|txt]. + Default namespace, to be used when commands do + not specify the --namespace command option. + Default: EnvVar PYWBEMCLI_DEFAULT_NAMESPACE, + or root/cimv2. + + -o, --output-format FORMAT Output format for the command result. The + default and allowed output formats are command + specific. The default output_format is None so + that each command selects its own default + format. FORMAT is: table formats: + [table|plain|simple|grid|psql|rst|html]; CIM + object formats: [mof|xml|repr|txt]]; TEXT + formats: [text]. -l, --log COMP[=DEST[:DETAIL]],... - Enable logging of the WBEM operations, defined by a list of log configuration strings - with: COMP: [api|http|all]; DEST: [file|stderr], default: file; DETAIL: - [all|paths|summary], default: all. Default: EnvVar PYWBEMCLI_LOG, or all. + Enable logging of the WBEM operations, defined + by a list of log configuration strings with: + COMP: [api|http|all]; DEST: [file|stderr], + default: file; DETAIL: [all|paths|summary], + default: all. Default: EnvVar PYWBEMCLI_LOG, + or all. + + -v, --verbose / --no-verbose Display extra information about the + processing. + + --pdb Pause execution in the built-in pdb debugger + just before executing the command within + pywbemcli. Default: EnvVar PYWBEMCLI_PDB, or + false. - -v, --verbose / --no-verbose Display extra information about the processing. - --pdb Pause execution in the built-in pdb debugger just before executing the command within - pywbemcli. Default: EnvVar PYWBEMCLI_PDB, or false. + --version Show the version of this command and the + pywbem package. - --version Show the version of this command and the pywbem package. -h, --help Show this help message. Commands: diff --git a/tests/unit/test_instance_cmds.py b/tests/unit/test_instance_cmds.py index bdf90365..08a0ed29 100644 --- a/tests/unit/test_instance_cmds.py +++ b/tests/unit/test_instance_cmds.py @@ -971,8 +971,17 @@ 'test': 'regex'}, SIMPLE_MOCK_FILE, OK], + ['Verify instance command get with -o txt fails', + {'args': ['enumerate', 'CIM_Foo'], + 'general': ['--output-format', 'text']}, + {'stderr': ['Output format "text"', 'not allowed', 'Only CIM formats:', + 'TABLE formats:'], + 'rc': 1, + 'test': 'innows'}, + SIMPLE_MOCK_FILE, OK], + # - # exhaustive tests for INSTANCENAME parameter (using instance get command) + # Exhaustive tests for INSTANCENAME parameter (using instance get command) # including variations on --namespace and --key options. # @@ -1484,7 +1493,7 @@ [ASSOC_MOCK_FILE, MOCK_PROMPT_0_FILE], OK], # - # get command errors + # instance get command errors # ['instance command get error. no classname', ['get'], @@ -1522,6 +1531,15 @@ 'test': 'lines'}, SIMPLE_MOCK_FILE, OK], + ['Verify instance command get with -o txt fails', + {'args': ['get', 'CIM_Foo.InstanceID="CIM_Foo1"', '--lo'], + 'general': ['--output-format', 'text']}, + {'stderr': ['Output format "text"', 'not allowed', 'Only CIM formats:', + 'TABLE formats:'], + 'rc': 1, + 'test': 'innows'}, + SIMPLE_MOCK_FILE, OK], + # # instance create command # @@ -2234,6 +2252,15 @@ 'test': 'regex'}, ASSOC_MOCK_FILE, OK], + ['Verify instance command references with --output-format text', + {'args': ['references', 'CIM_Foo.InstanceID="CIM_Foo1"'], + 'general': ['--output-format', 'text']}, + {'stderr': ['Output format "text"', 'not allowed', 'Only CIM formats:', + 'TABLE formats:'], + 'rc': 1, + 'test': 'innows'}, + SIMPLE_MOCK_FILE, OK], + # TODO add more invalid references tests # @@ -2661,35 +2688,35 @@ {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree no namepace', ['shrub', 'TST_Person.name="Mike"', '--fullpath'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree no namepace. short path', ['shrub', 'TST_Person.name="Mike"'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree with --role option 1', ['shrub', 'TST_Person.name="Mike"', '--role', 'parent'], {'stdout': SIMPLE_SHRUB_TREE_ROLE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree with --role option 2', ['shrub', 'TST_Person.name="Mike"', '--role', 'Parent'], {'stdout': SIMPLE_SHRUB_TREE_ROLE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --role option err', ['shrub', 'TST_Person.name="Mike"', '--role', 'parentx'], @@ -2698,21 +2725,21 @@ 'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option1', ['shrub', 'TST_Person.name="Mike"', '--assoc-class', 'TST_Lineage'], {'stdout': SIMPLE_SHRUB_TREE_ASSOC_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option2', ['shrub', 'TST_Person.name="Mike"', '--assoc-class', 'tst_lineage'], {'stdout': SIMPLE_SHRUB_TREE_ASSOC_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option err', ['shrub', 'TST_Person.name="Mike"', '--assoc-class', 'TST_Lineagex'], @@ -2720,28 +2747,28 @@ 'stderr': "WARNING", 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --result-class option1', ['shrub', 'TST_Person.name="Mike"', '--result-class', 'TST_Person'], {'stdout': SIMPLE_SHRUB_TREE_RESULT_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option2', ['shrub', 'TST_Person.name="Mike"', '--result-class', 'tst_person'], {'stdout': SIMPLE_SHRUB_TREE_RESULT_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree with --assoc-class error', ['shrub', 'TST_Person.name="Mike"', '--result-class', 'TST_Personx'], {'stdout': SIMPLE_SHRUB_TREE_RESULT_CLASS_NO_RTN, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple table request w ns', {'args': ['shrub', 'root/cimv2:TST_Person.name="Mike"', @@ -2750,7 +2777,7 @@ {'stdout': SIMPLE_SHRUB_TABLE1, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tableno ns in request', {'args': ['shrub', 'root/cimv2:TST_Person.name="Mike"'], @@ -2758,21 +2785,21 @@ {'stdout': SIMPLE_SHRUB_TABLE1, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with namespace', ['shrub', 'TST_Person.name="Mike"', '--fullpath'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree without namespace', ['shrub', 'TST_Person.name="Mike"', '--fullpath'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], # Test with a complex (ternary) association # TODO: Fix the following failed tests. Some minor diff in table I have @@ -2793,7 +2820,7 @@ {'stdout': COMPLEX_SHRUB_TABLE_SUMMARY, 'rc': 0, 'test': 'innows'}, - COMPLEX_ASSOC_MODEL, RUN], + COMPLEX_ASSOC_MODEL, OK], ['Verify instance subcommand shrub, complex tree', {'args': ['shrub', 'TST_EP.InstanceID=1', '--fullpath'], @@ -2801,7 +2828,7 @@ {'stdout': COMPLEX_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - COMPLEX_ASSOC_MODEL, RUN], + COMPLEX_ASSOC_MODEL, OK], # TODO test results if we have keys that get hidden. This will require # a more complex model with CreationClassName, etc. in paths. diff --git a/tests/unit/test_server_cmds.py b/tests/unit/test_server_cmds.py index 433f0e31..dfc6c714 100644 --- a/tests/unit/test_server_cmds.py +++ b/tests/unit/test_server_cmds.py @@ -200,15 +200,20 @@ # # Verify the individual commands returning data # + ['Verify server command interop default output', + {'args': ['interop'], + 'general': ['-d', 'interop']}, + {'stdout': ['interop'], + 'rc': 0, + 'test': 'innows'}, + MOCK_SERVER_MODEL, OK], + ['Verify server command interop', {'args': ['interop'], - 'general': ['-d', 'interop', '-o', 'simple']}, - {'stdout': ['Server Interop Namespace:', - 'Namespace Name', - '----------------', - 'interop'], + 'general': ['-d', 'interop', '-o', 'text']}, + {'stdout': ['interop'], 'rc': 0, - 'test': 'lines'}, + 'test': 'innows'}, MOCK_SERVER_MODEL, OK], ['Verify server command namespaces', @@ -222,27 +227,37 @@ 'test': 'lines'}, MOCK_SERVER_MODEL, OK], - # TODO: Remove this test once removal of --sort option is agreed. - ['Verify server command namespaces with sort option', - {'args': ['namespaces', '-s'], - 'general': ['-d', 'interop', '-o', 'simple']}, - {'stdout': ['Server Namespaces:', - 'Namespace Name', - '----------------', - 'interop'], + ['Verify server command namespaces, text output', + {'args': ['namespaces'], + 'general': ['-d', 'interop', '-o', 'text']}, + {'stdout': ['interop'], 'rc': 0, 'test': 'lines'}, - MOCK_SERVER_MODEL, FAIL], + MOCK_SERVER_MODEL, OK], + + ['Verify server command namespaces with sort option', + {'args': ['namespaces'], + 'general': ['-d', 'interop']}, + {'stdout': ['interop'], + 'rc': 0, + 'test': 'innows'}, + MOCK_SERVER_MODEL, OK], ['Verify server command brand', {'args': ['brand'], - 'general': ['-d', 'interop', '-o', 'simple']}, - {'stdout': ['Server brand:', - 'WBEM server brand', - '-------------------', - 'OpenPegasus'], + 'general': ['-d', 'interop']}, + {'stdout': ['OpenPegasus'], 'rc': 0, - 'test': 'lines'}, + 'test': 'innows'}, + MOCK_SERVER_MODEL, OK], + + + ['Verify server command brand with --output table fails', + {'args': ['brand'], + 'general': ['-d', 'interop', '-o', 'simple']}, + {'stderr': ['Output format "simple" not allowed for this command'], + 'rc': 1, + 'test': 'innows'}, MOCK_SERVER_MODEL, OK], ['Verify server command profiles', diff --git a/tests/unit/testmock/wbemserver_mock.py b/tests/unit/testmock/wbemserver_mock.py index 0b44fc49..06c068ee 100644 --- a/tests/unit/testmock/wbemserver_mock.py +++ b/tests/unit/testmock/wbemserver_mock.py @@ -20,7 +20,7 @@ # test that GLOBALS exist. They should be provided by pywbemcli assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() # Location of DMTF schema directory used by all tests.