def register_event_callbacks(self): # NOTE(morganfainberg): A provider who has an implicit # dependency on other providers may utilize the event callback # mechanism to react to any changes in those providers. This is # performed at the .provider() mechanism so that we can ensure # that the callback is only ever called once and guaranteed # to be on the properly configured and instantiated backend. if not hasattr(self, 'event_callbacks'): return if not isinstance(self.event_callbacks, dict): msg = _('event_callbacks must be a dict') raise ValueError(msg) for event in self.event_callbacks: if not isinstance(self.event_callbacks[event], dict): msg = _('event_callbacks[%s] must be a dict') % event raise ValueError(msg) for resource_type in self.event_callbacks[event]: # Make sure we register the provider for each event it # cares to call back. callbacks = self.event_callbacks[event][resource_type] if not callbacks: continue if not hasattr(callbacks, '__iter__'): # ensure the callback information is a list # allowing multiple callbacks to exist callbacks = [callbacks] notifications.register_event_callback(event, resource_type, callbacks)
def wrapper(*args, **kwargs): try: return method(*args, **kwargs) except db_exception.DBDuplicateEntry as e: # LOG the exception for debug purposes, do not send the # exception details out with the raised Conflict exception # as it can contain raw SQL. LOG.debug(_conflict_msg, { 'conflict_type': conflict_type, 'details': six.text_type(e) }) raise exception.Conflict(type=conflict_type, details=_('Duplicate Entry')) except db_exception.DBError as e: # TODO(blk-u): inspecting inner_exception breaks encapsulation; # oslo_db should provide exception we need. if isinstance(e.inner_exception, IntegrityError): # LOG the exception for debug purposes, do not send the # exception details out with the raised Conflict exception # as it can contain raw SQL. LOG.debug( _conflict_msg, { 'conflict_type': conflict_type, 'details': six.text_type(e) }) # NOTE(morganfainberg): This is really a case where the SQL # failed to store the data. This is not something that the # user has done wrong. Example would be a ForeignKey is # missing; the code that is executed before reaching the # SQL writing to the DB should catch the issue. raise exception.UnexpectedError( _('An unexpected error occurred when trying to ' 'store %s') % conflict_type) raise
class UnexpectedError(SecurityError): """Avoids exposing details of failures, unless in debug mode.""" _message_format = _("An unexpected error prevented the server " "from fulfilling your request.") debug_message_format = _("An unexpected error prevented the server " "from fulfilling your request: %(exception)s") @property def message_format(self): """Return the generic message format string unless debug is enabled.""" if CONF.debug: return self.debug_message_format return self._message_format def _build_message(self, message, **kwargs): if CONF.debug and 'exception' not in kwargs: # Ensure that exception has a value to be extra defensive for # substitutions and make sure the exception doesn't raise an # exception. kwargs['exception'] = '' return super(UnexpectedError, self)._build_message(message, **kwargs) code = 500 title = 'Internal Server Error'
def check_length(property_name, value, min_length=1, max_length=64): if len(value) < min_length: if min_length == 1: msg = _("%s cannot be empty.") % property_name else: msg = (_("%(property_name)s cannot be less than " "%(min_length)s characters.") % dict(property_name=property_name, min_length=min_length)) raise exception.ValidationError(msg) if len(value) > max_length: msg = (_("%(property_name)s should not be greater than " "%(max_length)s characters.") % dict(property_name=property_name, max_length=max_length)) raise exception.ValidationError(msg)
def _ssl_cert_req_type(self, req_type): try: import ssl except ImportError: raise exception.ValidationError(_('no ssl support available')) req_type = req_type.upper() try: return { 'NONE': ssl.CERT_NONE, 'OPTIONAL': ssl.CERT_OPTIONAL, 'REQUIRED': ssl.CERT_REQUIRED }[req_type] except KeyError: msg = _('Invalid ssl_cert_reqs value of %s, must be one of ' '"NONE", "OPTIONAL", "REQUIRED"') % (req_type) raise exception.ValidationError(message=msg)
class ValidationTimeStampError(Error): message_format = _("Timestamp not in expected format." " The server could not comply with the request" " since it is either malformed or otherwise" " incorrect. The client is assumed to be in error.") code = 400 title = 'Bad Request'
class ValidationError(Error): message_format = _("Expecting to find %(attribute)s in %(target)s -" " the server could not comply with the request" " since it is either malformed or otherwise" " incorrect. The client is assumed to be in error.") code = 400 title = 'Bad Request'
def check_type(property_name, value, expected_type, display_expected_type): if not isinstance(value, expected_type): msg = (_("%(property_name)s is not a " "%(display_expected_type)s") % dict(property_name=property_name, display_expected_type=display_expected_type)) raise exception.ValidationError(msg)
def __init__(self, mod_name, path): super(MigrationNotProvided, self).__init__( _("%(mod_name)s doesn't provide database migrations. The migration" " repository path at %(path)s doesn't exist or isn't a directory." ) % { 'mod_name': mod_name, 'path': path })
def _require_attribute(self, ref, attribute): """Ensures the reference contains the specified attribute. Raise a ValidationError if the given attribute is not present """ if self._attribute_is_empty(ref, attribute): msg = _('%s field is required and cannot be empty') % attribute raise exception.ValidationError(message=msg)
class ValidationSizeError(Error): message_format = _("Request attribute %(attribute)s must be" " less than or equal to %(size)i. The server" " could not comply with the request because" " the attribute size is invalid (too large)." " The client is assumed to be in error.") code = 400 title = 'Bad Request'
def _build_message(self, message, **kwargs): """Only returns detailed messages in debug mode.""" if CONF.debug: return _('%(message)s %(amendment)s') % { 'message': message or self.message_format % kwargs, 'amendment': self.amendment } else: return self.message_format % kwargs
def get_blob_from_credential(credential): try: blob = jsonutils.loads(credential.blob) except (ValueError, TypeError): raise exception.ValidationError( message=_('Invalid blob in credential')) if not blob or not isinstance(blob, dict): raise exception.ValidationError(attribute='blob', target='credential') return blob
def _require_attributes(self, ref, attrs): """Ensures the reference contains the specified attributes. Raise a ValidationError if any of the given attributes is not present """ missing_attrs = [attribute for attribute in attrs if self._attribute_is_empty(ref, attribute)] if missing_attrs: msg = _('%s field(s) cannot be empty') % ', '.join(missing_attrs) raise exception.ValidationError(message=msg)
def update_resource_data(cls, resource_data, status): if status is cls.STABLE: # We currently do not add a status if the resource is stable, the # absence of the status property can be taken as meaning that the # resource is stable. return if status is cls.DEPRECATED or status is cls.EXPERIMENTAL: resource_data['hints'] = {'status': status} return raise exception.Error(message=_( 'Unexpected status requested for JSON Home response, %s') % status)
def get_db_version(extension=None): if not extension: return migration.db_version(sql.get_engine(), find_migrate_repo(), migrate_repo.DB_INIT_VERSION) try: package_name = '.'.join((contrib.__name__, extension)) package = importutils.import_module(package_name) except ImportError: raise ImportError(_("%s extension does not exist.") % package_name) return migration.db_version(sql.get_engine(), find_migrate_repo(package), 0)
def base64_is_padded(text, pad='='): """Test if the text is base64 padded. The input text must be in a base64 alphabet. The pad must be a single character. If the text has been percent-encoded (e.g. pad is the string '%3D') you must convert the text back to a base64 alphabet (e.g. if percent-encoded use the function base64url_percent_decode()). :param text: text containing ONLY characters in a base64 alphabet :type text: string :param pad: pad character (must be single character) (default: '=') :type pad: string :returns: bool -- True if padded, False otherwise :raises: ValueError, InvalidBase64Error """ _check_padding_length(pad) text_len = len(text) if text_len > 0 and text_len % 4 == 0: pad_index = text.find(pad) if pad_index >= 0 and pad_index < text_len - 2: raise InvalidBase64Error( _('text is multiple of 4, ' 'but pad "%s" occurs before ' '2nd to last char') % pad) if pad_index == text_len - 2 and text[-1] != pad: raise InvalidBase64Error( _('text is multiple of 4, ' 'but pad "%s" occurs before ' 'non-pad last char') % pad) return True if text.find(pad) >= 0: raise InvalidBase64Error( _('text is not a multiple of 4, ' 'but contains pad "%s"') % pad) return False
class SecurityError(Error): """Avoids exposing details of security failures, unless in debug mode.""" amendment = _('(Disable debug mode to suppress these details.)') def _build_message(self, message, **kwargs): """Only returns detailed messages in debug mode.""" if CONF.debug: return _('%(message)s %(amendment)s') % { 'message': message or self.message_format % kwargs, 'amendment': self.amendment } else: return self.message_format % kwargs
def register_event_callback(event, resource_type, callbacks): """Register each callback with the event. :param event: Action being registered :type event: sidserver.notifications.ACTIONS :param resource_type: Type of resource being operated on :type resource_type: str :param callbacks: Callback items to be registered with event :type callbacks: list :raises ValueError: If event is not a valid ACTION :raises TypeError: If callback is not callable """ if event not in ACTIONS: raise ValueError( _('%(event)s is not a valid notification event, must ' 'be one of: %(actions)s') % { 'event': event, 'actions': ', '.join(ACTIONS) }) if not hasattr(callbacks, '__iter__'): callbacks = [callbacks] for callback in callbacks: if not callable(callback): msg = _('Method not callable: %s') % callback LOG.error(msg) raise TypeError(msg) _SUBSCRIBERS.setdefault(event, {}).setdefault(resource_type, set()) _SUBSCRIBERS[event][resource_type].add(callback) if LOG.logger.getEffectiveLevel() <= logging.DEBUG: # Do this only if its going to appear in the logs. msg = 'Callback: `%(callback)s` subscribed to event `%(event)s`.' callback_info = _get_callback_info(callback) callback_str = '.'.join(i for i in callback_info if i is not None) event_str = '.'.join(['identity', resource_type, event]) LOG.debug(msg, {'callback': callback_str, 'event': event_str})
def _sync_extension_repo(extension, version): init_version = 0 engine = sql.get_engine() try: package_name = '.'.join((contrib.__name__, extension)) package = importutils.import_module(package_name) except ImportError: raise ImportError(_("%s extension does not exist.") % package_name) try: abs_path = find_migrate_repo(package) try: migration.db_version_control(sql.get_engine(), abs_path) # Register the repo with the version control API # If it already knows about the repo, it will throw # an exception that we can safely ignore except exceptions.DatabaseAlreadyControlledError: pass except exception.MigrationNotProvided as e: print(e) sys.exit(1) _assert_not_schema_downgrade(extension=extension, version=version) try: migration.db_sync(engine, abs_path, version=version, init_version=init_version) except ValueError: # NOTE(marco-fargetta): ValueError is raised from the sanity check ( # verifies that tables are utf8 under mysql). The federation_protocol, # identity_provider and mapping tables were not initially built with # InnoDB and utf8 as part of the table arguments when the migration # was initially created. Bug #1426334 is a scenario where the deployer # can get wedged, unable to upgrade or downgrade. # This is a workaround to "fix" those tables if we're under MySQL and # the version is before the 6 because before the tables were introduced # before and patched when migration 5 was available if engine.name == 'mysql' and \ int(six.text_type(get_db_version(extension))) < 6: _fix_federation_tables(engine) # The migration is applied again after the fix migration.db_sync(engine, abs_path, version=version, init_version=init_version) else: raise
def pem_type(self, pem_type): if pem_type is None: self._pem_type = None self._pem_header = None else: pem_header = PEM_TYPE_TO_HEADER.get(pem_type) if pem_header is None: raise ValueError( _('unknown pem_type "%(pem_type)s", ' 'valid types are: %(valid_pem_types)s') % { 'pem_type': pem_type, 'valid_pem_types': ', '.join(pem_types) }) self._pem_type = pem_type self._pem_header = pem_header
def serve(*servers): logging.warning( _('Running sidserver via eventlet is deprecated as of Kilo ' 'in favor of running in a WSGI server (e.g. mod_wsgi). ' 'Support for sidserver under eventlet will be removed in ' 'the "M"-Release.')) if max([server[1].workers for server in servers]) > 1: launcher = service.ProcessLauncher() else: launcher = service.ServiceLauncher() for name, server in servers: try: server.launch_with(launcher) except socket.error: logging.exception( _('Failed to start the %(name)s server') % {'name': name}) raise # notify calling process we are ready to serve systemd.notify_once() for name, server in servers: launcher.wait()
def _dispatch(req): """Dispatch the request to the appropriate controller. Called by self._router after matching the incoming request to a route and putting the information into req.environ. Either returns 404 or the routed WSGI app's response. """ match = req.environ['wsgiorg.routing_args'][1] if not match: msg = _('The resource could not be found.') return render_exception(exception.NotFound(msg), request=req, user_locale=best_match_language(req)) app = match['controller'] return app
def configure_cache_region(region): """Configure a cache region. :param region: optional CacheRegion object, if not provided a new region will be instantiated :raises: exception.ValidationError :returns: dogpile.cache.CacheRegion """ if not isinstance(region, dogpile.cache.CacheRegion): raise exception.ValidationError( _('region not type dogpile.cache.CacheRegion')) if not region.is_configured: # NOTE(morganfainberg): this is how you tell if a region is configured. # There is a request logged with dogpile.cache upstream to make this # easier / less ugly. config_dict = build_cache_config() region.configure_from_config(config_dict, '%s.' % CONF.cache.config_prefix) if CONF.cache.debug_cache_backend: region.wrap(DebugProxy) # NOTE(morganfainberg): if the backend requests the use of a # key_mangler, we should respect that key_mangler function. If a # key_mangler is not defined by the backend, use the sha1_mangle_key # mangler provided by dogpile.cache. This ensures we always use a fixed # size cache-key. if region.key_mangler is None: region.key_mangler = util.sha1_mangle_key for class_path in CONF.cache.proxies: # NOTE(morganfainberg): if we have any proxy wrappers, we should # ensure they are added to the cache region's backend. Since # configure_from_config doesn't handle the wrap argument, we need # to manually add the Proxies. For information on how the # ProxyBackends work, see the dogpile.cache documents on # "changing-backend-behavior" cls = importutils.import_class(class_path) LOG.debug("Adding cache-proxy '%s' to backend.", class_path) region.wrap(cls) return region
def pem_header(self, pem_header): if pem_header is None: self._pem_type = None self._pem_header = None else: pem_type = PEM_HEADER_TO_TYPE.get(pem_header) if pem_type is None: raise ValueError( _('unknown pem header "%(pem_header)s", ' 'valid headers are: ' '%(valid_pem_headers)s') % { 'pem_header': pem_header, 'valid_pem_headers': ', '.join("'%s'" % [x for x in pem_headers]) }) self._pem_type = pem_type self._pem_header = pem_header
def base64url_percent_encode(text): """Percent-encode base64url padding. The input text should only contain base64url alphabet characters. Any non-base64url alphabet characters will also be subject to percent-encoding. :param text: text containing ONLY characters in the base64url alphabet :type text: string :returns: string -- percent-encoded base64url text :raises: InvalidBase64Error """ if len(text) % 4 != 0: raise InvalidBase64Error( _('padded base64url text must be ' 'multiple of 4 characters')) return urllib.parse.quote(text)
def base64url_percent_decode(text): """Percent-decode base64url padding. The input text should only contain base64url alphabet characters and the percent-encoded pad character. Any other percent-encoded characters will be subject to percent-decoding. :param text: base64url alphabet text :type text: string :returns: string -- percent-decoded base64url text """ decoded_text = urllib.parse.unquote(text) if len(decoded_text) % 4 != 0: raise InvalidBase64Error( _('padded base64url text must be ' 'multiple of 4 characters')) return decoded_text
def acquire(self): self._debug_logger('Acquiring connection') try: conn = self.get(timeout=self._connection_get_timeout) except queue.Empty: raise exception.UnexpectedError( _('Unable to get a connection from pool id %(id)s after ' '%(seconds)s seconds.') % {'id': id(self), 'seconds': self._connection_get_timeout}) self._debug_logger('Acquired connection %s', id(conn)) try: yield conn finally: self._debug_logger('Releasing connection %s', id(conn)) self._drop_expired_connections() try: # super() cannot be used here because Queue in stdlib is an # old-style class queue.Queue.put(self, conn, block=False) except queue.Full: self._debug_logger('Reaping exceeding connection %s', id(conn)) self._destroy_connection(conn)
def wrapper(self, hints, *args, **kwargs): if not hasattr(hints, 'limit'): raise exception.UnexpectedError( _('Cannot truncate a driver call without hints list as ' 'first parameter after self ')) if hints.limit is None: return f(self, hints, *args, **kwargs) # A limit is set, so ask for one more entry than we need list_limit = hints.limit['limit'] hints.set_limit(list_limit + 1) ref_list = f(self, hints, *args, **kwargs) # If we got more than the original limit then trim back the list and # mark it truncated. In both cases, make sure we set the limit back # to its original value. if len(ref_list) > list_limit: hints.set_limit(list_limit, truncated=True) return ref_list[:list_limit] else: hints.set_limit(list_limit) return ref_list
def __init__(self, name, targets): msg = _('Unregistered dependency: %(name)s for %(targets)s') % { 'name': name, 'targets': targets} super(UnresolvableDependencyException, self).__init__(msg)