Ejemplo n.º 1
0
 def _validate_input_api_version(options):
     if not options.os_volume_api_version:
         api_version = api_versions.APIVersion(api_versions.MAX_VERSION)
     else:
         api_version = api_versions.get_api_version(
             options.os_volume_api_version)
     return api_version
Ejemplo n.º 2
0
    def lazy_cinder_loader():
        """
        Build the v1 or v2 ``ICinderVolumeManager`` wrapped for compatibility
        with the v1 API and wrapped to provide logging of API calls.
        This will be invoked by ``LazyLoadingProxy`` the first time an
        ``ICinderVolumeManager`` attribute is accessed.
        The reason for the lazy loading of the volume manager is so that the
        the cinder API version detection can delayed until the
        ``flocker-dataset-agent`` loop has started. And the reason for that is
        so that exceptions (e.g. keystone connection errors) that occur during
        the cinder API version detection, do not occur when the
        ``CinderBlockDeviceAPI`` is initialized and crash the process. This way
        errors will be caught by the loop and the cinder API version detection
        will be retried until it succeeds.

        :returns: The ``ICinderVolumeManager`` wrapper.
        """
        session = get_keystone_session(**config)
        # Force authentication here for a clearer stack trace if the keystone
        # endpoint is not accessible.
        session.get_token()
        cinder_client = get_cinder_client(
            session=session,
            region=region,
        )

        wrapped_cinder_volume_manager = _LoggingCinderVolumeManager(
            cinder_client.volumes)
        cinder_client_version = get_api_version(cinder_client.version)
        # Add a Cinder v1 adapter if necessary
        adapted_cinder_volume_manager = CINDER_V1_ADAPTERS[
            cinder_client_version.ver_major](wrapped_cinder_volume_manager)

        return adapted_cinder_volume_manager
 def test_major_and_minor_parts_is_presented(self, mock_apiversion,
                                             mock_get_majors):
     version = "2.7"
     mock_get_majors.return_value = [
         str(mock_apiversion.return_value.ver_major)]
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with(version)
 def test_only_major_part_is_presented(self, mock_apiversion,
                                       mock_get_majors):
     mock_get_majors.return_value = [
         str(mock_apiversion.return_value.ver_major)]
     version = 7
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with("%s.0" % str(version))
Ejemplo n.º 5
0
 def test_major_and_minor_parts_is_presented(self, mock_apiversion,
                                             mock_get_majors):
     version = "2.7"
     mock_get_majors.return_value = [
         str(mock_apiversion.return_value.ver_major)]
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with(version)
Ejemplo n.º 6
0
 def test_only_major_part_is_presented(self, mock_apiversion,
                                       mock_get_majors):
     mock_get_majors.return_value = [
         str(mock_apiversion.return_value.ver_major)]
     version = 7
     self.assertEqual(mock_apiversion.return_value,
                      api_versions.get_api_version(version))
     mock_apiversion.assert_called_once_with("%s.0" % str(version))
Ejemplo n.º 7
0
def _get_client_class_and_version(version):
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    else:
        api_versions.check_major_version(version)
    if version.is_latest():
        raise exceptions.UnsupportedVersion(_("The version should be explicit, not latest."))
    return version, importutils.import_class("cinderclient.v%s.client.Client" % version.ver_major)
Ejemplo n.º 8
0
def make_client(instance):
    """Returns a volume service client."""

    # Defer client imports until we actually need them
    from cinderclient import extension
    from cinderclient.v3.contrib import list_extensions
    from cinderclient.v3 import volume_snapshots
    from cinderclient.v3 import volumes

    # Check whether the available cinderclient supports v1 or v2
    try:
        from cinderclient.v1 import services  # noqa
    except Exception:
        del API_VERSIONS['1']
    try:
        from cinderclient.v2 import services  # noqa
    except Exception:
        del API_VERSIONS['2']

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

    if version.ver_major == '1':
        # Monkey patch for v1 cinderclient
        volumes.Volume.NAME_ATTR = 'display_name'
        volume_snapshots.Snapshot.NAME_ATTR = 'display_name'

    volume_client = utils.get_client_class(API_NAME, version.ver_major,
                                           API_VERSIONS)
    LOG.debug('Instantiating volume client: %s', volume_client)

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

    extensions = [extension.Extension('list_extensions', list_extensions)]

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

    endpoint_override = instance.sdk_connection.config.get_endpoint(
        'block-storage')

    client = volume_client(session=instance.session,
                           extensions=extensions,
                           http_log_debug=http_log_debug,
                           region_name=instance.region_name,
                           endpoint_override=endpoint_override,
                           api_version=version,
                           **kwargs)

    return client
Ejemplo n.º 9
0
def _get_client_class_and_version(version):
    if not isinstance(version, api_versions.APIVersion):
        version = api_versions.get_api_version(version)
    else:
        api_versions.check_major_version(version)
    if version.is_latest():
        raise exceptions.UnsupportedVersion(
            _("The version should be explicit, not latest."))
    return version, importutils.import_class(
        "cinderclient.v%s.client.Client" % version.ver_major)
Ejemplo n.º 10
0
def check_api_version(check_version):
    """Validate version supplied by user

    Returns:

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

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

    global _volume_api_version

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

    # Bypass X.latest format microversion
    if not _volume_api_version.is_latest():
        if _volume_api_version > api_versions.APIVersion("3.0"):
            if not _volume_api_version.matches(
                    api_versions.MIN_VERSION,
                    api_versions.MAX_VERSION,
            ):
                msg = _("versions supported by client: %(min)s - %(max)s") % {
                    "min": api_versions.MIN_VERSION,
                    "max": api_versions.MAX_VERSION,
                }
                raise exceptions.CommandError(msg)

            return True

    return False
Ejemplo n.º 11
0
    def lazy_cinder_loader():
        """
        Build the v1 or v2 ``ICinderVolumeManager`` wrapped for compatibility
        with the v1 API and wrapped to provide logging of API calls.
        This will be invoked by ``LazyLoadingProxy`` the first time an
        ``ICinderVolumeManager`` attribute is accessed.
        The reason for the lazy loading of the volume manager is so that the
        the cinder API version detection can delayed until the
        ``flocker-dataset-agent`` loop has started. And the reason for that is
        so that exceptions (e.g. keystone connection errors) that occur during
        the cinder API version detection, do not occur when the
        ``CinderBlockDeviceAPI`` is initialized and crash the process. This way
        errors will be caught by the loop and the cinder API version detection
        will be retried until it succeeds.

        :returns: The ``ICinderVolumeManager`` wrapper.
        """
        session = get_keystone_session(**config)
        # Force authentication here for a clearer stack trace if the keystone
        # endpoint is not accessible.
        session.get_token()
        cinder_client = get_cinder_client(
            session=session,
            region=region,
        )

        wrapped_cinder_volume_manager = _LoggingCinderVolumeManager(
            cinder_client.volumes
        )
        cinder_client_version = get_api_version(cinder_client.version)
        # Add a Cinder v1 adapter if necessary
        adapted_cinder_volume_manager = CINDER_V1_ADAPTERS[
            cinder_client_version.ver_major
        ](wrapped_cinder_volume_manager)

        return adapted_cinder_volume_manager
Ejemplo n.º 12
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

        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(major_version_string)
        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, bypass_url,
         cacert, os_auth_system) = (
             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.bypass_url, args.os_cacert,
             args.os_auth_system)
        if os_auth_system and os_auth_system != "keystone":
            auth_plugin = cinderclient.auth_plugin.load_plugin(os_auth_system)
        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)

        if not utils.isunauthenticated(args.func):
            if auth_plugin:
                auth_plugin.parse_opts(args)

            if not auth_plugin or not auth_plugin.opts:
                if not os_username:
                    raise exc.CommandError("You must provide a user name "
                                           "through --os-username or "
                                           "env[OS_USERNAME].")

            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:
                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 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:
            raise exc.CommandError(
                "You must provide an authentication URL "
                "through --os-auth-url or env[OS_AUTH_URL].")

        auth_session = None
        if not auth_plugin:
            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=bypass_url,
            retries=options.retries,
            http_log_debug=args.debug,
            insecure=insecure,
            cacert=cacert, auth_system=os_auth_system,
            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)

        args.func(self.cs, args)

        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)
Ejemplo n.º 13
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_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 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_project_name,
            os_auth_url,
            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,
            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)