Esempio n. 1
0
    def __init__(self, opts):
        super(OpenStackProvider, self).__init__(opts)

        # NOTE(aloga): we do not want a project to be passed from the CLI,
        # as we will iterate over it for each configured VO and project.  We
        # have not added these arguments to the parser, but, since the plugin
        # is expecting them when parsing the arguments we need to set them to
        # None before calling the load_auth_from_argparse_arguments. However,
        # we may receive this in the "opts" namespace, therefore we do not set
        # it this is passed.
        if "os_project_name" not in opts:
            opts.os_project_name = None
            opts.os_tenant_name = None
        if "os_project_id" not in opts:
            opts.os_project_id = None
            opts.os_tenant_id = None

        # need to keep this to be able to rescope
        self.opts = opts
        self.auth_plugin = loading.load_auth_from_argparse_arguments(opts)

        self.session = loading.load_session_from_argparse_arguments(
            opts, auth=self.auth_plugin
        )

        # Hide urllib3 warnings when allowing unverified connection
        if opts.insecure:
            requests.packages.urllib3.disable_warnings()

        self.nova = novaclient.client.Client(2, session=self.session)
        self.glance = glanceclient.Client('2', session=self.session)

        try:
            self.project_id = self.session.get_project_id()
        except http_exc.Unauthorized:
            msg = "Could not authorize user"
            raise exceptions.OpenStackProviderException(msg)

        self.static = providers.static.StaticProvider(opts)
        self.insecure = opts.insecure
        self.all_images = opts.all_images

        # Retieve information about Keystone endpoint SSL configuration
        e_cert_info = ssl_utils.get_endpoint_ca_information(opts.os_auth_url,
                                                            opts.insecure,
                                                            opts.os_cacert)
        self.keystone_cert_issuer = e_cert_info['issuer']
        self.keystone_trusted_cas = e_cert_info['trusted_cas']
        self.os_cacert = opts.os_cacert
        # Select 'public', 'private' or 'all' (default) templates.
        self.select_flavors = opts.select_flavors
        # GOCDB info
        self.goc_info = {}
Esempio n. 2
0
    def test_env_overrides_default_opt(self, m):
        name = uuid.uuid4().hex
        val = uuid.uuid4().hex
        self.env('OS_A_STR', val)

        klass = loading.register_auth_argparse_arguments(self.p,
                                                         [],
                                                         default=name)
        self.assertIsInstance(klass, utils.MockLoader)
        opts = self.p.parse_args([])
        a = loading.load_auth_from_argparse_arguments(opts)

        self.assertEqual(val, a['a_str'])
Esempio n. 3
0
    def test_default_options(self, m):
        name = uuid.uuid4().hex
        argv = ['--os-auth-type', name,
                '--os-a-float', str(self.a_float)]

        klass = loading.register_auth_argparse_arguments(self.p, argv)
        self.assertIsInstance(klass, utils.MockLoader)

        opts = self.p.parse_args(argv)
        self.assertEqual(name, opts.os_auth_type)

        a = loading.load_auth_from_argparse_arguments(opts)

        self.assertEqual(self.a_float, a['a_float'])
        self.assertEqual(3, a['a_int'])
Esempio n. 4
0
    def client(self):
        # NOTE(sileht): we lazy load the client to not
        # load/connect auth stuffs
        if self._client is None:
            if hasattr(self.options, "endpoint"):
                endpoint_override = self.options.endpoint
            else:
                endpoint_override = None
            auth_plugin = loading.load_auth_from_argparse_arguments(
                self.options)
            session = loading.load_session_from_argparse_arguments(
                self.options, auth=auth_plugin)

            self._client = client.Client(self.options.aodh_api_version,
                                         session=session,
                                         interface=self.options.interface,
                                         region_name=self.options.region_name,
                                         endpoint_override=endpoint_override)
        return self._client
Esempio n. 5
0
    def client(self):
        if self._client is None:
            if hasattr(self.options, "endpoint"):
                endpoint_override = self.options.endpoint
            else:
                endpoint_override = None
            auth_plugin = loading.load_auth_from_argparse_arguments(
                self.options)
            session = loading.load_session_from_argparse_arguments(
                self.options, auth=auth_plugin)

            # noinspection PyAttributeOutsideInit
            self._client = client.Client(
                self.options.vitrage_api_version,
                session=session,
                interface=self.options.interface,
                region_name=self.options.region_name,
                endpoint_override=endpoint_override)

        return self._client
Esempio n. 6
0
    def test_param_loading(self, m):
        name = uuid.uuid4().hex
        argv = ['--os-auth-type', name,
                '--os-a-int', str(self.a_int),
                '--os-a-float', str(self.a_float),
                '--os-a-bool', str(self.a_bool)]

        klass = loading.register_auth_argparse_arguments(self.p, argv)
        self.assertIsInstance(klass, utils.MockLoader)

        opts = self.p.parse_args(argv)
        self.assertEqual(name, opts.os_auth_type)

        a = loading.load_auth_from_argparse_arguments(opts)
        self.assertTestVals(a)

        self.assertEqual(name, opts.os_auth_type)
        self.assertEqual(str(self.a_int), opts.os_a_int)
        self.assertEqual(str(self.a_float), opts.os_a_float)
        self.assertEqual(str(self.a_bool), opts.os_a_bool)
Esempio n. 7
0
    def __init__(self, opts):
        super(OpenStackProvider, self).__init__(opts)

        # NOTE(aloga): we do not want a project to be passed from the CLI,
        # as we will iterate over it for each configured VO and project.  We
        # have not added these arguments to the parser, but, since the plugin
        # is expecting them when parsing the arguments we need to set them to
        # None before calling the load_auth_from_argparse_arguments. However,
        # we may receive this in the "opts" namespace, therefore we do not set
        # it this is passed.
        if "os_project_name" not in opts:
            opts.os_project_name = None
        if "os_project_id" not in opts:
            opts.os_project_id = None

        self.auth_plugin = loading.load_auth_from_argparse_arguments(opts)

        self.session = loading.load_session_from_argparse_arguments(
            opts, auth=self.auth_plugin
        )

        self.os_tenant_id = None

        # Hide urllib3 warnings when allowing unverified connection
        if opts.insecure:
            requests.packages.urllib3.disable_warnings()

        self.nova = novaclient.client.Client(2, session=self.session)
        self.glance = glanceclient.Client('2', session=self.session)

        self.static = providers.static.StaticProvider(opts)
        self.legacy_occi_os = opts.legacy_occi_os
        self.insecure = opts.insecure

        # Retieve information about Keystone endpoint SSL configuration
        e_cert_info = self._get_endpoint_ca_information(opts.os_auth_url,
                                                        opts.insecure,
                                                        opts.os_cacert)
        self.keystone_cert_issuer = e_cert_info['issuer']
        self.keystone_trusted_cas = e_cert_info['trusted_cas']
        self.os_cacert = opts.os_cacert
Esempio n. 8
0
    def client(self):
        # NOTE(sileht): we lazy load the client to not
        # load/connect auth stuffs
        if self._client is None:
            auth_plugin = loading.load_auth_from_argparse_arguments(
                self.options)
            session = loading.load_session_from_argparse_arguments(
                self.options, auth=auth_plugin)

            if isinstance(auth_plugin, (auth.GnocchiNoAuthPlugin,
                                        auth.GnocchiBasicPlugin)):
                # Normal endpoint
                kwargs = dict(
                    version=self.options.gnocchi_api_version,
                    session=session,
                )
            else:
                # Openstck style endpoint
                kwargs = dict(
                    version=(self.options.os_metric_api_version or
                             self.options.os_api_version or
                             self.options.gnocchi_api_version),
                    session=session,
                    adapter_options=dict(
                        service_type=(self.options.os_metric_service_type or
                                      self.options.os_service_type),
                        service_name=(self.options.os_metric_service_name or
                                      self.options.os_service_name),
                        interface=(self.options.os_metric_interface or
                                   self.options.os_interface),
                        region_name=self.options.os_region_name,
                        endpoint_override=(
                            self.options.os_metric_endpoint_override or
                            self.options.os_endpoint_override or
                            self.options.endpoint),
                    )
                )
            self._client = client.Client(**kwargs)
        return self._client
Esempio n. 9
0
    def _rescope_project(self, project_id):
        '''Switch to new OS project whenever there is a change.

           It updates every OpenStack client used in case of new project.
        '''
        if (not self.project_id or project_id != self.project_id):
            self.opts.os_project_id = project_id
            # make sure that it also works for v2voms
            self.opts.os_tenant_id = project_id
            self.auth_plugin = loading.load_auth_from_argparse_arguments(
                self.opts
            )
            self.session = loading.load_session_from_argparse_arguments(
                self.opts, auth=self.auth_plugin
            )
            self.auth_plugin.invalidate()
            try:
                self.project_id = self.session.get_project_id()
            except http_exc.Unauthorized:
                msg = "Could not authorize user in project '%s'" % project_id
                raise exceptions.OpenStackProviderException(msg)
            # make sure the clients know about the change
            self.nova = novaclient.client.Client(2, session=self.session)
            self.glance = glanceclient.Client('2', session=self.session)
Esempio n. 10
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser(argv)

        # 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'
            # NOTE(Vek): Not emitting a warning here, as that will
            #            occur when "--endpoint-type" is processed

        # For backwards compat with old os-auth-token parameter
        if '--os-auth-token' in argv:
            spot = argv.index('--os-auth-token')
            argv[spot] = '--os-token'
            print(_('WARNING: Option "%(option)s" is deprecated; %(use)s') % {
                'option':
                '--os-auth-token',
                'use':
                _('use "%s"; this option will be removed in '
                  'novaclient 3.3.0.') % '--os-token',
            },
                  file=sys.stderr)

        (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 authentication
        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_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
        os_auth_system = args.os_auth_system

        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")

        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 = getattr(args, 'os_token', None)
        management_url = bypass_url if bypass_url else None

        if os_auth_system and os_auth_system != "keystone":
            warnings.warn(
                _('novaclient auth plugins that are not keystone are deprecated.'
                  ' Auth plugins should now be done as plugins to keystoneauth'
                  ' and selected with --os-auth-type or OS_AUTH_TYPE'))
            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([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:
                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]"))

            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 = (
                        loading.load_session_from_argparse_arguments(args))
                    keystone_auth = (
                        loading.load_auth_from_argparse_arguments(args))
            else:
                # set password for auth plugins
                os_password = args.os_password

        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,
                                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_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,
                                                       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_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 utils.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())
Esempio n. 11
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())
Esempio n. 12
0
    def main(self, argv):

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

        template_file = args.template_file
        template_type = args.template_type
        output_file = args.output_file
        validate_only = args.validate_only
        deploy = args.deploy
        stack_name = args.stack_name

        parsed_params = {}
        if args.parameters:
            parsed_params = self._parse_parameters(args.parameters)

        a_file = os.path.isfile(template_file)
        a_url = UrlUtils.validate_url(template_file) if not a_file else False
        if a_file or a_url:
            if validate_only:
                ToscaTemplate(template_file, parsed_params, a_file)
                msg = (_('The input "%(template_file)s" successfully passed '
                         'validation.') % {'template_file': template_file})
                print(msg)
            else:
                if keystone_client_avail:
                    try:
                        keystone_auth = (
                            loading.load_auth_from_argparse_arguments(args)
                        )
                        keystone_session = (
                            loading.load_session_from_argparse_arguments(
                                args,
                                auth=keystone_auth
                            )
                        )
                        images.SESSION = keystone_session
                        flavors.SESSION = keystone_session
                    except Exception:
                        keystone_session = None

                translator = self._get_translator(template_type,
                                                  template_file,
                                                  parsed_params, a_file,
                                                  deploy)

                if translator and deploy:
                    if not keystone_client_avail or not heat_client_avail:
                        raise RuntimeError(_('Could not find Heat or Keystone'
                                             'client to deploy, aborting '))
                    if not keystone_session:
                        raise RuntimeError(_('Impossible to login with '
                                             'Keystone to deploy on Heat, '
                                             'please check your credentials'))

                    file_name = os.path.basename(
                        os.path.splitext(template_file)[0])
                    self.deploy_on_heat(keystone_session, keystone_auth,
                                        translator, stack_name, file_name,
                                        parsed_params)

                self._write_output(translator, output_file)
        else:
            msg = (_('The path %(template_file)s is not a valid '
                     'file or URL.') % {'template_file': template_file})

            log.error(msg)
            raise ValueError(msg)
Esempio n. 13
0
    def main(self, argv):

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

        template_file = args.template_file
        template_type = args.template_type
        output_file = args.output_file
        validate_only = args.validate_only
        deploy = args.deploy
        stack_name = args.stack_name

        parsed_params = {}
        if args.parameters:
            parsed_params = self._parse_parameters(args.parameters)

        a_file = os.path.isfile(template_file)
        a_url = UrlUtils.validate_url(template_file) if not a_file else False
        if a_file or a_url:
            if validate_only:
                ToscaTemplate(template_file, parsed_params, a_file)
                msg = (_('The input "%(template_file)s" successfully passed '
                         'validation.') % {'template_file': template_file})
                print(msg)
            else:
                if keystone_client_avail:
                    try:
                        keystone_auth = (
                            loading.load_auth_from_argparse_arguments(args)
                        )
                        keystone_session = (
                            loading.load_session_from_argparse_arguments(
                                args,
                                auth=keystone_auth
                            )
                        )
                        images.SESSION = keystone_session
                        flavors.SESSION = keystone_session
                    except Exception:
                        keystone_session = None

                hot = self._translate(template_type, template_file,
                                      parsed_params, a_file, deploy)
                if hot and deploy:
                    if not keystone_client_avail or not heat_client_avail:
                        raise RuntimeError(_('Could not find Heat or Keystone'
                                             'client to deploy, aborting '))
                    if not keystone_session:
                        raise RuntimeError(_('Impossible to login with '
                                             'Keystone to deploy on Heat, '
                                             'please check your credentials'))

                    file_name = os.path.basename(
                        os.path.splitext(template_file)[0])
                    self.deploy_on_heat(keystone_session, keystone_auth,
                                        hot, stack_name, file_name,
                                        parsed_params)

                self._write_output(hot, output_file)
        else:
            msg = (_('The path %(template_file)s is not a valid '
                     'file or URL.') % {'template_file': template_file})

            log.error(msg)
            raise ValueError(msg)
Esempio n. 14
0
 def test_load_with_nothing(self):
     loading.register_auth_argparse_arguments(self.p, [])
     opts = self.p.parse_args([])
     self.assertIsNone(loading.load_auth_from_argparse_arguments(opts))
Esempio n. 15
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser()
        (options, args) = parser.parse_known_args(argv)
        self.setup_debugging(options.debug)
        api_version_input = True
        self.options = options

        do_help = ('help' in argv) or (
            '--help' in argv) or ('-h' in argv) or not argv

        if not options.os_volume_api_version:
            api_version = api_versions.get_api_version(
                DEFAULT_MAJOR_OS_VOLUME_API_VERSION)
        else:
            api_version = api_versions.get_api_version(
                options.os_volume_api_version)

        # build available subcommands based on version
        major_version_string = "%s" % api_version.ver_major
        self.extensions = client.discover_extensions(major_version_string)
        self._run_extension_hooks('__pre_parse_args__')

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

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

        argv = self._delimit_metadata_args(argv)
        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

        (os_username, os_password, os_tenant_name, os_auth_url,
         os_region_name, os_tenant_id, endpoint_type,
         service_type, service_name, volume_service_name, os_endpoint,
         cacert, os_auth_type) = (
             args.os_username, args.os_password,
             args.os_tenant_name, args.os_auth_url,
             args.os_region_name, args.os_tenant_id,
             args.os_endpoint_type,
             args.service_type, args.service_name,
             args.volume_service_name,
             args.os_endpoint, args.os_cacert,
             args.os_auth_type)
        auth_session = None

        if os_auth_type and os_auth_type != "keystone":
            auth_plugin = loading.load_auth_from_argparse_arguments(
                self.options)
            auth_session = loading.load_session_from_argparse_arguments(
                self.options, auth=auth_plugin)
        else:
            auth_plugin = None

        if not service_type:
            service_type = client.SERVICE_TYPES[major_version_string]

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

        # V3 stuff
        project_info_provided = ((self.options.os_tenant_name or
                                  self.options.os_tenant_id) or
                                 (self.options.os_project_name and
                                  (self.options.os_project_domain_name or
                                   self.options.os_project_domain_id)) or
                                 self.options.os_project_id)

        # NOTE(e0ne): if auth_session exists it means auth plugin created
        # session and we don't need to check for password and other
        # authentification-related things.
        if not utils.isunauthenticated(args.func) and not auth_session:
            if not os_password:
                # No password, If we've got a tty, try prompting for it
                if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
                    # Check for Ctl-D
                    try:
                        os_password = getpass.getpass('OS Password: '******'t have a tty or the
                # user Ctl-D when prompted.
                if not os_password:
                    raise exc.CommandError("You must provide a password "
                                           "through --os-password, "
                                           "env[OS_PASSWORD] "
                                           "or, prompted response.")

            if not project_info_provided:
                raise exc.CommandError(_(
                    "You must provide a tenant_name, tenant_id, "
                    "project_id or project_name (with "
                    "project_domain_name or project_domain_id) via "
                    "  --os-tenant-name (env[OS_TENANT_NAME]),"
                    "  --os-tenant-id (env[OS_TENANT_ID]),"
                    "  --os-project-id (env[OS_PROJECT_ID])"
                    "  --os-project-name (env[OS_PROJECT_NAME]),"
                    "  --os-project-domain-id "
                    "(env[OS_PROJECT_DOMAIN_ID])"
                    "  --os-project-domain-name "
                    "(env[OS_PROJECT_DOMAIN_NAME])"
                ))

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

        if not project_info_provided:
            raise exc.CommandError(_(
                "You must provide a tenant_name, tenant_id, "
                "project_id or project_name (with "
                "project_domain_name or project_domain_id) via "
                "  --os-tenant-name (env[OS_TENANT_NAME]),"
                "  --os-tenant-id (env[OS_TENANT_ID]),"
                "  --os-project-id (env[OS_PROJECT_ID])"
                "  --os-project-name (env[OS_PROJECT_NAME]),"
                "  --os-project-domain-id "
                "(env[OS_PROJECT_DOMAIN_ID])"
                "  --os-project-domain-name "
                "(env[OS_PROJECT_DOMAIN_NAME])"
            ))

        if not os_auth_url and not auth_plugin:
            raise exc.CommandError(
                "You must provide an authentication URL "
                "through --os-auth-url or env[OS_AUTH_URL].")

        if not auth_session:
            auth_session = self._get_keystone_session()

        insecure = self.options.insecure

        self.cs = client.Client(
            api_version, os_username,
            os_password, os_tenant_name, os_auth_url,
            region_name=os_region_name,
            tenant_id=os_tenant_id,
            endpoint_type=endpoint_type,
            extensions=self.extensions,
            service_type=service_type,
            service_name=service_name,
            volume_service_name=volume_service_name,
            bypass_url=os_endpoint,
            retries=options.retries,
            http_log_debug=args.debug,
            insecure=insecure,
            cacert=cacert, auth_system=os_auth_type,
            auth_plugin=auth_plugin,
            session=auth_session,
            logger=self.ks_logger if auth_session else self.client_logger)

        try:
            if not utils.isunauthenticated(args.func):
                self.cs.authenticate()
        except exc.Unauthorized:
            raise exc.CommandError("OpenStack credentials are not valid.")
        except exc.AuthorizationFailure:
            raise exc.CommandError("Unable to authorize user.")

        endpoint_api_version = None
        # Try to get the API version from the endpoint URL.  If that fails fall
        # back to trying to use what the user specified via
        # --os-volume-api-version or with the OS_VOLUME_API_VERSION environment
        # variable.  Fail safe is to use the default API setting.
        try:
            endpoint_api_version = \
                self.cs.get_volume_api_version_from_endpoint()
        except exc.UnsupportedVersion:
            endpoint_api_version = options.os_volume_api_version
            if api_version_input:
                logger.warning("Cannot determine the API version from "
                               "the endpoint URL. Falling back to the "
                               "user-specified version: %s",
                               endpoint_api_version)
            else:
                logger.warning("Cannot determine the API version from the "
                               "endpoint URL or user input. Falling back "
                               "to the default API version: %s",
                               endpoint_api_version)

        profile = osprofiler_profiler and options.profile
        if profile:
            osprofiler_profiler.init(options.profile)

        try:
            args.func(self.cs, args)
        finally:
            if profile:
                trace_id = osprofiler_profiler.get().get_base_id()
                print("Trace ID: %s" % trace_id)
                print("To display trace use next command:\n"
                      "osprofiler trace show --html %s " % trace_id)
Esempio n. 16
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        parser = self.get_base_parser(argv)

        # 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'
            # NOTE(Vek): Not emitting a warning here, as that will
            #            occur when "--endpoint-type" is processed

        # For backwards compat with old os-auth-token parameter
        if '--os-auth-token' in argv:
            spot = argv.index('--os-auth-token')
            argv[spot] = '--os-token'
            print(_('WARNING: Option "%(option)s" is deprecated; %(use)s') % {
                'option': '--os-auth-token',
                'use': _('use "%s"; this option will be removed in '
                         'novaclient 3.3.0.') % '--os-token',
            }, file=sys.stderr)

        (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 authentication
        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_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
        os_auth_system = args.os_auth_system

        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")

        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 = getattr(args, 'os_token', None)
        management_url = bypass_url if bypass_url else None

        if os_auth_system and os_auth_system != "keystone":
            warnings.warn(_(
                'novaclient auth plugins that are not keystone are deprecated.'
                ' Auth plugins should now be done as plugins to keystoneauth'
                ' and selected with --os-auth-type or OS_AUTH_TYPE'))
            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([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:
                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]"))

            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 = (
                        loading.load_session_from_argparse_arguments(args))
                    keystone_auth = (
                        loading.load_auth_from_argparse_arguments(args))
            else:
                # set password for auth plugins
                os_password = args.os_password

        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, 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_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, 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_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 utils.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())
Esempio n. 17
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())
Esempio n. 18
0
    def main(self, argv):
        # Parse args once to find version and debug settings
        for filter in FILTER_CHECK:
            if filter in argv:
                self.check_duplicate_filters(argv, filter)
                break
        parser = self.get_base_parser()
        (options, args) = parser.parse_known_args(argv)
        self.setup_debugging(options.debug)
        api_version_input = True
        self.options = options

        do_help = ('help' in argv) or ('--help'
                                       in argv) or ('-h' in argv) or not argv

        api_version = self._validate_input_api_version(options)

        # build available subcommands based on version
        major_version_string = "%s" % api_version.ver_major
        self.extensions = client.discover_extensions(major_version_string)
        self._run_extension_hooks('__pre_parse_args__')

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

        if argv and len(argv) > 1 and '--help' in argv:
            argv = [x for x in argv if x != '--help']
            if argv[0] in self.subcommands:
                self.subcommands[argv[0]].print_help()
                return 0

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

        argv = self._delimit_metadata_args(argv)
        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

        (os_username, os_password, os_project_name, os_auth_url,
         os_region_name, os_project_id, endpoint_type, service_type,
         service_name, volume_service_name, os_endpoint, cacert,
         os_auth_type) = (args.os_username, args.os_password,
                          args.os_project_name, args.os_auth_url,
                          args.os_region_name, args.os_project_id,
                          args.os_endpoint_type, args.service_type,
                          args.service_name, args.volume_service_name,
                          args.os_endpoint, args.os_cacert, args.os_auth_type)
        auth_session = None

        if os_auth_type and os_auth_type != "keystone":
            auth_plugin = loading.load_auth_from_argparse_arguments(
                self.options)
            auth_session = loading.load_session_from_argparse_arguments(
                self.options, auth=auth_plugin)
        else:
            auth_plugin = None

        if not service_type:
            service_type = client.SERVICE_TYPES[major_version_string]

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

        # V3 stuff
        project_info_provided = ((self.options.os_project_name and
                                  (self.options.os_project_domain_name
                                   or self.options.os_project_domain_id))
                                 or self.options.os_project_id
                                 or self.options.os_project_name)

        # NOTE(e0ne): if auth_session exists it means auth plugin created
        # session and we don't need to check for password and other
        # authentification-related things.
        if not utils.isunauthenticated(args.func) and not auth_session:
            if not os_password:
                # No password, If we've got a tty, try prompting for it
                if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
                    # Check for Ctl-D
                    try:
                        os_password = getpass.getpass('OS Password: '******'t have a tty or the
                # user Ctl-D when prompted.
                if not os_password:
                    raise exc.CommandError("You must provide a password "
                                           "through --os-password, "
                                           "env[OS_PASSWORD] "
                                           "or, prompted response.")

            if not project_info_provided:
                raise exc.CommandError(
                    _("You must provide a project_id or project_name (with "
                      "project_domain_name or project_domain_id) via "
                      "  --os-project-id (env[OS_PROJECT_ID])"
                      "  --os-project-name (env[OS_PROJECT_NAME]),"
                      "  --os-project-domain-id "
                      "(env[OS_PROJECT_DOMAIN_ID])"
                      "  --os-project-domain-name "
                      "(env[OS_PROJECT_DOMAIN_NAME])"))

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

        if not project_info_provided:
            raise exc.CommandError(
                _("You must provide a project_id or project_name (with "
                  "project_domain_name or project_domain_id) via "
                  "  --os-project-id (env[OS_PROJECT_ID])"
                  "  --os-project-name (env[OS_PROJECT_NAME]),"
                  "  --os-project-domain-id "
                  "(env[OS_PROJECT_DOMAIN_ID])"
                  "  --os-project-domain-name "
                  "(env[OS_PROJECT_DOMAIN_NAME])"))

        if not os_auth_url and not auth_plugin:
            raise exc.CommandError(
                "You must provide an authentication URL "
                "through --os-auth-url or env[OS_AUTH_URL].")

        if not auth_session:
            auth_session = self._get_keystone_session()

        insecure = self.options.insecure

        client_args = dict(
            region_name=os_region_name,
            tenant_id=os_project_id,
            endpoint_type=endpoint_type,
            extensions=self.extensions,
            service_type=service_type,
            service_name=service_name,
            volume_service_name=volume_service_name,
            os_endpoint=os_endpoint,
            retries=options.retries,
            http_log_debug=args.debug,
            insecure=insecure,
            cacert=cacert,
            auth_system=os_auth_type,
            auth_plugin=auth_plugin,
            session=auth_session,
            logger=self.ks_logger if auth_session else self.client_logger)

        self.cs = client.Client(api_version, os_username, os_password,
                                os_project_name, os_auth_url, **client_args)

        try:
            if not utils.isunauthenticated(args.func):
                self.cs.authenticate()
        except exc.Unauthorized:
            raise exc.CommandError("OpenStack credentials are not valid.")
        except exc.AuthorizationFailure:
            raise exc.CommandError("Unable to authorize user.")

        endpoint_api_version = None
        # Try to get the API version from the endpoint URL.  If that fails fall
        # back to trying to use what the user specified via
        # --os-volume-api-version or with the OS_VOLUME_API_VERSION environment
        # variable.  Fail safe is to use the default API setting.
        try:
            endpoint_api_version = \
                self.cs.get_volume_api_version_from_endpoint()
        except exc.UnsupportedVersion:
            endpoint_api_version = options.os_volume_api_version
            if api_version_input:
                logger.warning(
                    "Cannot determine the API version from "
                    "the endpoint URL. Falling back to the "
                    "user-specified version: %s", endpoint_api_version)
            else:
                logger.warning(
                    "Cannot determine the API version from the "
                    "endpoint URL or user input. Falling back "
                    "to the default API version: %s", endpoint_api_version)

        API_MAX_VERSION = api_versions.APIVersion(api_versions.MAX_VERSION)
        if endpoint_api_version[0] == '3':
            disc_client = client.Client(API_MAX_VERSION, os_username,
                                        os_password, os_project_name,
                                        os_auth_url, **client_args)
            self.cs, discovered_version = self._discover_client(
                disc_client, api_version, args.os_endpoint_type,
                args.service_type, os_username, os_password, os_project_name,
                os_auth_url, client_args)

            if discovered_version < api_version:
                self.downgrade_warning(api_version, discovered_version)

        profile = osprofiler_profiler and options.profile
        if profile:
            osprofiler_profiler.init(options.profile)

        try:
            args.func(self.cs, args)
        finally:
            if profile:
                trace_id = osprofiler_profiler.get().get_base_id()
                print("Trace ID: %s" % trace_id)
                print("To display trace use next command:\n"
                      "osprofiler trace show --html %s " % trace_id)
Esempio n. 19
0
 def test_load_with_nothing(self):
     loading.register_auth_argparse_arguments(self.p, [])
     opts = self.p.parse_args([])
     self.assertIsNone(loading.load_auth_from_argparse_arguments(opts))
Esempio n. 20
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]."))

            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())