GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Software
  • OpenStack Components
  • SDKs
  • Deployment Tools
  • OpenStack Map
  • Sample Configs
  • Use Cases
  • Ironic Bare Metal
  • Edge Computing
  • Telecom & NFV
  • Science and HPC
  • Containers
  • Enterprise
  • User Survey

This view

  • Original page
  • New address

GeezerVison is showing docs.openstack.org — Command Errors — OpenStack Command Line Client 10.5.1.dev13 documentation

Command Errors

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.

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 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.create_keypair(
            name=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.

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.

class DeleteNetwork(common.NetworkDelete):
    """Delete network(s)"""

    def get_parser(self, prog_name):
        parser = super().get_parser(prog_name)
        parser.add_argument(
            'network',
            metavar="<network>",
            nargs="+",
            help=_("Network(s) to delete (name or ID)")
        )
        return parser

    def take_action_delete(self, parsed_args):
        client = self.app.client_manager.network
        obj = client.find_network(network, ignore_missing=False)
        client.delete_network(obj)
this page last updated: 2026-03-20 18:16:54
Creative Commons Attribution 3.0 License

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.

  • Guides
  • Install Guides
  • User Guides
  • Configuration Guides
  • Operations and Administration Guides
  • API Guides
  • Contributor Guides
  • Languages
  • Deutsch (German)
  • Français (French)
  • Bahasa Indonesia (Indonesian)
  • Italiano (Italian)
  • 日本語 (Japanese)
  • 한국어 (Korean)
  • Português (Portuguese)
  • Türkçe (Türkiye)
  • 简体中文 (Simplified Chinese)

OpenStack Command Line Client 10.5.1.dev13

  • User Documentation
  • Configuration
  • Release Notes
  • Contributor Documentation
    • Developing with OpenStackClient
    • Command Beta
    • Command Options
    • Command Class Wrappers
    • Command Errors
    • Command Logs
    • Plugins
    • Migrating Project Client OSC Plugins to OSC
    • Human Interface Guide
    • openstackclient

Page Contents

  • Command Errors
    • General Command Errors
      • External Errors
        • Example
    • REST API Errors
      • Multiple REST API Calls
        • Example 1
        • Example 2
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.