def validate_integer(value, name, min_value=None, max_value=None): """Make sure that value is a valid integer, potentially within range. :param value: the value of the integer :param name: the name of the integer :param min_length: the min_length of the integer :param max_length: the max_length of the integer :returns: integer """ try: value = int(value) except (TypeError, ValueError, UnicodeEncodeError): raise webob.exc.HTTPBadRequest(explanation=( _('%s must be an integer.') % name)) if min_value is not None and value < min_value: raise webob.exc.HTTPBadRequest( explanation=(_('%(value_name)s must be >= %(min_value)d') % {'value_name': name, 'min_value': min_value})) if max_value is not None and value > max_value: raise webob.exc.HTTPBadRequest( explanation=(_('%(value_name)s must be <= %(max_value)d') % {'value_name': name, 'max_value': max_value})) return value
def check_string_length(value, name, min_length=0, max_length=None): """Check the length of specified string. :param value: the value of the string :param name: the name of the string :param min_length: the min_length of the string :param max_length: the max_length of the string """ if not isinstance(value, six.string_types): msg = _("%s is not a string or unicode") % name raise exception.InvalidInput(message=msg) if len(value) < min_length: msg = _("%(name)s has a minimum character requirement of " "%(min_length)s.") % { 'name': name, 'min_length': min_length } raise exception.InvalidInput(message=msg) if max_length and len(value) > max_length: msg = _("%(name)s has more than %(max_length)s " "characters.") % { 'name': name, 'max_length': max_length } raise exception.InvalidInput(message=msg)
def _get_offset_param(params): """Extract offset id from request's dictionary (defaults to 0) or fail.""" try: offset = int(params.pop('offset', 0)) except ValueError: msg = _('offset param must be an integer') raise webob.exc.HTTPBadRequest(explanation=msg) if offset < 0: msg = _('offset param must be positive') raise webob.exc.HTTPBadRequest(explanation=msg) return offset
def __call__(self, environ, start_response): r"""Subclasses will probably want to implement __call__ like this: @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): # Any of the following objects work as responses: # Option 1: simple string res = 'message\n' # Option 2: a nicely formatted HTTP exception page res = exc.HTTPForbidden(explanation='Nice try') # Option 3: a webob Response object (in case you need to play with # headers, or you want to be treated like an iterable) res = Response(); res.app_iter = open('somefile') # Option 4: any wsgi app to be run next res = self.application # Option 5: you can get a Response object for a wsgi app, too, to # play with headers etc res = req.get_response(self.application) # You can then just return your response... return res # ... or set req.response and return None. req.response = res See the end of http://pythonpaste.org/webob/modules/dec.html for more info. """ raise NotImplementedError(_('You must implement __call__'))
def action_peek_json(body): """Determine action to invoke.""" try: decoded = jsonutils.loads(body) except ValueError: msg = _("cannot understand JSON") raise exception.MalformedRequestBody(reason=msg) # Make sure there's exactly one key... if len(decoded) != 1: msg = _("too many body keys") raise exception.MalformedRequestBody(reason=msg) # Return the action and the decoded body... return decoded.keys()[0]
def __init__(self, name, loader=None): """Initialize, but do not start the WSGI server. :param name: The name of the WSGI server given to the loader. :param loader: Loads the WSGI application using the given name. :returns: None """ self.name = name self.manager = self._get_manager() self.loader = loader or wsgi_common.Loader() self.app = self.loader.load_app(name) self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0") self.port = getattr(CONF, '%s_listen_port' % name, 0) self.workers = (getattr(CONF, '%s_workers' % name, None) or processutils.get_worker_count()) if self.workers and self.workers < 1: worker_name = '%s_workers' % name msg = (_("%(worker_name)s value of %(workers)d is invalid, " "must be greater than 0.") % {'worker_name': worker_name, 'workers': self.workers}) raise exception.InvalidInput(msg) setup_profiler(name, self.host) self.server = wsgi.Server(name, self.app, host=self.host, port=self.port)
class APIException(VenusException): message = _("Error while requesting %(service)s API.") def __init__(self, message=None, **kwargs): if 'service' not in kwargs: kwargs['service'] = 'unknown' super(APIException, self).__init__(message, **kwargs)
def attach(self, *slaves): """Attach one or more slave templates. Attaches one or more slave templates to the master template. Slave templates must have a root element with the same tag as the master template. The slave template's apply() method will be called to determine if the slave should be applied to this master; if it returns False, that slave will be skipped. (This allows filtering of slaves based on the version of the master template.) """ slave_list = [] for slave in slaves: slave = slave.wrap() # Make sure we have a tree match if slave.root.tag != self.root.tag: msg = (_("Template tree mismatch; adding slave %(slavetag)s " "to master %(mastertag)s") % {'slavetag': slave.root.tag, 'mastertag': self.root.tag}) raise ValueError(msg) # Make sure slave applies to this template if not slave.apply(self): continue slave_list.append(slave) # Add the slaves self.slaves.extend(slave_list)
def check_exclusive_options(**kwargs): """Checks that only one of the provided options is actually not-none. Iterates over all the kwargs passed in and checks that only one of said arguments is not-none, if more than one is not-none then an exception will be raised with the names of those arguments who were not-none. """ if not kwargs: return pretty_keys = kwargs.pop("pretty_keys", True) exclusive_options = {} for (k, v) in kwargs.items(): if v is not None: exclusive_options[k] = True if len(exclusive_options) > 1: # Change the format of the names from pythonic to # something that is more readable. # # Ex: 'the_key' -> 'the key' if pretty_keys: names = [k.replace('_', ' ') for k in kwargs.keys()] else: names = kwargs.keys() names = ", ".join(sorted(names)) msg = (_("May specify only one of %s") % (names)) raise exception.InvalidInput(reason=msg)
def is_admin_context(context): """Indicates if the request context is an administrator.""" if not context: warnings.warn(_('Use of empty request context is deprecated'), DeprecationWarning) raise Exception('die') return context.is_admin
def _error(self, inner, req): safe = getattr(inner, 'safe', False) headers = getattr(inner, 'headers', None) status = getattr(inner, 'code', 500) if status is None: status = 500 msg_dict = dict(url=req.url, status=status) LOG.info(_LI("%(url)s returned with HTTP %(status)d"), msg_dict) outer = self.status_to_type(status) if headers: outer.headers = headers # NOTE(johannes): We leave the explanation empty here on # purpose. It could possibly have sensitive information # that should not be returned back to the user. See # bugs 868360 and 874472 # NOTE(eglynn): However, it would be over-conservative and # inconsistent with the EC2 API to hide every exception, # including those that are safe to expose, see bug 1021373 if safe: msg = (inner.msg if isinstance(inner, exception.VenusException) else six.text_type(inner)) params = { 'exception': inner.__class__.__name__, 'explanation': msg } outer.explanation = _('%(exception)s: %(explanation)s') % params return wsgi.Fault(outer)
class VenusException(Exception): """Base Venus Exception To correctly use this class, inherit from it and define a 'message' property. That message will get printf'd with the keyword arguments provided to the constructor. """ message = _("An unknown exception occurred.") code = 500 headers = {} safe = False def __init__(self, message=None, **kwargs): self.kwargs = kwargs self.kwargs['message'] = message if 'code' not in self.kwargs: try: self.kwargs['code'] = self.code except AttributeError: pass for k, v in self.kwargs.items(): if isinstance(v, Exception): self.kwargs[k] = six.text_type(v) if self._should_format(): try: message = self.message % kwargs except Exception: exc_info = sys.exc_info() # kwargs doesn't match a variable in the message # log the issue and the kwargs LOG.exception(_LE('Exception in string format operation')) for name, value in kwargs.items(): LOG.error(_LE("%(name)s: %(value)s"), { 'name': name, 'value': value }) if CONF.fatal_exception_format_errors: six.reraise(*exc_info) # at least get the core message out if something happened message = self.message elif isinstance(message, Exception): message = six.text_type(message) # NOTE(luisg): We put the actual message in 'msg' so that we can access # it, because if we try to access the message via 'message' it will be # overshadowed by the class' message attribute self.msg = message super(VenusException, self).__init__(message) def _should_format(self): return self.kwargs['message'] is None or '%(message)' in self.message def __unicode__(self): return six.text_type(self.msg)
def purge(self, age_in_days): """Purge deleted rows older than a given age from venus tables.""" age_in_days = int(age_in_days) if age_in_days <= 0: print(_("Must supply a positive, non-zero value for age")) exit(1) ctxt = context.get_admin_context() db.purge_deleted_rows(ctxt, age_in_days)
def construct(self): """Construct a template. Called to construct a template instance, which it must return. Only called once. """ raise NotImplementedError(_("subclasses must implement construct()!"))
def _get_limit_param(params, max_limit=None): """Extract integer limit from request's dictionary or fail. Defaults to max_limit if not present and returns max_limit if present 'limit' is greater than max_limit. """ max_limit = max_limit or CONF.osapi_max_limit try: limit = int(params.pop('limit', max_limit)) except ValueError: msg = _('limit param must be an integer') raise webob.exc.HTTPBadRequest(explanation=msg) if limit < 0: msg = _('limit param must be positive') raise webob.exc.HTTPBadRequest(explanation=msg) limit = min(limit, max_limit) return limit
def _from_xml(self, datastring): plurals = set(self.metadata.get('plurals', {})) try: node = utils.safe_minidom_parse_string(datastring).childNodes[0] return {node.nodeName: self._from_xml_node(node, plurals)} except expat.ExpatError: msg = _("cannot understand XML") raise exception.MalformedRequestBody(reason=msg)
def assert_valid_body(body, entity_name): # NOTE: After v1 api is deprecated need to merge 'is_valid_body' and # 'assert_valid_body' in to one method. Right now it is not # possible to modify 'is_valid_body' to raise exception because # in case of V1 api when 'is_valid_body' return False, # 'HTTPUnprocessableEntity' exception is getting raised and in # V2 api 'HTTPBadRequest' exception is getting raised. if not Controller.is_valid_body(body, entity_name): raise webob.exc.HTTPBadRequest( explanation=_("Missing required element '%s' in " "request body.") % entity_name)
def get_bool_param(param_string, params): param = params.get(param_string, False) if not is_valid_boolstr(param): msg = _('Value %(param)s for %(param_string)s is not a ' 'boolean.') % { 'param': param, 'param_string': param_string } raise exception.InvalidParameterValue(err=msg) return strutils.bool_from_string(param, strict=True)
def errors(self): """Get all of the errors from the log files.""" error_found = 0 if CONF.log_dir: logs = [x for x in os.listdir(CONF.log_dir) if x.endswith('.log')] for file in logs: log_file = os.path.join(CONF.log_dir, file) lines = [line.strip() for line in open(log_file, "r")] lines.reverse() print_name = 0 for index, line in enumerate(lines): if line.find(" ERROR ") > 0: error_found += 1 if print_name == 0: print(log_file + ":-") print_name = 1 print(_("Line %(dis)d : %(line)s") % {'dis': len(lines) - index, 'line': line}) if error_found == 0: print(_("No errors in logfiles!"))
def remove(self, elem): """Remove a child element.""" # Unwrap templates... elem = elem.unwrap() # Check if element exists if elem.tag not in self._childmap or self._childmap[elem.tag] != elem: raise ValueError(_('element is not a child')) self._children.remove(elem) del self._childmap[elem.tag]
def __init__(self, ext_mgr=None): if ext_mgr is None: if self.ExtensionManager: ext_mgr = self.ExtensionManager() else: raise Exception(_("Must specify an ExtensionManager class")) mapper = ProjectMapper() self.resources = {} self._setup_routes(mapper, ext_mgr) self._setup_ext_routes(mapper, ext_mgr) self._setup_extensions(ext_mgr) super(APIRouter, self).__init__(mapper)
def syslog(self, num_entries=10): """Get <num_entries> of the venus syslog events.""" entries = int(num_entries) count = 0 log_file = '' if os.path.exists('/var/log/syslog'): log_file = '/var/log/syslog' elif os.path.exists('/var/log/messages'): log_file = '/var/log/messages' else: print(_("Unable to find system log file!")) sys.exit(1) lines = [line.strip() for line in open(log_file, "r")] lines.reverse() print(_("Last %s venus syslog entries:-") % (entries)) for line in lines: if line.find("venus") > 0: count += 1 print(_("%s") % (line)) if count == entries: break if count == 0: print(_("No venus entries in syslog!"))
def as_int(obj, quiet=True): # Try "2" -> 2 try: return int(obj) except (ValueError, TypeError): pass # Try "2.5" -> 2 try: return int(float(obj)) except (ValueError, TypeError): pass # Eck, not sure what this is then. if not quiet: raise TypeError(_("Can not translate %s to integer.") % (obj)) return obj
def __call__(self, req): user_id = req.headers.get('X_USER') user_id = req.headers.get('X_USER_ID', user_id) if user_id is None: LOG.debug("Neither X_USER_ID nor X_USER found in request") return webob.exc.HTTPUnauthorized() # get the roles roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')] if 'X_TENANT_ID' in req.headers: # This is the new header since Keystone went to ID/Name project_id = req.headers['X_TENANT_ID'] else: # This is for legacy compatibility project_id = req.headers['X_TENANT'] project_name = req.headers.get('X_TENANT_NAME') req_id = req.environ.get(request_id.ENV_REQUEST_ID) # Get the auth token auth_token = req.headers.get('X_AUTH_TOKEN', req.headers.get('X_STORAGE_TOKEN')) # Build a context, including the auth_token... remote_address = req.remote_addr service_catalog = None if req.headers.get('X_SERVICE_CATALOG') is not None: try: catalog_header = req.headers.get('X_SERVICE_CATALOG') service_catalog = jsonutils.loads(catalog_header) except ValueError: raise webob.exc.HTTPInternalServerError( explanation=_('Invalid service catalog json.')) if CONF.use_forwarded_for: remote_address = req.headers.get('X-Forwarded-For', remote_address) ctx = context.RequestContext(user_id, project_id, project_name=project_name, roles=roles, auth_token=auth_token, remote_address=remote_address, service_catalog=service_catalog, request_id=req_id) req.environ['venus.context'] = ctx return self.application
def get_sort_params(params, default_key='created_at', default_dir='desc'): """Retrieves sort keys/directions parameters. Processes the parameters to create a list of sort keys and sort directions that correspond to either the 'sort' parameter or the 'sort_key' and 'sort_dir' parameter values. The value of the 'sort' parameter is a comma- separated list of sort keys, each key is optionally appended with ':<sort_direction>'. Note that the 'sort_key' and 'sort_dir' parameters are deprecated in kilo and an exception is raised if they are supplied with the 'sort' parameter. The sort parameters are removed from the request parameters by this function. :param params: webob.multidict of request parameters (from venus.api.openstack.wsgi.Request.params) :param default_key: default sort key value, added to the list if no sort keys are supplied :param default_dir: default sort dir value, added to the list if the corresponding key does not have a direction specified :returns: list of sort keys, list of sort dirs :raise webob.exc.HTTPBadRequest: If both 'sort' and either 'sort_key' or 'sort_dir' are supplied parameters """ if 'sort' in params and ('sort_key' in params or 'sort_dir' in params): msg = _("The 'sort_key' and 'sort_dir' parameters are deprecated and " "cannot be used with the 'sort' parameter.") raise webob.exc.HTTPBadRequest(explanation=msg) sort_keys = [] sort_dirs = [] if 'sort' in params: for sort in params.pop('sort').strip().split(','): sort_key, _sep, sort_dir = sort.partition(':') if not sort_dir: sort_dir = default_dir sort_keys.append(sort_key.strip()) sort_dirs.append(sort_dir.strip()) else: sort_key = params.pop('sort_key', default_key) sort_dir = params.pop('sort_dir', default_dir) sort_keys.append(sort_key.strip()) sort_dirs.append(sort_dir.strip()) return sort_keys, sort_dirs
def render(self, parent, obj, patches=None, nsmap=None): """Render an object. Renders an object against this template node. Returns a list of two-item tuples, where the first item is an etree.Element instance and the second item is the datum associated with that instance. :param parent: The parent for the etree.Element instances. :param obj: The object to render this template element against. :param patches: A list of other template elements to apply when rendering this template element. :param nsmap: An optional namespace dictionary to attach to the etree.Element instances. """ patches = patches or [] # First, get the datum we're rendering data = None if obj is None else self.selector(obj) # Check if we should render at all if not self.will_render(data): return [] elif data is None: return [(self._render(parent, None, patches, nsmap), None)] # Make the data into a list if it isn't already if not isinstance(data, list): data = [data] elif parent is None: raise ValueError(_('root element selecting a list')) # Render all the elements elems = [] for datum in data: if self.subselector is not None: datum = self.subselector(datum) elems.append((self._render(parent, datum, patches, nsmap), datum)) # Return all the elements rendered, as well as the # corresponding datum for the next step down the tree return elems
def limited_by_marker(items, request, max_limit=None): """Return a slice of items according to the requested marker and limit.""" max_limit = max_limit or CONF.osapi_max_limit marker, limit, __ = get_pagination_params(request.GET.copy(), max_limit) start_index = 0 if marker: start_index = -1 for i, item in enumerate(items): if 'flavorid' in item: if item['flavorid'] == marker: start_index = i + 1 break elif item['id'] == marker or item.get('uuid') == marker: start_index = i + 1 break if start_index < 0: msg = _('marker [%s] not found') % marker raise webob.exc.HTTPBadRequest(explanation=msg) range_end = start_index + limit return items[start_index:range_end]
def main(): objects.register_all() """Parse options and call the appropriate class/method.""" CONF.register_cli_opt(category_opt) script_name = sys.argv[0] if len(sys.argv) < 2: print(_("\nOpenStack Venus version: %(version)s\n") % {'version': version.version_string()}) print(script_name + " category action [<args>]") print(_("Available categories:")) for category in CATEGORIES: print(_("\t%s") % category) sys.exit(2) try: CONF(sys.argv[1:], project='venus', version=version.version_string()) logdir = CONF.log_dir is_exits = os.path.exists(logdir) if not is_exits: os.makedirs(logdir) logging.setup(CONF, "venus") except cfg.ConfigDirNotFoundError as details: print(_("Invalid directory: %s") % details) sys.exit(2) except cfg.ConfigFilesNotFoundError: cfgfile = CONF.config_file[-1] if CONF.config_file else None if cfgfile and not os.access(cfgfile, os.R_OK): st = os.stat(cfgfile) print(_("Could not read %s. Re-running with sudo") % cfgfile) try: os.execvp('sudo', ['sudo', '-u', '#%s' % st.st_uid] + sys.argv) except Exception: print(_('sudo failed, continuing as if nothing happened')) print(_('Please re-run venus-manage as root.')) sys.exit(2) fn = CONF.category.action_fn fn_args = fetch_func_args(fn) fn(*fn_args)
debug_opts = [ ] CONF.register_cli_opts(core_opts) CONF.register_cli_opts(debug_opts) global_opts = [ cfg.StrOpt('my_ip', default=netutils.get_my_ipv4(), help='IP address of this host'), cfg.StrOpt('venusmanager_topic', default='venus-venusmanager', help='The topic that venusmanager nodes listen on'), cfg.BoolOpt('enable_v1_api', default=True, help=_("DEPRECATED: Deploy v1 of the Venus API.")), cfg.BoolOpt('api_rate_limit', default=True, help='Enables or disables rate limit of the API.'), cfg.ListOpt('osapi_venus_ext_list', default=[], help='Specify list of extensions to load when using ' 'osapi_venus_extension option with venus.api.' 'contrib.select_extensions'), cfg.MultiStrOpt('osapi_venus_extension', default=['venus.api.contrib.standard_extensions'], help='osapi venus extension to load'), cfg.StrOpt('venusmanager_manager', default='venus.venusmanager.' 'manager.VenusmanagerManager', help='Full class name for '
def serve(server, workers=None): global _launcher if _launcher: raise RuntimeError(_('serve() can only be called once')) _launcher = service.launch(CONF, server, workers=workers)