Exemple #1
0
    def validate_version(cls, version):
        from manilaclient import api_versions
        from manilaclient import exceptions as manila_exc

        try:
            api_versions.get_api_version(version)
        except manila_exc.UnsupportedVersion:
            raise exceptions.RallyException(
                "Version string '%s' is unsupported." % version)
Exemple #2
0
    def validate_version(cls, version):
        from novaclient import api_versions
        from novaclient import exceptions as nova_exc

        try:
            api_versions.get_api_version(version)
        except nova_exc.UnsupportedVersion:
            raise exceptions.RallyException(
                "Version string '%s' is unsupported." % version)
def make_client(instance):
    """Returns a compute service client."""

    # Defer client import until we actually need them
    from novaclient import client as nova_client

    if _compute_api_version is not None:
        version = _compute_api_version
    else:
        version = instance._api_version[API_NAME]
        from novaclient import api_versions
        # convert to APIVersion object
        version = api_versions.get_api_version(version)

    if version.is_latest():
        import novaclient
        # NOTE(RuiChen): executing version discovery make sense, but that need
        #                an initialized REST client, it's not available now,
        #                fallback to use the max version of novaclient side.
        version = novaclient.API_MAX_VERSION

    LOG.debug('Instantiating compute client for %s', version)

    compute_api = utils.get_client_class(
        API_NAME,
        version.ver_major,
        COMPUTE_API_VERSIONS,
    )
    LOG.debug('Instantiating compute api: %s', compute_api)

    # Set client http_log_debug to True if verbosity level is high enough
    http_log_debug = utils.get_effective_log_level() <= logging.DEBUG

    extensions = [ext for ext in nova_client.discover_extensions(version)
                  if ext.name == "list_extensions"]

    # Remember interface only if it is set
    kwargs = utils.build_kwargs_dict('endpoint_type', instance.interface)

    client = nova_client.Client(
        version,
        session=instance.session,
        extensions=extensions,
        http_log_debug=http_log_debug,
        timings=instance.timing,
        region_name=instance.region_name,
        **kwargs
    )

    client.api = compute_api(
        session=instance.session,
        service_type=COMPUTE_API_TYPE,
        endpoint=instance.get_endpoint_for_service_type(
            COMPUTE_API_TYPE,
            region_name=instance.region_name,
            interface=instance.interface,
        )
    )

    return client
 def __init__(self, conf, endpoint_override=None):
     self.session = None
     self.endpoint_override = endpoint_override
     self.project_domain_name = conf.project_domain_name
     self.username_domain_name = conf.user_domain_name
     self.username = conf.username
     self.password = conf.password
     self.project_name = conf.project_name
     self.auth_url = conf.auth_url
     self.region_name = conf.region_name
     self.endpoint_type = conf.endpoint_type
     self.init_session()
     self._volumes = cinderclient.Client(
         self.username,
         self.password,
         self.project_name,
         auth_url=self.auth_url,
         region_name=self.region_name,
         endpoint_override=self.endpoint_override,
         insecure=True)
     self._compute = nova_client.Client(
         api_versions.get_api_version('2.53'),
         session=self.session,
         endpoint_type=self.endpoint_type,
         endpoint_override=self.endpoint_override,
         region_name=self.region_name)
     self._placement = PlacementClient(self.session)
Exemple #5
0
def make_client(instance):
    """Returns a compute service client."""

    # Defer client import until we actually need them
    from novaclient import client as nova_client

    if _compute_api_version is not None:
        version = _compute_api_version
    else:
        version = instance._api_version[API_NAME]
        from novaclient import api_versions
        # convert to APIVersion object
        version = api_versions.get_api_version(version)

    if version.is_latest():
        import novaclient
        # NOTE(RuiChen): executing version discovery make sense, but that need
        #                an initialized REST client, it's not available now,
        #                fallback to use the max version of novaclient side.
        version = novaclient.API_MAX_VERSION

    LOG.debug('Instantiating compute client for %s', version)

    compute_api = utils.get_client_class(
        API_NAME,
        version.ver_major,
        COMPUTE_API_VERSIONS,
    )
    LOG.debug('Instantiating compute api: %s', compute_api)

    # Set client http_log_debug to True if verbosity level is high enough
    http_log_debug = utils.get_effective_log_level() <= logging.DEBUG

    extensions = [
        ext for ext in nova_client.discover_extensions(version)
        if ext.name == "list_extensions"
    ]

    # Remember interface only if it is set
    kwargs = utils.build_kwargs_dict('endpoint_type', instance.interface)

    client = nova_client.Client(version,
                                session=instance.session,
                                extensions=extensions,
                                http_log_debug=http_log_debug,
                                timings=instance.timing,
                                region_name=instance.region_name,
                                **kwargs)

    client.api = compute_api(session=instance.session,
                             service_type=COMPUTE_API_TYPE,
                             endpoint=instance.get_endpoint_for_service_type(
                                 COMPUTE_API_TYPE,
                                 region_name=instance.region_name,
                                 interface=instance.interface,
                             ))

    return client
Exemple #6
0
    def __init__ (self, config, poolname):
        self.config = config
        self.blocks = {}
        self.pool   = poolname
        controller_file = "~/.ipython/profile_default/security/ipcontroller-engine.json"

        self.client = client.Client(api_versions.APIVersion("2.0"),
                                    config['sites.jetstream']['OS_USERNAME'],
                                    config['sites.jetstream']['OS_PASSWORD'],
                                    project_id=config['sites.jetstream']['OS_PROJECT_ID'],
                                    project_name=config['sites.jetstream']['OS_PROJECT_NAME'],
                                    auth_url=config['sites.jetstream']['OS_AUTH_URL'],
                                    insecure=False,
                                    region_name=config['sites.jetstream']['OS_REGION_NAME'],
                                    user_domain_name=config['sites.jetstream']['OS_USER_DOMAIN_NAME'])

        api_version = api_versions.get_api_version("2.0")
        api_version = api_versions.discover_version(self.client, api_version)
        extensions  = client.discover_extensions(api_version)

        logger.debug(self.client.has_neutron())
        self.server_manager =  self.client.servers

        try:
            with open(os.path.expanduser(controller_file), 'r') as f:
                self.engine_config = f.read()

        except FileNotFoundError :
            logger.error("No controller_file found at : %s. Cannot proceed", controller_file)
            exit(-1)

        except Exception as e :

            logger.error("Caught exception while reading from the ipcontroller_engine.json")
            raise e


        try:
            # Check if the authentication worked by forcing a call
            self.server_manager.list()

        except Exception as e:
            logger.error("Caught exception : %s", e)
            raise e

        flavors = self.client.flavors.list()

        try:
            self.flavor = [ f for f in flavors
                            if f.name == config['sites.jetstream.{0}'.format(poolname)]['flavor']][0]
        except Exception as e:
            logger.error("Caught exception : ",e)
            raise e

        self.sec_groups = ast.literal_eval(config['sites.jetstream.{0}'.format(poolname)]['sec_groups'])
        self.nics = ast.literal_eval(config['sites.jetstream.{0}'.format(poolname)]['nics'])
def _get_client_class_and_version(version):
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    else:
        api_versions.check_major_version(version)
    if version.is_latest():
        raise exceptions.UnsupportedVersion(
            _("The version should be explicit, not latest."))
    return version, importutils.import_class(
        "novaclient.v%s.client.Client" % version.ver_major)
Exemple #8
0
def _get_client_class_and_version(version):
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    else:
        api_versions.check_major_version(version)
    if version.is_latest():
        raise exceptions.UnsupportedVersion(
            _("The version should be explicit, not latest."))
    return version, importutils.import_class(
        "novaclient.v%s.client.Client" % version.ver_major)
def discover_extensions(version):
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    extensions = []
    for name, module in itertools.chain(_discover_via_python_path(),
                                        _discover_via_contrib_path(version),
                                        _discover_via_entry_points()):

        extension = ext.Extension(name, module)
        extensions.append(extension)

    return extensions
def discover_extensions(version):
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    extensions = []
    for name, module in itertools.chain(
            _discover_via_python_path(),
            _discover_via_contrib_path(version),
            _discover_via_entry_points()):

        extension = ext.Extension(name, module)
        extensions.append(extension)

    return extensions
Exemple #11
0
def novaclient_with_version(request, version):
    """Downgrade the nova API to the specified version if possible."""

    api_version = api_versions.get_api_version(version)
    if api_version > nc.API_MIN_VERSION:
        if not api_version.matches(nc.API_MIN_VERSION,
                                   nc.API_MAX_VERSION):
            api_version = nc.API_MAX_VERSION
    elif api_version < nc.API_MIN_VERSION:
        api_version = nc.API_MIN_VERSION

    c = novaclient(request, api_version)

    return c
def discover_extensions(version, only_contrib=False):
    """Returns the list of extensions, which can be discovered by python path,
    contrib path and by entry-point 'novaclient.extension'.

    :param version: api version
    :type version: str or novaclient.api_versions.APIVersion
    :param only_contrib: search only in contrib directory or not
    :type only_contrib: bool
    """
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    if only_contrib:
        chain = _discover_via_contrib_path(version)
    else:
        chain = itertools.chain(_discover_via_python_path(),
                                _discover_via_contrib_path(version),
                                _discover_via_entry_points())
    return [ext.Extension(name, module) for name, module in chain]
Exemple #13
0
def discover_extensions(version, only_contrib=False):
    """Returns the list of extensions, which can be discovered by python path,
    contrib path and by entry-point 'novaclient.extension'.

    :param version: api version
    :type version: str or novaclient.api_versions.APIVersion
    :param only_contrib: search only in contrib directory or not
    :type only_contrib: bool
    """
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    if only_contrib:
        chain = _discover_via_contrib_path(version)
    else:
        chain = itertools.chain(_discover_via_python_path(),
                                _discover_via_contrib_path(version),
                                _discover_via_entry_points())
    return [ext.Extension(name, module) for name, module in chain]
def check_api_version(check_version):
    """Validate version supplied by user

    Returns:
    * True if version is OK
    * False if the version has not been checked and the previous plugin
      check should be performed
    * throws an exception if the version is no good

    TODO(dtroyer): make the exception thrown a version-related one
    """

    # Defer client imports until we actually need them
    try:
        from novaclient import api_versions
    except ImportError:
        # Retain previous behaviour
        return False

    import novaclient

    global _compute_api_version

    # Copy some logic from novaclient 2.27.0 for basic version detection
    # NOTE(dtroyer): This is only enough to resume operations using API
    #                version 2.0 or any valid version supplied by the user.
    _compute_api_version = api_versions.get_api_version(check_version)

    if _compute_api_version > api_versions.APIVersion("2.0"):
        if not _compute_api_version.matches(
            novaclient.API_MIN_VERSION,
            novaclient.API_MAX_VERSION,
        ):
            raise exceptions.CommandError(
                "versions supported by client: %s - %s" % (
                    novaclient.API_MIN_VERSION.get_string(),
                    novaclient.API_MAX_VERSION.get_string(),
                ),
            )
    return True
def check_api_version(check_version):
    """Validate version supplied by user

    Returns:
    * True if version is OK
    * False if the version has not been checked and the previous plugin
      check should be performed
    * throws an exception if the version is no good

    TODO(dtroyer): make the exception thrown a version-related one
    """

    # Defer client imports until we actually need them
    try:
        from novaclient import api_versions
    except ImportError:
        # Retain previous behaviour
        return False

    import novaclient

    global _compute_api_version

    # Copy some logic from novaclient 2.27.0 for basic version detection
    # NOTE(dtroyer): This is only enough to resume operations using API
    #                version 2.0 or any valid version supplied by the user.
    _compute_api_version = api_versions.get_api_version(check_version)

    if _compute_api_version > api_versions.APIVersion("2.0"):
        if not _compute_api_version.matches(
            novaclient.API_MIN_VERSION,
            novaclient.API_MAX_VERSION,
        ):
            raise exceptions.CommandError(
                "versions supported by client: %s - %s" % (
                    novaclient.API_MIN_VERSION.get_string(),
                    novaclient.API_MAX_VERSION.get_string(),
                ),
            )
    return True
Exemple #16
0
def check_api_version(check_version):
    """Validate version supplied by user

    Returns:

    * True if version is OK
    * False if the version has not been checked and the previous plugin
      check should be performed
    * throws an exception if the version is no good

    TODO(dtroyer): make the exception thrown a version-related one
    """

    # Defer client imports until we actually need them
    import novaclient
    from novaclient import api_versions

    global _compute_api_version

    # Copy some logic from novaclient 3.3.0 for basic version detection
    # NOTE(dtroyer): This is only enough to resume operations using API
    #                version 2.0 or any valid version supplied by the user.
    _compute_api_version = api_versions.get_api_version(check_version)

    # Bypass X.latest format microversion
    if not _compute_api_version.is_latest():
        if _compute_api_version > api_versions.APIVersion("2.0"):
            if not _compute_api_version.matches(
                    novaclient.API_MIN_VERSION,
                    novaclient.API_MAX_VERSION,
            ):
                msg = _("versions supported by client: %(min)s - %(max)s") % {
                    "min": novaclient.API_MIN_VERSION.get_string(),
                    "max": novaclient.API_MAX_VERSION.get_string(),
                }
                raise exceptions.CommandError(msg)
    return True
def check_api_version(check_version):
    """Validate version supplied by user

    Returns:

    * True if version is OK
    * False if the version has not been checked and the previous plugin
      check should be performed
    * throws an exception if the version is no good

    TODO(dtroyer): make the exception thrown a version-related one
    """

    # Defer client imports until we actually need them
    import novaclient
    from novaclient import api_versions

    global _compute_api_version

    # Copy some logic from novaclient 3.3.0 for basic version detection
    # NOTE(dtroyer): This is only enough to resume operations using API
    #                version 2.0 or any valid version supplied by the user.
    _compute_api_version = api_versions.get_api_version(check_version)

    # Bypass X.latest format microversion
    if not _compute_api_version.is_latest():
        if _compute_api_version > api_versions.APIVersion("2.0"):
            if not _compute_api_version.matches(
                novaclient.API_MIN_VERSION,
                novaclient.API_MAX_VERSION,
            ):
                msg = _("versions supported by client: %(min)s - %(max)s") % {
                    "min": novaclient.API_MIN_VERSION.get_string(),
                    "max": novaclient.API_MAX_VERSION.get_string(),
                }
                raise exceptions.CommandError(msg)
    return True
Exemple #18
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser(argv)
        (args, args_list) = parser.parse_known_args(argv)

        self.setup_debugging(args.debug)
        self.extensions = []
        do_help = args.help or not args_list or args_list[0] == 'help'

        # bash-completion should not require authentication
        skip_auth = do_help or (
            'bash-completion' in argv)

        if not args.os_compute_api_version:
            api_version = api_versions.get_api_version(
                DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
        else:
            api_version = api_versions.get_api_version(
                args.os_compute_api_version)

        os_username = args.os_username
        os_user_id = args.os_user_id
        os_password = None  # Fetched and set later as needed
        os_project_name = getattr(
            args, 'os_project_name', getattr(args, 'os_tenant_name', None))
        os_project_id = getattr(
            args, 'os_project_id', getattr(args, 'os_tenant_id', None))
        os_auth_url = args.os_auth_url
        os_region_name = args.os_region_name

        if "v2.0" not in os_auth_url:
            # NOTE(andreykurilin): assume that keystone V3 is used and try to
            # be more user-friendly, i.e provide default values for domains
            if (not args.os_project_domain_id and
                    not args.os_project_domain_name):
                setattr(args, "os_project_domain_id", "default")
            if not args.os_user_domain_id and not args.os_user_domain_name:
                setattr(args, "os_user_domain_id", "default")

        os_project_domain_id = args.os_project_domain_id
        os_project_domain_name = args.os_project_domain_name
        os_user_domain_id = args.os_project_domain_id
        os_user_domain_name = args.os_project_domain_name

        endpoint_type = args.endpoint_type
        insecure = args.insecure
        service_type = args.service_type
        service_name = args.service_name
        endpoint_override = args.endpoint_override
        os_cache = args.os_cache
        cacert = args.os_cacert
        cert = args.os_cert
        timeout = args.timeout

        keystone_session = None
        keystone_auth = None

        # We may have either, both or none of these.
        # If we have both, we don't need USERNAME, PASSWORD etc.
        # Fill in the blanks from the SecretsHelper if possible.
        # Finally, authenticate unless we have both.
        # Note if we don't auth we probably don't have a tenant ID so we can't
        # cache the token.
        auth_token = getattr(args, 'os_token', None)

        if not endpoint_type:
            endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE

        # This allow users to use endpoint_type as (internal, public or admin)
        # just like other openstack clients (glance, cinder etc)
        if endpoint_type in ['internal', 'public', 'admin']:
            endpoint_type += 'URL'

        if not service_type:
            # Note(alex_xu): We need discover version first, so if there isn't
            # service type specified, we use default nova service type.
            service_type = DEFAULT_NOVA_SERVICE_TYPE

        # We should always auth unless we have a token and we're passing a
        # specific endpoint
        # Expired tokens are handled by client.py:_cs_request
        must_auth = not (auth_token and endpoint_override)

        # FIXME(usrleon): Here should be restrict for project id same as
        # for os_username or os_password but for compatibility it is not.
        if must_auth and not skip_auth:

            if not os_username and not os_user_id:
                raise exc.CommandError(
                    _("You must provide a username "
                      "or user ID via --os-username, --os-user-id, "
                      "env[OS_USERNAME] or env[OS_USER_ID]"))

            if not any([os_project_name, os_project_id]):
                raise exc.CommandError(_("You must provide a project name or"
                                         " project ID via --os-project-name,"
                                         " --os-project-id, env[OS_PROJECT_ID]"
                                         " or env[OS_PROJECT_NAME]. You may"
                                         " use os-project and os-tenant"
                                         " interchangeably."))

            if not os_auth_url:
                raise exc.CommandError(
                    _("You must provide an auth url "
                      "via either --os-auth-url or env[OS_AUTH_URL]."))

            with utils.record_time(self.times, args.timings,
                                   'auth_url', args.os_auth_url):
                keystone_session = (
                    loading.load_session_from_argparse_arguments(args))
                keystone_auth = (
                    loading.load_auth_from_argparse_arguments(args))

        if (not skip_auth and
                not any([os_project_name, os_project_id])):
            raise exc.CommandError(_("You must provide a project name or"
                                     " project id via --os-project-name,"
                                     " --os-project-id, env[OS_PROJECT_ID]"
                                     " or env[OS_PROJECT_NAME]. You may"
                                     " use os-project and os-tenant"
                                     " interchangeably."))

        if not os_auth_url and not skip_auth:
            raise exc.CommandError(
                _("You must provide an auth url "
                  "via either --os-auth-url or env[OS_AUTH_URL]"))

        # This client is just used to discover api version. Version API needn't
        # microversion, so we just pass version 2 at here.
        self.cs = client.Client(
            api_versions.APIVersion("2.0"),
            os_username, os_password, project_id=os_project_id,
            project_name=os_project_name, user_id=os_user_id,
            auth_url=os_auth_url, insecure=insecure,
            region_name=os_region_name, endpoint_type=endpoint_type,
            extensions=self.extensions, service_type=service_type,
            service_name=service_name, auth_token=auth_token,
            timings=args.timings, endpoint_override=endpoint_override,
            os_cache=os_cache, http_log_debug=args.debug,
            cacert=cacert, cert=cert, timeout=timeout,
            session=keystone_session, auth=keystone_auth,
            logger=self.client_logger,
            project_domain_id=os_project_domain_id,
            project_domain_name=os_project_domain_name,
            user_domain_id=os_user_domain_id,
            user_domain_name=os_user_domain_name)

        if not skip_auth:
            if not api_version.is_latest():
                if api_version > api_versions.APIVersion("2.0"):
                    if not api_version.matches(novaclient.API_MIN_VERSION,
                                               novaclient.API_MAX_VERSION):
                        raise exc.CommandError(
                            _("The specified version isn't supported by "
                              "client. The valid version range is '%(min)s' "
                              "to '%(max)s'") % {
                                "min": novaclient.API_MIN_VERSION.get_string(),
                                "max": novaclient.API_MAX_VERSION.get_string()}
                        )
            api_version = api_versions.discover_version(self.cs, api_version)

        # build available subcommands based on version
        self.extensions = client.discover_extensions(api_version)
        self._run_extension_hooks('__pre_parse_args__')

        subcommand_parser = self.get_subcommand_parser(
            api_version, do_help=do_help, argv=argv)
        self.parser = subcommand_parser

        if args.help or not argv:
            subcommand_parser.print_help()
            return 0

        args = subcommand_parser.parse_args(argv)
        self._run_extension_hooks('__post_parse_args__', args)

        # Short-circuit and deal with help right away.
        if args.func == self.do_help:
            self.do_help(args)
            return 0
        elif args.func == self.do_bash_completion:
            self.do_bash_completion(args)
            return 0

        if not args.service_type:
            service_type = (utils.get_service_type(args.func) or
                            DEFAULT_NOVA_SERVICE_TYPE)

        if utils.isunauthenticated(args.func):
            # NOTE(alex_xu): We need authentication for discover microversion.
            # But the subcommands may needn't it. If the subcommand needn't,
            # we clear the session arguments.
            keystone_session = None
            keystone_auth = None

        # Recreate client object with discovered version.
        self.cs = client.Client(
            api_version,
            os_username, os_password, os_project_name,
            tenant_id=os_project_id, user_id=os_user_id,
            auth_url=os_auth_url, insecure=insecure,
            region_name=os_region_name, endpoint_type=endpoint_type,
            extensions=self.extensions, service_type=service_type,
            service_name=service_name, auth_token=auth_token,
            timings=args.timings, endpoint_override=endpoint_override,
            os_cache=os_cache, http_log_debug=args.debug,
            cacert=cacert, cert=cert, timeout=timeout,
            session=keystone_session, auth=keystone_auth,
            project_domain_id=os_project_domain_id,
            project_domain_name=os_project_domain_name,
            user_domain_id=os_user_domain_id,
            user_domain_name=os_user_domain_name)

        # Now check for the password/token of which pieces of the
        # identifying keyring key can come from the underlying client
        if must_auth:
            helper = SecretsHelper(args, self.cs.client)
            self.cs.client.keyring_saver = helper

            tenant_id = helper.tenant_id
            # Allow commandline to override cache
            if not auth_token:
                auth_token = helper.auth_token
            endpoint_override = endpoint_override or helper.management_url
            if tenant_id and auth_token and endpoint_override:
                self.cs.client.tenant_id = tenant_id
                self.cs.client.auth_token = auth_token
                self.cs.client.management_url = endpoint_override
                self.cs.client.password_func = lambda: helper.password
            else:
                # We're missing something, so auth with user/pass and save
                # the result in our helper.
                self.cs.client.password = helper.password

        args.func(self.cs, args)

        if args.timings:
            self._dump_timings(self.times + self.cs.get_timings())
Exemple #19
0
    def __call__(self, req):
        """Get the nova micro version number

        * If neither "X-OpenStack-Nova-API-Version" nor
          "OpenStack-API-Version" (specifying "compute") is provided,
          act as if the minimum supported microversion was specified.

        * If both headers are provided,
          "OpenStack-API-Version" will be preferred.

        * If "X-OpenStack-Nova-API-Version" or "OpenStack-API-Version"
          is provided, respond with the API at that microversion.
          If that's outside of the range of microversions supported,
          return 406 Not Acceptable.

        * If "X-OpenStack-Nova-API-Version" or "OpenStack-API-Version"
          has a value of "latest" (special keyword),
          act as if maximum was specified.
        """
        version_num = req.environ.get(
            constants.HTTP_NOVA_API_VERSION_REQUEST_HEADER)
        legacy_version_num = req.environ.get(
            constants.HTTP_LEGACY_NOVA_API_VERSION_REQUEST_HEADER)
        message = None
        api_version = None

        if version_num is None and legacy_version_num is None:
            micro_version = constants.NOVA_APIGW_MIN_VERSION
        elif version_num is not None:
            err_msg = ("Invalid format of client version '%s'. "
                       "Expected format 'compute X.Y',"
                       "where X is a major part and Y "
                       "is a minor part of version.") % version_num
            try:
                nova_version_prefix = version_num.split()[0]
                micro_version = ''.join(version_num.split()[1:])
                if nova_version_prefix != 'compute':
                    message = err_msg
            except Exception:
                message = err_msg
        else:
            micro_version = legacy_version_num

        if message is None:
            try:
                # Returns checked APIVersion object,
                # or raise UnsupportedVersion exceptions.
                api_version = api_versions.get_api_version(micro_version)
            except exceptions.UnsupportedVersion as e:
                message = e.message

        if message is None and api_version is not None:
            min_minor = int(constants.NOVA_APIGW_MIN_VERSION.split('.')[1])
            max_minor = int(constants.NOVA_APIGW_MAX_VERSION.split('.')[1])
            if api_version.is_latest():
                micro_version = constants.NOVA_APIGW_MAX_VERSION
                api_version.ver_minor = max_minor

            if api_version.ver_minor < min_minor or \
                    api_version.ver_minor > max_minor:
                message = ("Version %s is not supported by the API. "
                           "Minimum is %s, and maximum is %s" %
                           (micro_version, constants.NOVA_APIGW_MIN_VERSION,
                            constants.NOVA_APIGW_MAX_VERSION))

        if message is None:
            req.environ[constants.NOVA_API_VERSION_REQUEST_HEADER] = \
                micro_version
            if self.app:
                return req.get_response(self.app)
        else:
            content_type = 'application/json'
            body = jsonutils.dumps(
                self._format_error('406', message, 'computeFault'))
            response = webob.Response()
            response.content_type = content_type
            response.body = encodeutils.to_utf8(body)
            response.status_code = 406
            return response
 def test_major_and_minor_parts_is_presented(self, mock_apiversion):
     version = "2.7"
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with(version)
 def test_only_major_part_is_presented(self, mock_apiversion):
     version = 7
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with("%s.0" % str(version))
Exemple #22
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser()

        # NOTE(dtroyer): Hackery to handle --endpoint_type due to argparse
        #                thinking usage-list --end is ambiguous; but it
        #                works fine with only --endpoint-type present
        #                Go figure.
        if '--endpoint_type' in argv:
            spot = argv.index('--endpoint_type')
            argv[spot] = '--endpoint-type'

        (args, args_list) = parser.parse_known_args(argv)

        self.setup_debugging(args.debug)
        self.extensions = []
        do_help = ('help' in argv) or ('--help'
                                       in argv) or ('-h' in argv) or not argv

        # bash-completion should not require authentification
        skip_auth = do_help or ('bash-completion' in argv)

        # Discover available auth plugins
        novaclient.auth_plugin.discover_auth_systems()

        if not args.os_compute_api_version:
            api_version = api_versions.get_api_version(
                DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
        else:
            api_version = api_versions.get_api_version(
                args.os_compute_api_version)

        os_username = args.os_username
        os_user_id = args.os_user_id
        os_password = None  # Fetched and set later as needed
        os_tenant_name = args.os_tenant_name
        os_tenant_id = args.os_tenant_id
        os_auth_url = args.os_auth_url
        os_region_name = args.os_region_name
        os_auth_system = args.os_auth_system
        endpoint_type = args.endpoint_type
        insecure = args.insecure
        service_type = args.service_type
        service_name = args.service_name
        volume_service_name = args.volume_service_name
        bypass_url = args.bypass_url
        os_cache = args.os_cache
        cacert = args.os_cacert
        timeout = args.timeout

        keystone_session = None
        keystone_auth = None

        # We may have either, both or none of these.
        # If we have both, we don't need USERNAME, PASSWORD etc.
        # Fill in the blanks from the SecretsHelper if possible.
        # Finally, authenticate unless we have both.
        # Note if we don't auth we probably don't have a tenant ID so we can't
        # cache the token.
        auth_token = args.os_auth_token if args.os_auth_token else None
        management_url = bypass_url if bypass_url else None

        if os_auth_system and os_auth_system != "keystone":
            auth_plugin = novaclient.auth_plugin.load_plugin(os_auth_system)
        else:
            auth_plugin = None

        if not endpoint_type:
            endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE

        # This allow users to use endpoint_type as (internal, public or admin)
        # just like other openstack clients (glance, cinder etc)
        if endpoint_type in ['internal', 'public', 'admin']:
            endpoint_type += 'URL'

        if not service_type:
            # Note(alex_xu): We need discover version first, so if there isn't
            # service type specified, we use default nova service type.
            service_type = DEFAULT_NOVA_SERVICE_TYPE

        # If we have an auth token but no management_url, we must auth anyway.
        # Expired tokens are handled by client.py:_cs_request
        must_auth = not (auth_token and management_url)

        # Do not use Keystone session for cases with no session support. The
        # presence of auth_plugin means os_auth_system is present and is not
        # keystone.
        use_session = True
        if auth_plugin or bypass_url or os_cache or volume_service_name:
            use_session = False

        # FIXME(usrleon): Here should be restrict for project id same as
        # for os_username or os_password but for compatibility it is not.
        if must_auth and not skip_auth:
            if auth_plugin:
                auth_plugin.parse_opts(args)

            if not auth_plugin or not auth_plugin.opts:
                if not os_username and not os_user_id:
                    raise exc.CommandError(
                        _("You must provide a username "
                          "or user id via --os-username, --os-user-id, "
                          "env[OS_USERNAME] or env[OS_USER_ID]"))

            if not any([
                    args.os_tenant_name, args.os_tenant_id, args.os_project_id,
                    args.os_project_name
            ]):
                raise exc.CommandError(
                    _("You must provide a project name or"
                      " project id via --os-project-name,"
                      " --os-project-id, env[OS_PROJECT_ID]"
                      " or env[OS_PROJECT_NAME]. You may"
                      " use os-project and os-tenant"
                      " interchangeably."))

            if not os_auth_url:
                if os_auth_system and os_auth_system != 'keystone':
                    os_auth_url = auth_plugin.get_auth_url()

            if not os_auth_url:
                raise exc.CommandError(
                    _("You must provide an auth url "
                      "via either --os-auth-url or env[OS_AUTH_URL] "
                      "or specify an auth_system which defines a "
                      "default url with --os-auth-system "
                      "or env[OS_AUTH_SYSTEM]"))

            project_id = args.os_project_id or args.os_tenant_id
            project_name = args.os_project_name or args.os_tenant_name
            if use_session:
                # Not using Nova auth plugin, so use keystone
                with utils.record_time(self.times, args.timings, 'auth_url',
                                       args.os_auth_url):
                    keystone_session = (
                        ksession.Session.load_from_cli_options(args))
                    keystone_auth = self._get_keystone_auth(
                        keystone_session,
                        args.os_auth_url,
                        username=args.os_username,
                        user_id=args.os_user_id,
                        user_domain_id=args.os_user_domain_id,
                        user_domain_name=args.os_user_domain_name,
                        password=args.os_password,
                        auth_token=args.os_auth_token,
                        project_id=project_id,
                        project_name=project_name,
                        project_domain_id=args.os_project_domain_id,
                        project_domain_name=args.os_project_domain_name)
            else:
                # set password for auth plugins
                os_password = args.os_password

        if (not skip_auth and not any([
                args.os_tenant_id, args.os_tenant_name, args.os_project_id,
                args.os_project_name
        ])):
            raise exc.CommandError(
                _("You must provide a project name or"
                  " project id via --os-project-name,"
                  " --os-project-id, env[OS_PROJECT_ID]"
                  " or env[OS_PROJECT_NAME]. You may"
                  " use os-project and os-tenant"
                  " interchangeably."))

        if not os_auth_url and not skip_auth:
            raise exc.CommandError(
                _("You must provide an auth url "
                  "via either --os-auth-url or env[OS_AUTH_URL]"))

        # This client is just used to discover api version. Version API needn't
        # microversion, so we just pass version 2 at here.
        self.cs = client.Client(api_versions.APIVersion("2.0"),
                                os_username,
                                os_password,
                                os_tenant_name,
                                tenant_id=os_tenant_id,
                                user_id=os_user_id,
                                auth_url=os_auth_url,
                                insecure=insecure,
                                region_name=os_region_name,
                                endpoint_type=endpoint_type,
                                extensions=self.extensions,
                                service_type=service_type,
                                service_name=service_name,
                                auth_system=os_auth_system,
                                auth_plugin=auth_plugin,
                                auth_token=auth_token,
                                volume_service_name=volume_service_name,
                                timings=args.timings,
                                bypass_url=bypass_url,
                                os_cache=os_cache,
                                http_log_debug=args.debug,
                                cacert=cacert,
                                timeout=timeout,
                                session=keystone_session,
                                auth=keystone_auth)

        if not skip_auth:
            if not api_version.is_latest():
                if api_version > api_versions.APIVersion("2.0"):
                    if not api_version.matches(novaclient.API_MIN_VERSION,
                                               novaclient.API_MAX_VERSION):
                        raise exc.CommandError(
                            _("The specified version isn't supported by "
                              "client. The valid version range is '%(min)s' "
                              "to '%(max)s'") %
                            {
                                "min": novaclient.API_MIN_VERSION.get_string(),
                                "max": novaclient.API_MAX_VERSION.get_string()
                            })
            api_version = api_versions.discover_version(self.cs, api_version)

        # build available subcommands based on version
        self.extensions = client.discover_extensions(api_version)
        self._run_extension_hooks('__pre_parse_args__')

        subcommand_parser = self.get_subcommand_parser(api_version,
                                                       do_help=do_help)
        self.parser = subcommand_parser

        if args.help or not argv:
            subcommand_parser.print_help()
            return 0

        args = subcommand_parser.parse_args(argv)
        self._run_extension_hooks('__post_parse_args__', args)

        # Short-circuit and deal with help right away.
        if args.func == self.do_help:
            self.do_help(args)
            return 0
        elif args.func == self.do_bash_completion:
            self.do_bash_completion(args)
            return 0

        if not args.service_type:
            service_type = (cliutils.get_service_type(args.func)
                            or DEFAULT_NOVA_SERVICE_TYPE)

        if cliutils.isunauthenticated(args.func):
            # NOTE(alex_xu): We need authentication for discover microversion.
            # But the subcommands may needn't it. If the subcommand needn't,
            # we clear the session arguements.
            keystone_session = None
            keystone_auth = None

        # Recreate client object with discovered version.
        self.cs = client.Client(api_version,
                                os_username,
                                os_password,
                                os_tenant_name,
                                tenant_id=os_tenant_id,
                                user_id=os_user_id,
                                auth_url=os_auth_url,
                                insecure=insecure,
                                region_name=os_region_name,
                                endpoint_type=endpoint_type,
                                extensions=self.extensions,
                                service_type=service_type,
                                service_name=service_name,
                                auth_system=os_auth_system,
                                auth_plugin=auth_plugin,
                                auth_token=auth_token,
                                volume_service_name=volume_service_name,
                                timings=args.timings,
                                bypass_url=bypass_url,
                                os_cache=os_cache,
                                http_log_debug=args.debug,
                                cacert=cacert,
                                timeout=timeout,
                                session=keystone_session,
                                auth=keystone_auth)

        # Now check for the password/token of which pieces of the
        # identifying keyring key can come from the underlying client
        if must_auth:
            helper = SecretsHelper(args, self.cs.client)
            self.cs.client.keyring_saver = helper
            if (auth_plugin and auth_plugin.opts
                    and "os_password" not in auth_plugin.opts):
                use_pw = False
            else:
                use_pw = True

            tenant_id = helper.tenant_id
            # Allow commandline to override cache
            if not auth_token:
                auth_token = helper.auth_token
            if not management_url:
                management_url = helper.management_url
            if tenant_id and auth_token and management_url:
                self.cs.client.tenant_id = tenant_id
                self.cs.client.auth_token = auth_token
                self.cs.client.management_url = management_url
                self.cs.client.password_func = lambda: helper.password
            elif use_pw:
                # We're missing something, so auth with user/pass and save
                # the result in our helper.
                self.cs.client.password = helper.password

        try:
            # This does a couple of bits which are useful even if we've
            # got the token + service URL already. It exits fast in that case.
            if not cliutils.isunauthenticated(args.func):
                if not use_session:
                    # Only call authenticate() if Nova auth plugin is used.
                    # If keystone is used, authentication is handled as part
                    # of session.
                    self.cs.authenticate()
        except exc.Unauthorized:
            raise exc.CommandError(_("Invalid OpenStack Nova credentials."))
        except exc.AuthorizationFailure:
            raise exc.CommandError(_("Unable to authorize user"))

        args.func(self.cs, args)

        if args.timings:
            self._dump_timings(self.times + self.cs.get_timings())
Exemple #23
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser(argv)
        (args, args_list) = parser.parse_known_args(argv)

        self.setup_debugging(args.debug)
        self.extensions = []
        do_help = args.help or not args_list or args_list[0] == 'help'

        # bash-completion should not require authentication
        skip_auth = do_help or ('bash-completion' in argv)

        if not args.os_compute_api_version:
            api_version = api_versions.get_api_version(
                DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
        else:
            api_version = api_versions.get_api_version(
                args.os_compute_api_version)

        os_username = args.os_username
        os_user_id = args.os_user_id
        os_password = None  # Fetched and set later as needed
        os_project_name = getattr(args, 'os_project_name',
                                  getattr(args, 'os_tenant_name', None))
        os_project_id = getattr(args, 'os_project_id',
                                getattr(args, 'os_tenant_id', None))
        os_auth_url = args.os_auth_url
        os_region_name = args.os_region_name

        if "v2.0" not in os_auth_url:
            # NOTE(andreykurilin): assume that keystone V3 is used and try to
            # be more user-friendly, i.e provide default values for domains
            if (not args.os_project_domain_id
                    and not args.os_project_domain_name):
                setattr(args, "os_project_domain_id", "default")
            if not args.os_user_domain_id and not args.os_user_domain_name:
                setattr(args, "os_user_domain_id", "default")

        os_project_domain_id = args.os_project_domain_id
        os_project_domain_name = args.os_project_domain_name
        os_user_domain_id = args.os_project_domain_id
        os_user_domain_name = args.os_project_domain_name

        endpoint_type = args.endpoint_type
        insecure = args.insecure
        service_type = args.service_type
        service_name = args.service_name
        endpoint_override = args.endpoint_override
        os_cache = args.os_cache
        cacert = args.os_cacert
        cert = args.os_cert
        timeout = args.timeout

        keystone_session = None
        keystone_auth = None

        # We may have either, both or none of these.
        # If we have both, we don't need USERNAME, PASSWORD etc.
        # Fill in the blanks from the SecretsHelper if possible.
        # Finally, authenticate unless we have both.
        # Note if we don't auth we probably don't have a tenant ID so we can't
        # cache the token.
        auth_token = getattr(args, 'os_token', None)

        if not endpoint_type:
            endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE

        # This allow users to use endpoint_type as (internal, public or admin)
        # just like other openstack clients (glance, cinder etc)
        if endpoint_type in ['internal', 'public', 'admin']:
            endpoint_type += 'URL'

        if not service_type:
            # Note(alex_xu): We need discover version first, so if there isn't
            # service type specified, we use default nova service type.
            service_type = DEFAULT_NOVA_SERVICE_TYPE

        # We should always auth unless we have a token and we're passing a
        # specific endpoint
        # Expired tokens are handled by client.py:_cs_request
        must_auth = not (auth_token and endpoint_override)

        # FIXME(usrleon): Here should be restrict for project id same as
        # for os_username or os_password but for compatibility it is not.
        if must_auth and not skip_auth:

            if not os_username and not os_user_id:
                raise exc.CommandError(
                    _("You must provide a username "
                      "or user ID via --os-username, --os-user-id, "
                      "env[OS_USERNAME] or env[OS_USER_ID]"))

            if not any([os_project_name, os_project_id]):
                raise exc.CommandError(
                    _("You must provide a project name or"
                      " project ID via --os-project-name,"
                      " --os-project-id, env[OS_PROJECT_ID]"
                      " or env[OS_PROJECT_NAME]. You may"
                      " use os-project and os-tenant"
                      " interchangeably."))

            if not os_auth_url:
                raise exc.CommandError(
                    _("You must provide an auth url "
                      "via either --os-auth-url or env[OS_AUTH_URL]."))

            with utils.record_time(self.times, args.timings, 'auth_url',
                                   args.os_auth_url):
                keystone_session = (
                    loading.load_session_from_argparse_arguments(args))
                keystone_auth = (
                    loading.load_auth_from_argparse_arguments(args))

        if (not skip_auth and not any([os_project_name, os_project_id])):
            raise exc.CommandError(
                _("You must provide a project name or"
                  " project id via --os-project-name,"
                  " --os-project-id, env[OS_PROJECT_ID]"
                  " or env[OS_PROJECT_NAME]. You may"
                  " use os-project and os-tenant"
                  " interchangeably."))

        if not os_auth_url and not skip_auth:
            raise exc.CommandError(
                _("You must provide an auth url "
                  "via either --os-auth-url or env[OS_AUTH_URL]"))

        additional_kwargs = {}
        if osprofiler_profiler:
            additional_kwargs["profile"] = args.profile

        # This client is just used to discover api version. Version API needn't
        # microversion, so we just pass version 2 at here.
        self.cs = client.Client(api_versions.APIVersion("2.0"),
                                os_username,
                                os_password,
                                project_id=os_project_id,
                                project_name=os_project_name,
                                user_id=os_user_id,
                                auth_url=os_auth_url,
                                insecure=insecure,
                                region_name=os_region_name,
                                endpoint_type=endpoint_type,
                                extensions=self.extensions,
                                service_type=service_type,
                                service_name=service_name,
                                auth_token=auth_token,
                                timings=args.timings,
                                endpoint_override=endpoint_override,
                                os_cache=os_cache,
                                http_log_debug=args.debug,
                                cacert=cacert,
                                cert=cert,
                                timeout=timeout,
                                session=keystone_session,
                                auth=keystone_auth,
                                logger=self.client_logger,
                                project_domain_id=os_project_domain_id,
                                project_domain_name=os_project_domain_name,
                                user_domain_id=os_user_domain_id,
                                user_domain_name=os_user_domain_name,
                                **additional_kwargs)

        if not skip_auth:
            if not api_version.is_latest():
                if api_version > api_versions.APIVersion("2.0"):
                    if not api_version.matches(novaclient.API_MIN_VERSION,
                                               novaclient.API_MAX_VERSION):
                        raise exc.CommandError(
                            _("The specified version isn't supported by "
                              "client. The valid version range is '%(min)s' "
                              "to '%(max)s'") %
                            {
                                "min": novaclient.API_MIN_VERSION.get_string(),
                                "max": novaclient.API_MAX_VERSION.get_string()
                            })
            api_version = api_versions.discover_version(self.cs, api_version)

        # build available subcommands based on version
        self.extensions = client.discover_extensions(api_version)
        self._run_extension_hooks('__pre_parse_args__')

        subcommand_parser = self.get_subcommand_parser(api_version,
                                                       do_help=do_help,
                                                       argv=argv)
        self.parser = subcommand_parser

        if args.help or not argv:
            subcommand_parser.print_help()
            return 0

        args = subcommand_parser.parse_args(argv)
        self._run_extension_hooks('__post_parse_args__', args)

        # Short-circuit and deal with help right away.
        if args.func == self.do_help:
            self.do_help(args)
            return 0
        elif args.func == self.do_bash_completion:
            self.do_bash_completion(args)
            return 0

        if not args.service_type:
            service_type = (utils.get_service_type(args.func)
                            or DEFAULT_NOVA_SERVICE_TYPE)

        if utils.isunauthenticated(args.func):
            # NOTE(alex_xu): We need authentication for discover microversion.
            # But the subcommands may needn't it. If the subcommand needn't,
            # we clear the session arguments.
            keystone_session = None
            keystone_auth = None

        # Recreate client object with discovered version.
        self.cs = client.Client(api_version,
                                os_username,
                                os_password,
                                os_project_name,
                                tenant_id=os_project_id,
                                user_id=os_user_id,
                                auth_url=os_auth_url,
                                insecure=insecure,
                                region_name=os_region_name,
                                endpoint_type=endpoint_type,
                                extensions=self.extensions,
                                service_type=service_type,
                                service_name=service_name,
                                auth_token=auth_token,
                                timings=args.timings,
                                endpoint_override=endpoint_override,
                                os_cache=os_cache,
                                http_log_debug=args.debug,
                                cacert=cacert,
                                cert=cert,
                                timeout=timeout,
                                session=keystone_session,
                                auth=keystone_auth,
                                project_domain_id=os_project_domain_id,
                                project_domain_name=os_project_domain_name,
                                user_domain_id=os_user_domain_id,
                                user_domain_name=os_user_domain_name)

        # Now check for the password/token of which pieces of the
        # identifying keyring key can come from the underlying client
        if must_auth:
            helper = SecretsHelper(args, self.cs.client)
            self.cs.client.keyring_saver = helper

            tenant_id = helper.tenant_id
            # Allow commandline to override cache
            if not auth_token:
                auth_token = helper.auth_token
            endpoint_override = endpoint_override or helper.management_url
            if tenant_id and auth_token and endpoint_override:
                self.cs.client.tenant_id = tenant_id
                self.cs.client.auth_token = auth_token
                self.cs.client.management_url = endpoint_override
                self.cs.client.password_func = lambda: helper.password
            else:
                # We're missing something, so auth with user/pass and save
                # the result in our helper.
                self.cs.client.password = helper.password

        args.func(self.cs, args)

        if osprofiler_profiler and args.profile:
            trace_id = osprofiler_profiler.get().get_base_id()
            print("To display trace use the command:\n\n"
                  "  osprofiler trace show --html %s " % trace_id)

        if args.timings:
            self._dump_timings(self.times + self.cs.get_timings())
Exemple #24
0
 def is_version_supported(self, version):
     api_ver = api_versions.get_api_version(version)
     max_api_ver = api_versions.get_api_version(
         self.get_max_microversion())
     return max_api_ver >= api_ver
Exemple #25
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser(argv)
        (args, args_list) = parser.parse_known_args(argv)

        self.setup_debugging(args.debug)
        self.extensions = []
        do_help = args.help or not args_list or args_list[0] == 'help'

        # bash-completion should not require authentication
        skip_auth = do_help or (
            'bash-completion' in argv)

        if not args.os_compute_api_version:
            api_version = api_versions.get_api_version(
                DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
        else:
            api_version = api_versions.get_api_version(
                args.os_compute_api_version)

        auth_token = getattr(args, "os_token", None)

        os_username = getattr(args, "os_username", None)
        os_user_id = getattr(args, "os_user_id", None)
        os_password = None  # Fetched and set later as needed
        os_project_name = getattr(
            args, 'os_project_name', getattr(args, 'os_tenant_name', None))
        os_project_id = getattr(
            args, 'os_project_id', getattr(args, 'os_tenant_id', None))
        os_auth_url = args.os_auth_url
        os_region_name = args.os_region_name

        if "v2.0" not in os_auth_url:
            # NOTE(andreykurilin): assume that keystone V3 is used and try to
            # be more user-friendly, i.e provide default values for domains
            if (not args.os_project_domain_id and
                    not args.os_project_domain_name):
                setattr(args, "os_project_domain_id", "default")

            # os_user_domain_id is redundant in case of Token auth type
            if not auth_token and (not args.os_user_domain_id and
                                   not args.os_user_domain_name):
                setattr(args, "os_user_domain_id", "default")

        os_project_domain_id = args.os_project_domain_id
        os_project_domain_name = args.os_project_domain_name
        os_user_domain_id = getattr(args, "os_user_domain_id", None)
        os_user_domain_name = getattr(args, "os_user_domain_name", None)

        endpoint_type = args.endpoint_type
        insecure = args.insecure
        service_type = args.service_type
        service_name = args.service_name
        endpoint_override = args.endpoint_override
        os_cache = args.os_cache
        cacert = args.os_cacert
        cert = args.os_cert
        timeout = args.timeout

        keystone_session = None
        keystone_auth = None

        if not endpoint_type:
            endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE

        # This allow users to use endpoint_type as (internal, public or admin)
        # just like other openstack clients (glance, cinder etc)
        if endpoint_type in ['internal', 'public', 'admin']:
            endpoint_type += 'URL'

        if not service_type:
            # Note(alex_xu): We need discover version first, so if there isn't
            # service type specified, we use default nova service type.
            service_type = DEFAULT_NOVA_SERVICE_TYPE

        # We should always auth unless we have a token and we're passing a
        # specific endpoint
        # Expired tokens are handled by client.py:_cs_request
        must_auth = not (auth_token and endpoint_override)

        # FIXME(usrleon): Here should be restrict for project id same as
        # for os_username or os_password but for compatibility it is not.
        if must_auth and not skip_auth:

            if not any([auth_token, os_username, os_user_id]):
                raise exc.CommandError(
                    _("You must provide a user name/id (via --os-username, "
                      "--os-user-id, env[OS_USERNAME] or env[OS_USER_ID]) or "
                      "an auth token (via --os-token)."))

            if not any([os_project_name, os_project_id]):
                raise exc.CommandError(_("You must provide a project name or"
                                         " project ID via --os-project-name,"
                                         " --os-project-id, env[OS_PROJECT_ID]"
                                         " or env[OS_PROJECT_NAME]. You may"
                                         " use os-project and os-tenant"
                                         " interchangeably."))

            if not os_auth_url:
                raise exc.CommandError(
                    _("You must provide an auth url "
                      "via either --os-auth-url or env[OS_AUTH_URL]."))

            # TODO(Shilpasd): need to provide support in python - novaclient
            # for required options for below default auth type plugins:
            # 1. v3oidcclientcredential
            # 2. v3oidcpassword
            # 3. v3oidcauthcode
            # 4. v3oidcaccesstoken
            # 5. v3oauth1
            # 6. v3fedkerb
            # 7. v3adfspassword
            # 8. v3samlpassword
            # 9. v3applicationcredential
            # TODO(Shilpasd): need to provide support in python - novaclient
            # for below extra keystoneauth auth type plugins:
            # We will need to add code to support discovering of versions
            # supported by the keystone service based on the auth_url similar
            # to the one supported by glanceclient.
            # 1. v3password
            # 2. v3token
            # 3. v3kerberos
            # 4. v3totp
            with utils.record_time(self.times, args.timings,
                                   'auth_url', args.os_auth_url):
                keystone_session = (
                    loading.load_session_from_argparse_arguments(args))
                keystone_auth = (
                    loading.load_auth_from_argparse_arguments(args))

        if (not skip_auth and
                not any([os_project_name, os_project_id])):
            raise exc.CommandError(_("You must provide a project name or"
                                     " project id via --os-project-name,"
                                     " --os-project-id, env[OS_PROJECT_ID]"
                                     " or env[OS_PROJECT_NAME]. You may"
                                     " use os-project and os-tenant"
                                     " interchangeably."))

        if not os_auth_url and not skip_auth:
            raise exc.CommandError(
                _("You must provide an auth url "
                  "via either --os-auth-url or env[OS_AUTH_URL]"))

        additional_kwargs = {}
        if osprofiler_profiler:
            additional_kwargs["profile"] = args.profile

        # This client is just used to discover api version. Version API needn't
        # microversion, so we just pass version 2 at here.
        self.cs = client.Client(
            api_versions.APIVersion("2.0"),
            os_username, os_password, project_id=os_project_id,
            project_name=os_project_name, user_id=os_user_id,
            auth_url=os_auth_url, insecure=insecure,
            region_name=os_region_name, endpoint_type=endpoint_type,
            extensions=self.extensions, service_type=service_type,
            service_name=service_name, auth_token=auth_token,
            timings=args.timings, endpoint_override=endpoint_override,
            os_cache=os_cache, http_log_debug=args.debug,
            cacert=cacert, cert=cert, timeout=timeout,
            session=keystone_session, auth=keystone_auth,
            logger=self.client_logger,
            project_domain_id=os_project_domain_id,
            project_domain_name=os_project_domain_name,
            user_domain_id=os_user_domain_id,
            user_domain_name=os_user_domain_name,
            **additional_kwargs)

        if not skip_auth:
            if not api_version.is_latest():
                if api_version > api_versions.APIVersion("2.0"):
                    if not api_version.matches(novaclient.API_MIN_VERSION,
                                               novaclient.API_MAX_VERSION):
                        raise exc.CommandError(
                            _("The specified version isn't supported by "
                              "client. The valid version range is '%(min)s' "
                              "to '%(max)s'") % {
                                "min": novaclient.API_MIN_VERSION.get_string(),
                                "max": novaclient.API_MAX_VERSION.get_string()}
                        )
            api_version = api_versions.discover_version(self.cs, api_version)

        # build available subcommands based on version
        self.extensions = client.discover_extensions(api_version)
        self._run_extension_hooks('__pre_parse_args__')

        subcommand_parser = self.get_subcommand_parser(
            api_version, do_help=do_help, argv=argv)
        self.parser = subcommand_parser

        if args.help or not argv:
            subcommand_parser.print_help()
            return 0

        args = subcommand_parser.parse_args(argv)
        self._run_extension_hooks('__post_parse_args__', args)

        # Short-circuit and deal with help right away.
        if args.func == self.do_help:
            self.do_help(args)
            return 0
        elif args.func == self.do_bash_completion:
            self.do_bash_completion(args)
            return 0

        if not args.service_type:
            service_type = (utils.get_service_type(args.func) or
                            DEFAULT_NOVA_SERVICE_TYPE)

        if utils.isunauthenticated(args.func):
            # NOTE(alex_xu): We need authentication for discover microversion.
            # But the subcommands may needn't it. If the subcommand needn't,
            # we clear the session arguments.
            keystone_session = None
            keystone_auth = None

        # Recreate client object with discovered version.
        self.cs = client.Client(
            api_version,
            os_username, os_password, project_id=os_project_id,
            project_name=os_project_name, user_id=os_user_id,
            auth_url=os_auth_url, insecure=insecure,
            region_name=os_region_name, endpoint_type=endpoint_type,
            extensions=self.extensions, service_type=service_type,
            service_name=service_name, auth_token=auth_token,
            timings=args.timings, endpoint_override=endpoint_override,
            os_cache=os_cache, http_log_debug=args.debug,
            cacert=cacert, cert=cert, timeout=timeout,
            session=keystone_session, auth=keystone_auth,
            project_domain_id=os_project_domain_id,
            project_domain_name=os_project_domain_name,
            user_domain_id=os_user_domain_id,
            user_domain_name=os_user_domain_name)

        args.func(self.cs, args)

        if osprofiler_profiler and args.profile:
            trace_id = osprofiler_profiler.get().get_base_id()
            print("To display trace use the command:\n\n"
                  "  osprofiler trace show --html %s " % trace_id)

        if args.timings:
            self._dump_timings(self.times + self.cs.get_timings())
Exemple #26
0
 def is_version_supported(self, version):
     api_ver = api_versions.get_api_version(version)
     max_api_ver = api_versions.get_api_version(
         self.get_max_microversion())
     return max_api_ver >= api_ver
Exemple #27
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser()

        # NOTE(dtroyer): Hackery to handle --endpoint_type due to argparse
        #                thinking usage-list --end is ambiguous; but it
        #                works fine with only --endpoint-type present
        #                Go figure.
        if "--endpoint_type" in argv:
            spot = argv.index("--endpoint_type")
            argv[spot] = "--endpoint-type"

        (args, args_list) = parser.parse_known_args(argv)

        self.setup_debugging(args.debug)
        self.extensions = []
        do_help = ("help" in argv) or not argv

        # Discover available auth plugins
        novaclient.auth_plugin.discover_auth_systems()

        if not args.os_compute_api_version:
            api_version = api_versions.get_api_version(DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
        else:
            api_version = api_versions.get_api_version(args.os_compute_api_version)

        os_username = args.os_username
        os_user_id = args.os_user_id
        os_password = None  # Fetched and set later as needed
        os_tenant_name = args.os_tenant_name
        os_tenant_id = args.os_tenant_id
        os_auth_url = args.os_auth_url
        os_region_name = args.os_region_name
        os_auth_system = args.os_auth_system
        endpoint_type = args.endpoint_type
        insecure = args.insecure
        service_type = args.service_type
        service_name = args.service_name
        volume_service_name = args.volume_service_name
        bypass_url = args.bypass_url
        os_cache = args.os_cache
        cacert = args.os_cacert
        timeout = args.timeout

        keystone_session = None
        keystone_auth = None

        # We may have either, both or none of these.
        # If we have both, we don't need USERNAME, PASSWORD etc.
        # Fill in the blanks from the SecretsHelper if possible.
        # Finally, authenticate unless we have both.
        # Note if we don't auth we probably don't have a tenant ID so we can't
        # cache the token.
        auth_token = args.os_auth_token if args.os_auth_token else None
        management_url = bypass_url if bypass_url else None

        if os_auth_system and os_auth_system != "keystone":
            auth_plugin = novaclient.auth_plugin.load_plugin(os_auth_system)
        else:
            auth_plugin = None

        if not endpoint_type:
            endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE

        # This allow users to use endpoint_type as (internal, public or admin)
        # just like other openstack clients (glance, cinder etc)
        if endpoint_type in ["internal", "public", "admin"]:
            endpoint_type += "URL"

        if not service_type:
            # Note(alex_xu): We need discover version first, so if there isn't
            # service type specified, we use default nova service type.
            service_type = DEFAULT_NOVA_SERVICE_TYPE

        # If we have an auth token but no management_url, we must auth anyway.
        # Expired tokens are handled by client.py:_cs_request
        must_auth = not (auth_token and management_url)

        # Do not use Keystone session for cases with no session support. The
        # presence of auth_plugin means os_auth_system is present and is not
        # keystone.
        use_session = True
        if auth_plugin or bypass_url or os_cache or volume_service_name:
            use_session = False

        # FIXME(usrleon): Here should be restrict for project id same as
        # for os_username or os_password but for compatibility it is not.
        if must_auth and not do_help:
            if auth_plugin:
                auth_plugin.parse_opts(args)

            if not auth_plugin or not auth_plugin.opts:
                if not os_username and not os_user_id:
                    raise exc.CommandError(
                        _(
                            "You must provide a username "
                            "or user id via --os-username, --os-user-id, "
                            "env[OS_USERNAME] or env[OS_USER_ID]"
                        )
                    )

            if not any([args.os_tenant_name, args.os_tenant_id, args.os_project_id, args.os_project_name]):
                raise exc.CommandError(
                    _(
                        "You must provide a project name or"
                        " project id via --os-project-name,"
                        " --os-project-id, env[OS_PROJECT_ID]"
                        " or env[OS_PROJECT_NAME]. You may"
                        " use os-project and os-tenant"
                        " interchangeably."
                    )
                )

            if not os_auth_url:
                if os_auth_system and os_auth_system != "keystone":
                    os_auth_url = auth_plugin.get_auth_url()

            if not os_auth_url:
                raise exc.CommandError(
                    _(
                        "You must provide an auth url "
                        "via either --os-auth-url or env[OS_AUTH_URL] "
                        "or specify an auth_system which defines a "
                        "default url with --os-auth-system "
                        "or env[OS_AUTH_SYSTEM]"
                    )
                )

            project_id = args.os_project_id or args.os_tenant_id
            project_name = args.os_project_name or args.os_tenant_name
            if use_session:
                # Not using Nova auth plugin, so use keystone
                with utils.record_time(self.times, args.timings, "auth_url", args.os_auth_url):
                    keystone_session = ksession.Session.load_from_cli_options(args)
                    keystone_auth = self._get_keystone_auth(
                        keystone_session,
                        args.os_auth_url,
                        username=args.os_username,
                        user_id=args.os_user_id,
                        user_domain_id=args.os_user_domain_id,
                        user_domain_name=args.os_user_domain_name,
                        password=args.os_password,
                        auth_token=args.os_auth_token,
                        project_id=project_id,
                        project_name=project_name,
                        project_domain_id=args.os_project_domain_id,
                        project_domain_name=args.os_project_domain_name,
                    )

        if not do_help and not any([args.os_tenant_id, args.os_tenant_name, args.os_project_id, args.os_project_name]):
            raise exc.CommandError(
                _(
                    "You must provide a project name or"
                    " project id via --os-project-name,"
                    " --os-project-id, env[OS_PROJECT_ID]"
                    " or env[OS_PROJECT_NAME]. You may"
                    " use os-project and os-tenant"
                    " interchangeably."
                )
            )

        if not os_auth_url and not do_help:
            raise exc.CommandError(_("You must provide an auth url " "via either --os-auth-url or env[OS_AUTH_URL]"))

        # This client is just used to discover api version. Version API needn't
        # microversion, so we just pass version 2 at here.
        self.cs = client.Client(
            api_versions.APIVersion("2.0"),
            os_username,
            os_password,
            os_tenant_name,
            tenant_id=os_tenant_id,
            user_id=os_user_id,
            auth_url=os_auth_url,
            insecure=insecure,
            region_name=os_region_name,
            endpoint_type=endpoint_type,
            extensions=self.extensions,
            service_type=service_type,
            service_name=service_name,
            auth_system=os_auth_system,
            auth_plugin=auth_plugin,
            auth_token=auth_token,
            volume_service_name=volume_service_name,
            timings=args.timings,
            bypass_url=bypass_url,
            os_cache=os_cache,
            http_log_debug=args.debug,
            cacert=cacert,
            timeout=timeout,
            session=keystone_session,
            auth=keystone_auth,
        )

        if not do_help:
            if not api_version.is_latest():
                if api_version > api_versions.APIVersion("2.0"):
                    if not api_version.matches(novaclient.API_MIN_VERSION, novaclient.API_MAX_VERSION):
                        raise exc.CommandError(
                            _(
                                "The specified version isn't supported by "
                                "client. The valid version range is '%(min)s' "
                                "to '%(max)s'"
                            )
                            % {
                                "min": novaclient.API_MIN_VERSION.get_string(),
                                "max": novaclient.API_MAX_VERSION.get_string(),
                            }
                        )
            api_version = api_versions.discover_version(self.cs, api_version)

        # build available subcommands based on version
        self.extensions = client.discover_extensions(api_version)
        self._run_extension_hooks("__pre_parse_args__")

        subcommand_parser = self.get_subcommand_parser(api_version, do_help=do_help)
        self.parser = subcommand_parser

        if args.help or not argv:
            subcommand_parser.print_help()
            return 0

        args = subcommand_parser.parse_args(argv)
        self._run_extension_hooks("__post_parse_args__", args)

        # Short-circuit and deal with help right away.
        if args.func == self.do_help:
            self.do_help(args)
            return 0
        elif args.func == self.do_bash_completion:
            self.do_bash_completion(args)
            return 0

        if not args.service_type:
            service_type = cliutils.get_service_type(args.func) or DEFAULT_NOVA_SERVICE_TYPE

        if cliutils.isunauthenticated(args.func):
            # NOTE(alex_xu): We need authentication for discover microversion.
            # But the subcommands may needn't it. If the subcommand needn't,
            # we clear the session arguements.
            keystone_session = None
            keystone_auth = None

        # Recreate client object with discovered version.
        self.cs = client.Client(
            api_version,
            os_username,
            os_password,
            os_tenant_name,
            tenant_id=os_tenant_id,
            user_id=os_user_id,
            auth_url=os_auth_url,
            insecure=insecure,
            region_name=os_region_name,
            endpoint_type=endpoint_type,
            extensions=self.extensions,
            service_type=service_type,
            service_name=service_name,
            auth_system=os_auth_system,
            auth_plugin=auth_plugin,
            auth_token=auth_token,
            volume_service_name=volume_service_name,
            timings=args.timings,
            bypass_url=bypass_url,
            os_cache=os_cache,
            http_log_debug=args.debug,
            cacert=cacert,
            timeout=timeout,
            session=keystone_session,
            auth=keystone_auth,
        )

        # Now check for the password/token of which pieces of the
        # identifying keyring key can come from the underlying client
        if must_auth:
            helper = SecretsHelper(args, self.cs.client)
            self.cs.client.keyring_saver = helper
            if auth_plugin and auth_plugin.opts and "os_password" not in auth_plugin.opts:
                use_pw = False
            else:
                use_pw = True

            tenant_id = helper.tenant_id
            # Allow commandline to override cache
            if not auth_token:
                auth_token = helper.auth_token
            if not management_url:
                management_url = helper.management_url
            if tenant_id and auth_token and management_url:
                self.cs.client.tenant_id = tenant_id
                self.cs.client.auth_token = auth_token
                self.cs.client.management_url = management_url
                self.cs.client.password_func = lambda: helper.password
            elif use_pw:
                # We're missing something, so auth with user/pass and save
                # the result in our helper.
                self.cs.client.password = helper.password

        try:
            # This does a couple of bits which are useful even if we've
            # got the token + service URL already. It exits fast in that case.
            if not cliutils.isunauthenticated(args.func):
                if not use_session:
                    # Only call authenticate() if Nova auth plugin is used.
                    # If keystone is used, authentication is handled as part
                    # of session.
                    self.cs.authenticate()
        except exc.Unauthorized:
            raise exc.CommandError(_("Invalid OpenStack Nova credentials."))
        except exc.AuthorizationFailure:
            raise exc.CommandError(_("Unable to authorize user"))

        args.func(self.cs, args)

        if args.timings:
            self._dump_timings(self.times + self.cs.get_timings())
 def test_major_and_minor_parts_is_presented(self, mock_apiversion):
     version = "2.7"
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with(version)
 def test_only_major_part_is_presented(self, mock_apiversion):
     version = 7
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with("%s.0" % str(version))
Exemple #30
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser(argv)
        (args, args_list) = parser.parse_known_args(argv)

        self.setup_debugging(args.debug)
        self.extensions = []
        do_help = args.help or not args_list or args_list[0] == 'help'

        # bash-completion should not require authentication
        skip_auth = do_help or ('bash-completion' in argv)

        if not args.os_compute_api_version:
            api_version = api_versions.get_api_version(
                DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
        else:
            api_version = api_versions.get_api_version(
                args.os_compute_api_version)

        auth_token = getattr(args, "os_token", None)

        os_username = getattr(args, "os_username", None)
        os_user_id = getattr(args, "os_user_id", None)
        os_password = None  # Fetched and set later as needed
        os_project_name = getattr(args, 'os_project_name',
                                  getattr(args, 'os_tenant_name', None))
        os_project_id = getattr(args, 'os_project_id',
                                getattr(args, 'os_tenant_id', None))
        os_auth_url = args.os_auth_url
        os_region_name = args.os_region_name

        if "v2.0" not in os_auth_url:
            # NOTE(andreykurilin): assume that keystone V3 is used and try to
            # be more user-friendly, i.e provide default values for domains
            if (not args.os_project_domain_id
                    and not args.os_project_domain_name):
                setattr(args, "os_project_domain_id", "default")

            # os_user_domain_id is redundant in case of Token auth type
            if not auth_token and (not args.os_user_domain_id
                                   and not args.os_user_domain_name):
                setattr(args, "os_user_domain_id", "default")

        os_project_domain_id = args.os_project_domain_id
        os_project_domain_name = args.os_project_domain_name
        os_user_domain_id = getattr(args, "os_user_domain_id", None)
        os_user_domain_name = getattr(args, "os_user_domain_name", None)

        endpoint_type = args.endpoint_type
        insecure = args.insecure
        service_type = args.service_type
        service_name = args.service_name
        endpoint_override = args.endpoint_override
        os_cache = args.os_cache
        cacert = args.os_cacert
        cert = args.os_cert
        timeout = args.timeout

        keystone_session = None
        keystone_auth = None

        if not endpoint_type:
            endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE

        # This allow users to use endpoint_type as (internal, public or admin)
        # just like other openstack clients (glance, cinder etc)
        if endpoint_type in ['internal', 'public', 'admin']:
            endpoint_type += 'URL'

        if not service_type:
            # Note(alex_xu): We need discover version first, so if there isn't
            # service type specified, we use default nova service type.
            service_type = DEFAULT_NOVA_SERVICE_TYPE

        # We should always auth unless we have a token and we're passing a
        # specific endpoint
        # Expired tokens are handled by client.py:_cs_request
        must_auth = not (auth_token and endpoint_override)

        # FIXME(usrleon): Here should be restrict for project id same as
        # for os_username or os_password but for compatibility it is not.
        if must_auth and not skip_auth:

            if not any([auth_token, os_username, os_user_id]):
                raise exc.CommandError(
                    _("You must provide a user name/id (via --os-username, "
                      "--os-user-id, env[OS_USERNAME] or env[OS_USER_ID]) or "
                      "an auth token (via --os-token)."))

            if not any([os_project_name, os_project_id]):
                raise exc.CommandError(
                    _("You must provide a project name or"
                      " project ID via --os-project-name,"
                      " --os-project-id, env[OS_PROJECT_ID]"
                      " or env[OS_PROJECT_NAME]. You may"
                      " use os-project and os-tenant"
                      " interchangeably."))

            if not os_auth_url:
                raise exc.CommandError(
                    _("You must provide an auth url "
                      "via either --os-auth-url or env[OS_AUTH_URL]."))

            # TODO(Shilpasd): need to provide support in python - novaclient
            # for required options for below default auth type plugins:
            # 1. v3oidcclientcredential
            # 2. v3oidcpassword
            # 3. v3oidcauthcode
            # 4. v3oidcaccesstoken
            # 5. v3oauth1
            # 6. v3fedkerb
            # 7. v3adfspassword
            # 8. v3samlpassword
            # 9. v3applicationcredential
            # TODO(Shilpasd): need to provide support in python - novaclient
            # for below extra keystoneauth auth type plugins:
            # We will need to add code to support discovering of versions
            # supported by the keystone service based on the auth_url similar
            # to the one supported by glanceclient.
            # 1. v3password
            # 2. v3token
            # 3. v3kerberos
            # 4. v3totp
            with utils.record_time(self.times, args.timings, 'auth_url',
                                   args.os_auth_url):
                keystone_session = (
                    loading.load_session_from_argparse_arguments(args))
                keystone_auth = (
                    loading.load_auth_from_argparse_arguments(args))

        if (not skip_auth and not any([os_project_name, os_project_id])):
            raise exc.CommandError(
                _("You must provide a project name or"
                  " project id via --os-project-name,"
                  " --os-project-id, env[OS_PROJECT_ID]"
                  " or env[OS_PROJECT_NAME]. You may"
                  " use os-project and os-tenant"
                  " interchangeably."))

        if not os_auth_url and not skip_auth:
            raise exc.CommandError(
                _("You must provide an auth url "
                  "via either --os-auth-url or env[OS_AUTH_URL]"))

        additional_kwargs = {}
        if osprofiler_profiler:
            additional_kwargs["profile"] = args.profile

        # This client is just used to discover api version. Version API needn't
        # microversion, so we just pass version 2 at here.
        self.cs = client.Client(api_versions.APIVersion("2.0"),
                                os_username,
                                os_password,
                                project_id=os_project_id,
                                project_name=os_project_name,
                                user_id=os_user_id,
                                auth_url=os_auth_url,
                                insecure=insecure,
                                region_name=os_region_name,
                                endpoint_type=endpoint_type,
                                extensions=self.extensions,
                                service_type=service_type,
                                service_name=service_name,
                                auth_token=auth_token,
                                timings=args.timings,
                                endpoint_override=endpoint_override,
                                os_cache=os_cache,
                                http_log_debug=args.debug,
                                cacert=cacert,
                                cert=cert,
                                timeout=timeout,
                                session=keystone_session,
                                auth=keystone_auth,
                                logger=self.client_logger,
                                project_domain_id=os_project_domain_id,
                                project_domain_name=os_project_domain_name,
                                user_domain_id=os_user_domain_id,
                                user_domain_name=os_user_domain_name,
                                **additional_kwargs)

        if not skip_auth:
            if not api_version.is_latest():
                if api_version > api_versions.APIVersion("2.0"):
                    if not api_version.matches(novaclient.API_MIN_VERSION,
                                               novaclient.API_MAX_VERSION):
                        raise exc.CommandError(
                            _("The specified version isn't supported by "
                              "client. The valid version range is '%(min)s' "
                              "to '%(max)s'") %
                            {
                                "min": novaclient.API_MIN_VERSION.get_string(),
                                "max": novaclient.API_MAX_VERSION.get_string()
                            })
            api_version = api_versions.discover_version(self.cs, api_version)

        # build available subcommands based on version
        self.extensions = client.discover_extensions(api_version)
        self._run_extension_hooks('__pre_parse_args__')

        subcommand_parser = self.get_subcommand_parser(api_version,
                                                       do_help=do_help,
                                                       argv=argv)
        self.parser = subcommand_parser

        if args.help or not argv:
            subcommand_parser.print_help()
            return 0

        args = subcommand_parser.parse_args(argv)
        self._run_extension_hooks('__post_parse_args__', args)

        # Short-circuit and deal with help right away.
        if args.func == self.do_help:
            self.do_help(args)
            return 0
        elif args.func == self.do_bash_completion:
            self.do_bash_completion(args)
            return 0

        if not args.service_type:
            service_type = (utils.get_service_type(args.func)
                            or DEFAULT_NOVA_SERVICE_TYPE)

        if utils.isunauthenticated(args.func):
            # NOTE(alex_xu): We need authentication for discover microversion.
            # But the subcommands may needn't it. If the subcommand needn't,
            # we clear the session arguments.
            keystone_session = None
            keystone_auth = None

        # Recreate client object with discovered version.
        self.cs = client.Client(api_version,
                                os_username,
                                os_password,
                                project_id=os_project_id,
                                project_name=os_project_name,
                                user_id=os_user_id,
                                auth_url=os_auth_url,
                                insecure=insecure,
                                region_name=os_region_name,
                                endpoint_type=endpoint_type,
                                extensions=self.extensions,
                                service_type=service_type,
                                service_name=service_name,
                                auth_token=auth_token,
                                timings=args.timings,
                                endpoint_override=endpoint_override,
                                os_cache=os_cache,
                                http_log_debug=args.debug,
                                cacert=cacert,
                                cert=cert,
                                timeout=timeout,
                                session=keystone_session,
                                auth=keystone_auth,
                                project_domain_id=os_project_domain_id,
                                project_domain_name=os_project_domain_name,
                                user_domain_id=os_user_domain_id,
                                user_domain_name=os_user_domain_name)

        args.func(self.cs, args)

        if osprofiler_profiler and args.profile:
            trace_id = osprofiler_profiler.get().get_base_id()
            print("To display trace use the command:\n\n"
                  "  osprofiler trace show --html %s " % trace_id)

        if args.timings:
            self._dump_timings(self.times + self.cs.get_timings())