@click.command(context_settings=command_settings)
# This is a little hacky, but we cannot directly set the default to nova
# because then we have no way of determining if the option was supplied on the
# command line, or simply set to the default.  We need that information so that
# we can properly set the executable to run in this order:
# 1. executable provided on command line
# 2. executable from environment variable
# 3. fallback to nova as a default if neither 1 nor 2 are set
@click.option('--executable', '-x', default='default',
              help='Command to run  [default: nova]', show_default=False)
@click.option('--debug', '-d', default=False, is_flag=True,
              help="Enable debugging", show_default=True)
@click.option('--conf', '-c', default=None, is_flag=False,
              help="Manually specify a supernova configuration file")
@click.option('--quiet', '-q', default=False, show_default=False,
              is_flag=True,
              help="Display the least amount of output possible")
@click.option('--echo', '-e', default=None, is_flag=True,
              help="Print the specified environment and exit")
@click.argument('environment', nargs=1)
@click.argument('command', nargs=-1)
@click.version_option()
@click.option('--list', '-l', is_flag=True, callback=print_env_list,
              expose_value=False, is_eager=False, default=False,
              help="List all configured environments")
@click.option('--shortlist', '-s', is_flag=True, callback=print_env_short_list,
              expose_value=False, is_eager=False, default=False,
              help="List all configured environments in shorter format")
@click.pass_context
def run_supernova(ctx, executable, debug, quiet, environment, command, conf,
                  echo):
    # Retrieve our credentials from the configuration file
    try:
        nova_creds = config.run_config(config_file_override=conf)
    except Exception as e:
        msg = ("\n  There's an error in your configuration file:\n\n"
               "    {0}\n").format(e)
        click.echo(msg)
        ctx.exit(1)

    # Warn the user if there are potentially conflicting environment variables
    # already set in the user's environment.
    utils.check_environment_presets()

    # Is our environment argument a single environment or a supernova group?
    if utils.is_valid_group(environment, nova_creds):
        envs = utils.get_envs_in_group(environment, nova_creds)
    else:
        envs = [environment]

    # These are arguments for supernova and not the executable that supernova
    # will eventually call.
    supernova_args = {
        'debug': debug,
        'executable': executable,
        'quiet': quiet,
        'echo': echo,
    }

    # If the user specified a single environment, we need to verify that the
    # environment actually exists in their configuration file.
    if len(envs) == 1 and not utils.is_valid_environment(envs[0], nova_creds):
        msg = ("\nCouldn't find an environment called '{0}' in your "
               "configuration file.\nTry supernova --list to see all "
               "configured environments.\n".format(envs[0]))
        click.echo(msg)
        ctx.exit(1)

    if supernova_args['echo']:
        if len(envs) > 1:
            msg = ("\nCan't echo a group of environments.\nSpecify a single "
                   "environment when using --echo.")
            click.echo(msg)
            ctx.exit(1)
        env = credentials.prep_shell_environment(envs[0], nova_creds)
        for k in env:
            click.echo('{0}={1}'.format(k, env[k]))
        ctx.exit(0)

    if len(command) == 0:
        msg = ("\nMissing arguments to pass to executable  Run supernova "
               "--help for examples.\n".format(envs[0]))
        click.echo(msg)
        ctx.exit(1)

    nova_args = list(command)

    # Loop through the single environment (if the user specified one) or all
    # of the environments in a supernova group (if the user specified a group).
    for env in envs:
        supernova_args['nova_env'] = env
        returncode = supernova.run_command(nova_creds, nova_args,
                                           supernova_args)

    # NOTE(major): The return code here is the one that comes back from the
    # OS_EXECUTABLE that supernova runs (by default, 'nova').  When using
    # supernova groups, the return code is the one returned by the executable
    # for the last environment in the group.
    #
    # It's not ideal, but it's all I can think of for now. ;)
    sys.exit(returncode)
You can use supernova with many OpenStack clients and avoid the pain of
dataset/ETHPy150Open major/supernova/supernova/executable.py/run_supernova