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