OpenStack Command-line Client

repository·master·Indexed 18 days ago

https://github.com/openstack/python-openstackclient

A unified command-line interface (OSC) for managing various OpenStack services, including Compute, Identity, Network, Image, Object Store, Share, and Volume. It provides a consistent command structure across different service APIs and supports multiple authentication methods via keystoneauth plugins, such as v3password, v3token, v3applicationcredential, and v3totp.

Tokens
52.8K
Snippets
218
Records
316
Agent score
62%

What's inside python-openstackclient

  1. Explore the OpenStackClient command list

    master

    The OpenStackClient provides a wide range of commands organized by OpenStack service modules. You can access commands for specific services by navigating to their respective command object groups. The available service modules include:

    • Compute (v2)
    • Identity (v2 and v3)
    • Image (v1 and v2)
    • Network (v2)
    • Object Store (v1)
    • Share (v2)
    • Volume (v2 and v3)
    • Common commands used across multiple services.
  2. Handle multiple REST API calls and partial failures

    master

    Some commands perform multiple API calls (e.g., create or set operations). When a command involves multiple steps, follow these principles:

    1. Attempt all calls: Whenever possible, continue executing subsequent API calls even if one fails, unless the next call depends on the result of the failed one.
    2. Log failures: Every failed API call should be logged for the user.
    3. Non-zero exit code: Any failure in any API call must result in a non-zero exit code.
    4. Idempotency: Design set commands to be idempotent so they can be safely retried. For create commands, provide options or follow-up modes to allow users to either complete the partial resource or clean up the partially-created resource.

    To implement this, track the number of failures during the execution of take_action and raise an exception at the end if any errors occurred.

    result = 0
    if parsed_args.property:
        try:
            volume_client.volume_snapshots.set_metadata(snapshot.id, parsed_args.property)
        except SomeException:
            LOG.error(_("Property set failed"))
            result += 1
    
    # ... other calls ...
    
    if result > 0:
        raise SomeNonFatalException
  3. Implement List Command Options: --long and Pagination

    master

    Standardize list commands by implementing the following options:

    Additional Fields

    Use the --long option to allow users to view additional fields that are hidden by default in standard list outputs.

    Pagination

    To provide a consistent pagination experience across different APIs, implement:

    • --marker <resource>: An anchor for paging (typically a name or ID).
    • --limit <num-resources>: An integer limiting the number of resources returned.
    # --long implementation
    parser.add_argument(
        '--long',
        action='store_true',
        default=False,
        help='List additional fields in output',
    )
    
    # Pagination implementation
    parser.add_argument(
        "--marker",
        metavar="<resource>",
        help="Anchor for paging (name or ID)",
    )
    parser.add_argument(
        "--limit",
        metavar="<num-resources>",
        type=int,
        help="Limit the number of <resource> returned",
    )
  4. Use Global Options and Environment Variables

    master

    Global options apply to every command invocation (e.g., authentication credentials and API version selection).

    Environment Variable Mapping: Most global options can be set via environment variables. To derive the environment variable name from a long option:

    1. Drop the leading dashes (--).
    2. Convert embedded dashes (-) to underscores (_).
    3. Convert to uppercase.

    Example: --os-username is set via OS_USERNAME.

    Priority: If both a command-line option and an environment variable are provided, the command-line option takes priority.

    Standard Global Options:

    • --help or -h: Displays program documentation and available commands. All other options/commands are ignored.
    • --version: Displays the name and version. All other options/commands are ignored.
    # Using a command-line option
    openstack --os-username myuser ...
    
    # Using an environment variable
    export OS_USERNAME=myuser
    openstack ...
  5. Implement Required Options

    master

    If an API does not allow a field to be None and no default value exists, the option must be marked as required=True in the parser. This allows the CLI to validate the presence of the argument and provide a clear error message (e.g., error: argument --test is required) before making the API call.

    parser.add_argument(
        '--test',
        metavar='<test>',
        required=True,
        help=_('Test option (required)'),
    )
  6. Identify Objects and Actions in commands

    master

    Commands are composed of an object (one or more words) followed by an action.

    Single Object Pattern: <object> <action>

    • group create
    • server set
    • volume type list (Note: volume type is a two-word single object)

    Two Object Pattern: Used when an action is performed on a secondary object using a primary object. <object-1> <action> <object-2>

    • group add user
    • aggregate add host
    • image remove project

    Note: Object names in commands are always specified in their singular form (e.g., group, not groups).

    group create <group>
    server set <server>
    volume type list
  7. Design principles for OpenStackClient interfaces

    master

    When interacting with or extending the OpenStackClient, the interface follows several core principles designed to ensure a predictable and efficient user experience:

    • Consistency: Commands, subjects, and outputs should behave uniformly across the entire CLI to ensure a single, predictable experience rather than a collection of disparate tools.
    • Simplicity: Interfaces should minimize noise. Output (such as tables) should show only the most frequently used columns by default, with additional data accessible via output control options. Commands should focus on intent and minimize superfluous elements.
    • User-Centered Design: Commands are organized around user workflows and goals rather than the underlying backend API or database structures. Commands should be easily discoverable.
    • Transparency: The CLI should provide clear feedback. Users should receive confirmation when an action is initiated and be informed when a process completes, ensuring they always understand the state of their infrastructure.
  8. Configure OpenStackClient using Global Options and Environment Variables

    master

    Global options apply to every command invocation and are typically used for authentication credentials and API version selection.

    Priority

    If both a command-line option and an environment variable are provided, the command-line option takes priority.

    Environment Variable Mapping

    You can set global options using environment variables. To derive the environment variable name from an option:

    1. Drop the leading dashes (--).
    2. Convert embedded dashes (-) to underscores (_).
    3. Convert to upper case.

    Example: To set the value for --os-username, use the environment variable OS_USERNAME.

    # Setting via CLI option
    openstack --os-username myuser server list
    
    # Setting via Environment Variable
    export OS_USERNAME=myuser
    openstack server list
  9. How beta commands and options are implemented

    master

    Beta features in OpenStackClient follow two different implementation patterns depending on whether the beta status applies to an entire command or just a specific option:

    Beta Commands

    To implement a beta command, the command's take_action method must call self.validate_os_beta_command_enabled(). This ensures a CommandError is raised if the user has not provided the --os-beta-command global option.

    Beta Options

    To implement a beta option, the option should only be added to the parser within the get_parser method if the beta flag is active. This is checked via self.app.options.os_beta_command.

    # Pattern for a Beta Command
    def take_action(self, parsed_args):
        self.validate_os_beta_command_enabled()
    
    # Pattern for a Beta Option
    def get_parser(self, prog_name):
        if self.app.options.os_beta_command:
            parser.add_argument(
                '--example',
                metavar='<example>',
                help=_("Example")
            )
  10. Use arguments to target specific objects

    master

    Arguments are positional parameters used to interact with a specific instance of an object, typically a name or an ID.

    Single Object Interaction: <object> <action> [<name-or-id>]

    • group create <group>
    • server set <server>

    Two Object Interaction: When a command requires two objects, arguments should appear in the same order as the objects. <object-1> <action> <object-2> [<object-1-name-or-id> <object-2-name-or-id>]

    • group add user <group> <user>
    • aggregate add host <aggregate> <host>
    • image remove project <image> <project>
    group add user mygroup myuser