python-openstackclient-5.2.0/0000775000175000017500000000000013637121160016245 5ustar zuulzuul00000000000000python-openstackclient-5.2.0/doc/0000775000175000017500000000000013637121160017012 5ustar zuulzuul00000000000000python-openstackclient-5.2.0/doc/Makefile0000664000175000017500000001126413637121057020463 0ustar zuulzuul00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html pdf dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " pdf to make pdf with rst2pdf" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." pdf: $(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) $(BUILDDIR)/pdf @echo @echo "Build finished. The PDFs are in $(BUILDDIR)/pdf." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/NebulaDocs.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/NebulaDocs.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/NebulaDocs" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/NebulaDocs" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." python-openstackclient-5.2.0/doc/source/0000775000175000017500000000000013637121160020312 5ustar zuulzuul00000000000000python-openstackclient-5.2.0/doc/source/index.rst0000664000175000017500000000450213637121057022161 0ustar zuulzuul00000000000000=============== OpenStackClient =============== OpenStackClient (aka OSC) is a command-line client for OpenStack that brings the command set for Compute, Identity, Image, Object Storage and Block Storage APIs together in a single shell with a uniform command structure. Using OpenStackClient --------------------- .. toctree:: :maxdepth: 2 cli/index configuration/index Getting Started --------------- * Try :ref:`some commands ` * Read the source `on OpenStack's Git server`_ * Install OpenStackClient from `PyPi`_ or a `tarball`_ Release Notes ------------- .. toctree:: :maxdepth: 1 Release Notes Contributor Documentation ------------------------- .. toctree:: :maxdepth: 2 contributor/index Project Goals ------------- * Use the OpenStack Python API libraries, extending or replacing them as required * Use a consistent naming and structure for commands and arguments * Provide consistent output formats with optional machine parseable formats * Use a single-binary approach that also contains an embedded shell that can execute multiple commands on a single authentication (see libvirt's virsh for an example) * Independence from the OpenStack project names; only API names are referenced (to the extent possible) Contributing ============ OpenStackClient utilizes all of the usual OpenStack processes and requirements for contributions. The code is hosted `on OpenStack's Git server`_. `Bug reports`_ may be submitted to the :code:`python-openstackclient` `Storyboard project`_. Code may be submitted to the :code:`openstack/python-openstackclient` project using `Gerrit`_. Developers may also be found in the `IRC channel`_ ``#openstack-sdks``. .. _`on OpenStack's Git server`: https://opendev.org/openstack/python-openstackclient/ .. _`Storyboard project`: https://storyboard.openstack.org/#!/project/openstack/python-openstackclient .. _Gerrit: http://docs.openstack.org/infra/manual/developers.html#development-workflow .. _Bug reports: https://storyboard.openstack.org/#!/project/975 .. _PyPi: https://pypi.org/project/python-openstackclient .. _tarball: http://tarballs.openstack.org/python-openstackclient .. _IRC channel: https://wiki.openstack.org/wiki/IRC Indices and Tables ================== * :ref:`genindex` * :ref:`search` python-openstackclient-5.2.0/doc/source/contributor/0000775000175000017500000000000013637121160022664 5ustar zuulzuul00000000000000python-openstackclient-5.2.0/doc/source/contributor/index.rst0000664000175000017500000000043413637121057024533 0ustar zuulzuul00000000000000=========================== Contributor Documentation =========================== .. toctree:: :maxdepth: 1 developing command-beta command-options command-wrappers command-errors command-logs specs/commands plugins humaninterfaceguide api/modules python-openstackclient-5.2.0/doc/source/contributor/command-logs.rst0000664000175000017500000000407213637121057026006 0ustar zuulzuul00000000000000============ Command Logs ============ Logger usage in OpenStackClient is not exactly the same as those in other OpenStack projects. The following basic rules should be followed. 1. OpenStackClient uses python standard logging library instead of oslo.log so that it will depend on oslo as little as possible. 2. All logs except debug log need to be translated. The log message strings that need to be translated should follow the rule of i18n guidelines: https://docs.openstack.org/oslo.i18n/latest/user/guidelines.html 3. There are mainly two kinds of logs in OpenStackClient: command specific log and general log. Use different logger to record them. The examples below will show the detail. Command specific log ==================== Command specific logs are those messages that used to record info, warning and error generated from a specific command. OpenStackClient uses the logger of the module the command belongs to to record the command specific logs. Example ~~~~~~~ This example shows how to log command specific logs in OpenStackClient. .. code-block:: python import logging from openstackclient.i18n import _ LOG = logging.getLogger(__name__) # Get the logger of this module ## ... LOG.error(_("Error message")) LOG.warning(_("Warning message")) LOG.info(_("Info message")) LOG.debug("Debug message") # Debug messages do not need to be translated ## ... General log =========== General logs are those messages that not specific to any single command. Use the logger of ``openstackclient.shell`` to record them. In each command class, we can simply get this logger by ``self.app.log``. Example ~~~~~~~ This example shows how to log general logs in OpenStackClient. .. code-block:: python from openstackclient.i18n import _ ## ... self.app.log.error(_("Error message")) self.app.log.warning(_("Warning message")) self.app.log.info(_("Info message")) self.app.log.debug("Debug message") # Debug messages do not need to be translated ## ... python-openstackclient-5.2.0/doc/source/contributor/command-beta.rst0000664000175000017500000000554513637121057025763 0ustar zuulzuul00000000000000.. _command-beta: ============ Command Beta ============ OpenStackClient releases do not always coincide with OpenStack releases. This creates challenges when developing new OpenStackClient commands for the current OpenStack release under development since there may not be an official release of the REST API enhancements necessary for the command. In addition, backwards compatibility may not be guaranteed until an official OpenStack release. To address these challenges, an OpenStackClient command may be labeled as a beta command according to the guidelines below. Such commands may introduce backwards incompatible changes and may use REST API enhancements not yet released. This also applies to command options associated with the beta command object. See the examples below on how to label an entire command or a specific option as a beta by updating the documentation and implementation. The initial release note must label the new command or option as a beta. No further release notes are required until the command or option is no longer a beta. At which time, the beta label or the command or option itself must be removed and a new release note must be provided. Beta Command Example -------------------- Documentation ~~~~~~~~~~~~~ The command documentation must label the command as a beta. example list ++++++++++++ List examples .. caution:: This is a beta command and subject to change. Use global option ``--os-beta-command`` to enable this command. .. program:: example list .. code:: bash openstack example list Help ~~~~ The command help must label the command as a beta. .. code-block:: python class ShowExample(command.ShowOne): """Display example details (Caution: This is a beta command and subject to change. Use global option --os-beta-command to enable this command) """ Implementation ~~~~~~~~~~~~~~ The command must raise a ``CommandError`` exception if beta commands are not enabled via ``--os-beta-command`` global option. .. code-block:: python def take_action(self, parsed_args): self.validate_os_beta_command_enabled() Beta Option Example ------------------- Documentation ~~~~~~~~~~~~~ The option documentation must label the option as a beta. .. option:: --example Example .. caution:: This is a beta command option and subject to change. Use global option ``--os-beta-command`` to enable this command option. Implementation ~~~~~~~~~~~~~~ The option must not be added if beta commands are not enabled via ``--os-beta-command`` global option. .. code-block:: python def get_parser(self, prog_name): if self.app.options.os_beta_command: parser.add_argument( '--example', metavar='', help=_("Example") ) python-openstackclient-5.2.0/doc/source/contributor/developing.rst0000664000175000017500000001200313637121057025553 0ustar zuulzuul00000000000000=============================== Developing with OpenStackClient =============================== Communication ------------- IRC Channel =========== The OpenStackClient team doesn't have regular meetings so if you have questions or anything you want to discuss, come to our channel: #openstack-sdks Testing ------- Tox prerequisites and installation ================================== Install the prerequisites for Tox: * On Ubuntu or Debian: .. code-block:: bash $ apt-get install gcc gettext python-dev libxml2-dev libxslt1-dev \ zlib1g-dev You may need to use pip install for some packages. * On RHEL or CentOS including Fedora: .. code-block:: bash $ yum install gcc python-devel libxml2-devel libxslt-devel * On openSUSE or SUSE linux Enterprise: .. code-block:: bash $ zypper install gcc python-devel libxml2-devel libxslt-devel Install python-tox: .. code-block:: bash $ pip install tox To run the full suite of tests maintained within OpenStackClient. .. code-block:: bash $ tox .. NOTE:: The first time you run ``tox``, it will take additional time to build virtualenvs. You can later use the ``-r`` option with ``tox`` to rebuild your virtualenv in a similar manner. To run tests for one or more specific test environments(for example, the most common configuration of Python 2.7 and PEP-8), list the environments with the ``-e`` option, separated by spaces: .. code-block:: bash $ tox -e py27,pep8 See ``tox.ini`` for the full list of available test environments. Running functional tests ======================== OpenStackClient also maintains a set of functional tests that are optimally designed to be run against OpenStack's gate. Optionally, a developer may choose to run these tests against any OpenStack deployment, however depending on the services available, results vary. To run the entire suite of functional tests: .. code-block:: bash $ tox -e functional To run a specific functional test: .. code-block:: bash $ tox -e functional -- --regex functional.tests.compute.v2.test_server Running with PDB ================ Using PDB breakpoints with ``tox`` and ``testr`` normally does not work since the tests fail with a `BdbQuit` exception rather than stopping at the breakpoint. To run with PDB breakpoints during testing, use the `debug` ``tox`` environment rather than ``py27``. For example, passing a test name since you will normally only want to run the test that hits your breakpoint: .. code-block:: bash $ tox -e debug openstackclient.tests.identity.v3.test_group For reference, the `debug`_ ``tox`` environment implements the instructions .. _`debug`: https://wiki.openstack.org/wiki/Testr#Debugging_.28pdb.29_Tests Building the Documentation -------------------------- The documentation is generated with Sphinx using the ``tox`` command. To create HTML docs, run the commands: .. code-block:: bash $ tox -e docs The resultant HTML will be in the ``doc/build/html`` directory. Release Notes ------------- The release notes for a patch should be included in the patch. See the `Project Team Guide`_ for more information on using reno in OpenStack. .. _`Project Team Guide`: http://docs.openstack.org/project-team-guide/release-management.html#managing-release-notes If any of the following applies to the patch, a release note is required: * The deployer needs to take an action when upgrading * The plugin interface changes * A new feature is implemented * A command or option is removed * Current behavior is changed * A security bug is fixed Reno is used to generate release notes. Use the commands: .. code-block:: bash $ tox -e venv -- reno new Then edit the sample file that was created and push it with your change. To run the commands and see results: .. code-block:: bash $ git commit # Commit the change because reno scans git log. $ tox -e releasenotes At last, look at the generated release notes files in ``releasenotes/build/html`` in your browser. Testing new code ---------------- If a developer wants to test new code (feature, command or option) that they have written, OpenStackClient may be installed from source by running the following commands in the base directory of the project: .. code-block:: bash $ python setup.py develop or .. code-block:: bash $ pip install -e . Standardize Import Format ========================= More information about Import Format, see `Import Order Guide `__. The import order shows below: .. code-block:: none {{stdlib imports in human alphabetical order}} \n {{third-party lib imports in human alphabetical order}} \n {{project imports in human alphabetical order}} \n \n {{begin your code}} Example ~~~~~~~ .. code-block:: python import copy import fixtures import mock import os from osc_lib.api import auth from osc_lib import utils import six from openstackclient import shell from openstackclient.tests import utils python-openstackclient-5.2.0/doc/source/contributor/plugins.rst0000664000175000017500000001716313637121057025114 0ustar zuulzuul00000000000000.. _plugins: ======= Plugins ======= The OpenStackClient plugin system is designed so that the plugin need only be properly installed for OSC to find and use it. It utilizes the ``setuptools`` entry points mechanism to advertise to OSC the plugin module and supported commands. Adoption ======== OpenStackClient promises to provide first class support for the following OpenStack services: Compute, Identity, Image, Object Storage, Block Storage and Network (core objects). These services are considered essential to any OpenStack deployment. Other OpenStack services, such as Orchestration or Telemetry may create an OpenStackClient plugin. The source code will not be hosted by OpenStackClient. The following is a list of projects that are an OpenStackClient plugin. - aodhclient - gnocchiclient - osc-placement - python-barbicanclient - python-congressclient - python-designateclient - python-heatclient - python-ironicclient - python-ironic-inspector-client - python-karborclient - python-mistralclient - python-muranoclient - python-neutronclient\*\*\* - python-octaviaclient - python-rsdclient - python-saharaclient - python-searchlightclient - python-senlinclient - python-tripleoclient\*\* - python-troveclient - python-watcherclient - python-zaqarclient - python-zunclient \*\* Note that some clients are not listed in global-requirements. \*\*\* Project contains advanced network services. The following is a list of projects that are not an OpenStackClient plugin. - python-magnumclient - python-monascaclient - python-solumclient Implementation ============== Client module ------------- Plugins are discovered by enumerating the entry points found under :py:mod:`openstack.cli.extension` and initializing the specified client module. .. code-block:: ini [entry_points] openstack.cli.extension = oscplugin = oscplugin.client The client module must define the following top-level variables: * ``API_NAME`` - A string containing the plugin API name; this is the name of the entry point declaring the plugin client module (``oscplugin = ...`` in the example above) and the group name for the plugin commands (``openstack.oscplugin.v1 =`` in the example below). OSC reserves the following API names: ``compute``, ``identity``, ``image``, ``network``, ``object_store`` and ``volume``. * ``API_VERSION_OPTION`` (optional) - If set, the name of the API version attribute; this must be a valid Python identifier and match the destination set in ``build_option_parser()``. * ``API_VERSIONS`` - A dict mapping a version string to the client class The client module must implement the following interface functions: * ``build_option_parser(parser)`` - Hook to add global options to the parser * ``make_client(instance)`` - Hook to create the client object OSC enumerates the plugin commands from the entry points in the usual manner defined for the API version: .. code-block:: ini openstack.oscplugin.v1 = plugin_list = oscplugin.v1.plugin:ListPlugin plugin_show = oscplugin.v1.plugin:ShowPlugin Note that OSC defines the group name as :py:mod:`openstack..v` so the version should not contain the leading 'v' character. .. code-block:: python from osc_lib import utils DEFAULT_API_VERSION = '1' # Required by the OSC plugin interface API_NAME = 'oscplugin' API_VERSION_OPTION = 'os_oscplugin_api_version' API_VERSIONS = { '1': 'oscplugin.v1.client.Client', } # Required by the OSC plugin interface def make_client(instance): """Returns a client to the ClientManager Called to instantiate the requested client version. instance has any available auth info that may be required to prepare the client. :param ClientManager instance: The ClientManager that owns the new client """ plugin_client = utils.get_client_class( API_NAME, instance._api_version[API_NAME], API_VERSIONS) client = plugin_client() return client # Required by the OSC plugin interface def build_option_parser(parser): """Hook to add global options Called from openstackclient.shell.OpenStackShell.__init__() after the builtin parser has been initialized. This is where a plugin can add global options such as an API version setting. :param argparse.ArgumentParser parser: The parser object that has been initialized by OpenStackShell. """ parser.add_argument( '--os-oscplugin-api-version', metavar='', help='OSC Plugin API version, default=' + DEFAULT_API_VERSION + ' (Env: OS_OSCPLUGIN_API_VERSION)') return parser Client usage of OSC interfaces ------------------------------ OSC provides the following interfaces that may be used to implement the plugin commands: .. code-block:: python # osc-lib interfaces available to plugins: from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions from osc_lib import logs from osc_lib import utils class DeleteMypluginobject(command.Command): """Delete mypluginobject""" ... def take_action(self, parsed_args): # Client manager interfaces are available to plugins. # This includes the OSC clients created. client_manager = self.app.client_manager ... return OSC provides the following interfaces that may be used to implement unit tests for the plugin commands: .. code-block:: python # OSC unit test interfaces available to plugins: from openstackclient.tests import fakes from openstackclient.tests import utils ... Requirements ------------ OSC should be included in the plugin's ``test-requirements.txt`` if the plugin can be installed as a library with the CLI being an optional feature (available when OSC is also installed). OSC should not appear in ``requirements.txt`` unless the plugin project wants OSC and all of its dependencies installed with it. This is specifically not a good idea for plugins that are also libraries installed with OpenStack services. .. code-block:: ini python-openstackclient>=X.Y.Z # Apache-2.0 Checklist for adding new OpenStack plugins ========================================== Creating the initial plugin described above is the first step. There are a few more steps needed to fully integrate the client with openstackclient. Add the command checker to your CI ---------------------------------- #. Add ``openstackclient-plugin-jobs`` to the list of job templates for your project. These jobs ensures that all plugin libraries are co-installable with ``python-openstackclient`` and checks for conflicts across all OpenStackClient plugins, such as duplicated commands, missing entry points, or other overlaps. #. Add your project to the ``required-projects`` list in the ``.zuul.yaml`` file in the ``openstack/openstackclient`` repo. Changes to python-openstackclient --------------------------------- #. In ``doc/source/plugins.rst``, update the `Adoption` section to reflect the status of the project. #. Update ``doc/source/commands.rst`` to include objects that are defined by fooclient's new plugin. #. Update ``doc/source/plugin-commands.rst`` to include the entry point defined in fooclient. We use `sphinxext`_ to automatically document commands that are used. #. Update ``test-requirements.txt`` to include fooclient. This is necessary to auto-document the commands in the previous step. .. _sphinxext: https://docs.openstack.org/stevedore/latest/user/sphinxext.html python-openstackclient-5.2.0/doc/source/contributor/command-errors.rst0000664000175000017500000001605413637121057026361 0ustar zuulzuul00000000000000============== Command Errors ============== Handling errors in OpenStackClient commands is fairly straightforward. An exception is thrown and handled by the application-level caller. Note: There are many cases that need to be filled out here. The initial version of this document considers the general command error handling as well as the specific case of commands that make multiple REST API calls and how to handle when one or more of those calls fails. General Command Errors ====================== The general pattern for handling OpenStackClient command-level errors is to raise a CommandError exception with an appropriate message. This should include conditions arising from arguments that are not valid/allowed (that are not otherwise enforced by ``argparse``) as well as errors arising from external conditions. External Errors --------------- External errors are a result of things outside OpenStackClient not being as expected. Example ~~~~~~~ This example is taken from ``keypair create`` where the ``--public-key`` option specifies a file containing the public key to upload. If the file is not found, the IOError exception is trapped and a more specific CommandError exception is raised that includes the name of the file that was attempted to be opened. .. code-block:: python class CreateKeypair(command.ShowOne): """Create new public key""" ## ... def take_action(self, parsed_args): compute_client = self.app.client_manager.compute public_key = parsed_args.public_key if public_key: try: with io.open( os.path.expanduser(parsed_args.public_key), "rb" ) as p: public_key = p.read() except IOError as e: msg = _("Key file %s not found: %s") raise exceptions.CommandError( msg % (parsed_args.public_key, e), ) keypair = compute_client.keypairs.create( parsed_args.name, public_key=public_key, ) ## ... REST API Errors =============== Most commands make a single REST API call via the supporting client library or SDK. Errors based on HTML return codes are usually handled well by default, but in some cases more specific or user-friendly messages need to be logged. Trapping the exception and raising a CommandError exception with a useful message is the correct approach. Multiple REST API Calls ----------------------- Some CLI commands make multiple calls to library APIs and thus REST APIs. Most of the time these are ``create`` or ``set`` commands that expect to add or change a resource on the server. When one of these calls fails, the behaviour of the remainder of the command handler is defined as such: * Whenever possible, all API calls will be made. This may not be possible for specific commands where the subsequent calls are dependent on the results of an earlier call. * Any failure of an API call will be logged for the user * A failure of any API call results in a non-zero exit code * In the cases of failures in a ``create`` command a follow-up mode needs to be present that allows the user to attempt to complete the call, or cleanly remove the partially-created resource and re-try. The desired behaviour is for commands to appear to the user as idempotent whenever possible, i.e. a partial failure in a ``set`` command can be safely retried without harm. ``create`` commands are a harder problem and may need to be handled by having the proper options in a set command available to allow recovery in the case where the primary resource has been created but the subsequent calls did not complete. Example 1 ~~~~~~~~~ This example is taken from the ``volume snapshot set`` command where ``--property`` arguments are set using the volume manager's ``set_metadata()`` method, ``--state`` arguments are set using the ``reset_state()`` method, and the remaining arguments are set using the ``update()`` method. .. code-block:: python class SetSnapshot(command.Command): """Set snapshot properties""" ## ... def take_action(self, parsed_args): volume_client = self.app.client_manager.volume snapshot = utils.find_resource( volume_client.volume_snapshots, parsed_args.snapshot, ) kwargs = {} if parsed_args.name: kwargs['name'] = parsed_args.name if parsed_args.description: kwargs['description'] = parsed_args.description result = 0 if parsed_args.property: try: volume_client.volume_snapshots.set_metadata( snapshot.id, parsed_args.property, ) except SomeException: # Need to define the exceptions to catch here LOG.error(_("Property set failed")) result += 1 if parsed_args.state: try: volume_client.volume_snapshots.reset_state( snapshot.id, parsed_args.state, ) except SomeException: # Need to define the exceptions to catch here LOG.error(_("State set failed")) result += 1 try: volume_client.volume_snapshots.update( snapshot.id, **kwargs ) except SomeException: # Need to define the exceptions to catch here LOG.error(_("Update failed")) result += 1 # NOTE(dtroyer): We need to signal the error, and a non-zero return code, # without aborting prematurely if result > 0: raise SomeNonFatalException Example 2 ~~~~~~~~~ This example is taken from the ``network delete`` command which takes multiple networks to delete. All networks will be deleted in a loop, which makes multiple ``delete_network()`` calls. .. code-block:: python class DeleteNetwork(common.NetworkAndComputeCommand): """Delete network(s)""" def update_parser_common(self, parser): parser.add_argument( 'network', metavar="", nargs="+", help=_("Network(s) to delete (name or ID)") ) return parser def take_action(self, client, parsed_args): ret = 0 for network in parsed_args.network: try: obj = client.find_network(network, ignore_missing=False) client.delete_network(obj) except Exception: LOG.error(_("Failed to delete network with name " "or ID %s."), network) ret += 1 if ret > 0: total = len(parsed_args.network) msg = (_("Failed to delete %(ret)s of %(total)s networks.") % {"ret": ret, "total": total}) raise exceptions.CommandError(msg) python-openstackclient-5.2.0/doc/source/contributor/humaninterfaceguide.rst0000664000175000017500000003502713637121057027441 0ustar zuulzuul00000000000000.. _hig: ===================== Human Interface Guide ===================== *Note: This page covers the OpenStackClient CLI only but looks familiar because it was derived from the Horizon HIG.* Overview ======== What is a HIG? The Human Interface Guidelines document was created for OpenStack developers in order to direct the creation of new OpenStackClient command interfaces. Personas ======== Personas are archetypal users of the system. Keep these types of users in mind when designing the interface. Alice the admin --------------- Alice is an administrator who is responsible for maintaining the OpenStack cloud installation. She has many years of experience with Linux systems administration. Darren the deployer ------------------- Darren is responsible for doing the initial OpenStack deployment on the host machines. Emile the end-user ------------------ Emile uses the cloud to do software development inside of the virtual machines. She uses the command-line tools because she finds it quicker than using the dashboard. Principles ========== The principles established in this section define the high-level priorities to be used when designing and evaluating interactions for the OpenStack command line interface. Principles are broad in scope and can be considered the philosophical foundation for the OpenStack experience; while they may not describe the tactical implementation of design, they should be used when deciding between multiple courses of design. A significant theme for designing for the OpenStack experience concerns focusing on common uses of the system rather than adding complexity to support functionality that is rarely used. Consistency ----------- Consistency between OpenStack experiences will ensure that the command line interface feels like a single experience instead of a jumble of disparate products. Fractured experiences only serve to undermine user expectations about how they should interact with the system, creating an unreliable user experience. To avoid this, each interaction and visual representation within the system must be used uniformly and predictably. The architecture and elements detailed in this document will provide a strong foundation for establishing a consistent experience. Example Review Criteria ~~~~~~~~~~~~~~~~~~~~~~~ * Do the command actions adhere to a consistent application of actions? * Has a new type of command subject or output been introduced? * Does the design use command elements (options and arguments) as defined? (See Core Elements.) * Can any newly proposed command elements (actions or subjects) be accomplished with existing elements? * Does the design adhere to the structural model of the core experience? (See Core Architecture.) * Are any data objects displayed or manipulated in a way contradictory to how they are handled elsewhere in the core experience? Simplicity ---------- To best support new users and create straight forward interactions, designs should be as simple as possible. When crafting new commands, designs should minimize the amount of noise present in output: large amounts of nonessential data, overabundance of possible actions and so on. Designs should focus on the intent of the command, requiring only the necessary components and either removing superfluous elements or making them accessible through optional arguments. An example of this principle occurs in OpenStack's use of tables: only the most often used columns are shown by default. Further data may be accessed through the output control options, allowing users to specify the types of data that they find useful in their day-to-day work. Example Review Criteria ~~~~~~~~~~~~~~~~~~~~~~~ * Can options be used to combine otherwise similar commands? * How many of the displayed elements are relevant to the majority of users? * If multiple actions are required for the user to complete a task, is each step required or can the process be more efficient? User-Centered Design -------------------- Commands should be design based on how a user will interact with the system and not how the system's backend is organized. While database structures and APIs may define what is possible, they often do not define good user experience; consider user goals and the way in which users will want to interact with their data, then design for these work flows and mold the interface to the user, not the user to the interface. Commands should be discoverable via the interface itself. To determine a list of available commands, use the :code:`-h` or :code:`--help` options: .. code-block:: bash $ openstack --help For help with an individual command, use the :code:`help` command: .. code-block:: bash $ openstack help server create Example Review Criteria ~~~~~~~~~~~~~~~~~~~~~~~ * How quickly can a user figure out how to accomplish a given task? * Has content been grouped and ordered according to usage relationships? * Do work flows support user goals or add complexity? Transparency ------------ Make sure users understand the current state of their infrastructure and interactions. For example, users should be able to access information about the state of each machine/virtual machine easily, without having to actively seek out this information. Whenever the user initiates an action, make sure a confirmation is displayed[1] to show that an input has been received. Upon completion of a process, make sure the user is informed. Ensure that the user never questions the state of their environment. [1] This goes against the common UNIX philosophy of only reporting error conditions and output that is specifically requested. Example Review Criteria ~~~~~~~~~~~~~~~~~~~~~~~ * Does the user receive feedback when initiating a process? * When a process is completed? * Does the user have quick access to the state of their infrastructure? Architecture ============ Command Structure ----------------- OpenStackClient has a consistent and predictable format for all of its commands. * The top level command name is :code:`openstack` * Sub-commands take the form: .. code-block:: bash openstack [] [] [] Subcommands shall have three distinct parts to its commands (in order that they appear): * global options * command object(s) and action * command options and arguments Output formats: * user-friendly tables with headers, etc * machine-parsable delimited Global Options ~~~~~~~~~~~~~~ Global options are global in the sense that they apply to every command invocation regardless of action to be performed. They include authentication credentials and API version selection. Most global options have a corresponding environment variable that may also be used to set the value. If both are present, the command-line option takes priority. The environment variable names are derived from the option name by dropping the leading dashes ('--'), converting each embedded dash ('-') to an underscore ('_'), and converting to upper case. * Global options shall always have a long option name, certain common options may also have short names. Short names should be reserved for global options to limit the potential for duplication and multiple meanings between commands given the limited set of available short names. * All long options names shall begin with two dashes ('--') and use a single dash ('-') internally between words (:code:`--like-this`). Underscores ('_') shall not be used in option names. * Authentication options conform to the common CLI authentication guidelines in :ref:`authentication`. For example, :code:`--os-username` can be set from the environment via :code:`OS_USERNAME`. --help ++++++ The standard :code:`--help` global option displays the documentation for invoking the program and a list of the available commands on standard output. All other options and commands are ignored when this is present. The traditional short form help option (:code:`-h`) is also available. --version +++++++++ The standard :code:`--version` option displays the name and version on standard output. All other options and commands are ignored when this is present. Command Object(s) and Action ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Commands consist of an object described by one or more words followed by an action. Commands that require two objects have the primary object ahead of the action and the secondary object after the action. Any positional arguments identifying the objects shall appear in the same order as the objects. In badly formed English it is expressed as "(Take) object1 (and perform) action (using) object2 (to it)." [] Examples: * :code:`group add user ` * :code:`volume type list` # Note that :code:`volume type` is a two-word single object The :code:`help` command is unique as it appears in front of a normal command and displays the help text for that command rather than execute it. Object names are always specified in command in their singular form. This is contrary to natural language use. Command Arguments and Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each command may have its own set of options distinct from the global options. They follow the same style as the global options and always appear between the command and any positional arguments the command requires. Command options shall only have long names. The small range of available short names makes it hard for a single short option name to have a consistent meaning across multiple commands. Option Forms ++++++++++++ * **boolean**: boolean options shall use a form of :code:`--|--` (preferred) or :code:`--