def __str__(self): self.details = _("Requested version of King API is not" "available.") return (_("%(name)s (HTTP %(code)s) %(details)s") % { 'name': reflection.get_class_name(self, fully_qualified=False), 'code': self.code, 'details': self.details })
def __str__(self): message = self.error['error'].get('message', 'Internal Error') if verbose: traceback = self.error['error'].get('traceback', '') return (_('ERROR: %(message)s\n%(traceback)s') % {'message': message, 'traceback': traceback}) else: return _('ERROR: %s') % message
def __str__(self): self.details = _("Requested version of King API is not" "available.") return (_("%(name)s (HTTP %(code)s) %(details)s") % { 'name': reflection.get_class_name(self, fully_qualified=False), 'code': self.code, 'details': self.details})
def __str__(self): message = self.error['error'].get('message', 'Internal Error') if verbose: traceback = self.error['error'].get('traceback', '') return (_('ERROR: %(message)s\n%(traceback)s') % { 'message': message, 'traceback': traceback }) else: return _('ERROR: %s') % message
class BadRequest(HTTPClientError): """HTTP 400 - Bad Request. The request cannot be fulfilled due to bad syntax. """ http_status = 400 message = _("Bad Request")
class HttpServerError(HttpError): """Server-side HTTP error. Exception for cases in which the server is aware that it has erred or is incapable of performing the request. """ message = _("HTTP Server Error")
class HttpError(ClientException): """The base exception class for all HTTP exceptions. """ http_status = 0 message = _("HTTP Error") def __init__(self, message=None, details=None, response=None, request_id=None, url=None, method=None, http_status=None): self.http_status = http_status or self.http_status self.message = message or self.message self.details = details self.request_id = request_id self.response = response self.url = url self.method = method formatted_string = "%s (HTTP %s)" % (self.message, self.http_status) if request_id: formatted_string += " (Request-ID: %s)" % request_id super(HttpError, self).__init__(formatted_string)
def find(self, base_url=None, **kwargs): """Find a single item with attributes matching ``**kwargs``. :param base_url: if provided, the generated URL will be appended to it """ kwargs = self._filter_kwargs(kwargs) rl = self._list( '%(base_url)s%(query)s' % { 'base_url': self.build_url(base_url=base_url, **kwargs), 'query': '?%s' % parse.urlencode(kwargs) if kwargs else '', }, self.collection_key) num = len(rl) if num == 0: msg = _("No %(name)s matching %(args)s.") % { 'name': self.resource_class.__name__, 'args': kwargs } raise exceptions.NotFound(msg) elif num > 1: raise exceptions.NoUniqueMatch else: return rl[0]
def find_resource(manager, name_or_id): """Helper for the _find_* methods.""" # first try to get entity as integer id try: if isinstance(name_or_id, int) or name_or_id.isdigit(): return manager.get(int(name_or_id)) except exc.NotFound: pass # now try to get entity as uuid try: uuid.UUID(str(name_or_id)) return manager.get(name_or_id) except (ValueError, exc.NotFound): pass # finally try to find entity by name try: return manager.find(name=name_or_id) except exc.NotFound: msg = (_("No %(name)s with a name or ID of " "'%(name_or_id)s' exists.") % { 'name': manager.resource_class.__name__.lower(), 'name_or_id': name_or_id }) raise exc.CommandError(msg)
def format_parameters(params, parse_semicolon=True): '''Reformat parameters into dict of format expected by the API.''' if not params: return {} if parse_semicolon: # expect multiple invocations of --parameters but fall back # to ; delimited if only one --parameters is specified if len(params) == 1: params = params[0].split(';') parameters = {} for p in params: try: (n, v) = p.split(('='), 1) except ValueError: msg = _('Malformed parameter(%s). Use the key=value format.') % p raise exc.CommandError(msg) if n not in parameters: parameters[n] = v else: if not isinstance(parameters[n], list): parameters[n] = [parameters[n]] parameters[n].append(v) return parameters
class PaymentRequired(HTTPClientError): """HTTP 402 - Payment Required. Reserved for future use. """ http_status = 402 message = _("Payment Required")
class RequestTimeout(HTTPClientError): """HTTP 408 - Request Timeout. The server timed out waiting for the request. """ http_status = 408 message = _("Request Timeout")
class RequestUriTooLong(HTTPClientError): """HTTP 414 - Request-URI Too Long. The URI provided was too long for the server to process. """ http_status = 414 message = _("Request-URI Too Long")
def find_resource(manager, name_or_id): """Helper for the _find_* methods.""" # first try to get entity as integer id try: if isinstance(name_or_id, int) or name_or_id.isdigit(): return manager.get(int(name_or_id)) except exc.NotFound: pass # now try to get entity as uuid try: uuid.UUID(str(name_or_id)) return manager.get(name_or_id) except (ValueError, exc.NotFound): pass # finally try to find entity by name try: return manager.find(name=name_or_id) except exc.NotFound: msg = ( _("No %(name)s with a name or ID of " "'%(name_or_id)s' exists.") % { 'name': manager.resource_class.__name__.lower(), 'name_or_id': name_or_id }) raise exc.CommandError(msg)
class InternalServerError(HttpServerError): """HTTP 500 - Internal Server Error. A generic error message, given when no more specific message is suitable. """ http_status = 500 message = _("Internal Server Error")
class ExpectationFailed(HTTPClientError): """HTTP 417 - Expectation Failed. The server cannot meet the requirements of the Expect request-header field. """ http_status = 417 message = _("Expectation Failed")
class ProxyAuthenticationRequired(HTTPClientError): """HTTP 407 - Proxy Authentication Required. The client must first authenticate itself with the proxy. """ http_status = 407 message = _("Proxy Authentication Required")
class HttpVersionNotSupported(HttpServerError): """HTTP 505 - HttpVersion Not Supported. The server does not support the HTTP protocol version used in the request. """ http_status = 505 message = _("HTTP Version Not Supported")
class ServiceUnavailable(HttpServerError): """HTTP 503 - Service Unavailable. The server is currently unavailable. """ http_status = 503 message = _("Service Unavailable")
class BadGateway(HttpServerError): """HTTP 502 - Bad Gateway. The server was acting as a gateway or proxy and received an invalid response from the upstream server. """ http_status = 502 message = _("Bad Gateway")
class HttpNotImplemented(HttpServerError): """HTTP 501 - Not Implemented. The server either does not recognize the request method, or it lacks the ability to fulfill the request. """ http_status = 501 message = _("Not Implemented")
class UnprocessableEntity(HTTPClientError): """HTTP 422 - Unprocessable Entity. The request was well-formed but was unable to be followed due to semantic errors. """ http_status = 422 message = _("Unprocessable Entity")
class NotAcceptable(HTTPClientError): """HTTP 406 - Not Acceptable. The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request. """ http_status = 406 message = _("Not Acceptable")
class PreconditionFailed(HTTPClientError): """HTTP 412 - Precondition Failed. The server does not meet one of the preconditions that the requester put on the request. """ http_status = 412 message = _("Precondition Failed")
class LengthRequired(HTTPClientError): """HTTP 411 - Length Required. The request did not specify the length of its content, which is required by the requested resource. """ http_status = 411 message = _("Length Required")
class Gone(HTTPClientError): """HTTP 410 - Gone. Indicates that the resource requested is no longer available and will not be available again. """ http_status = 410 message = _("Gone")
class Conflict(HTTPClientError): """HTTP 409 - Conflict. Indicates that the request could not be processed because of conflict in the request, such as an edit conflict. """ http_status = 409 message = _("Conflict")
def format_output(output, format='yaml'): """Format the supplied dict as specified.""" output_format = format.lower() try: return supported_formats[output_format](output) except KeyError: raise exc.HTTPUnsupported(_("The format(%s) is unsupported.") % output_format)
class NotFound(HTTPClientError): """HTTP 404 - Not Found. The requested resource could not be found but may be available again in the future. """ http_status = 404 message = _("Not Found")
class GatewayTimeout(HttpServerError): """HTTP 504 - Gateway Timeout. The server was acting as a gateway or proxy and did not receive a timely response from the upstream server. """ http_status = 504 message = _("Gateway Timeout")
class MethodNotAllowed(HTTPClientError): """HTTP 405 - Method Not Allowed. A request was made of a resource using a request method not supported by that resource. """ http_status = 405 message = _("Method Not Allowed")
class UnsupportedMediaType(HTTPClientError): """HTTP 415 - Unsupported Media Type. The request entity has a media type which the server or resource does not support. """ http_status = 415 message = _("Unsupported Media Type")
class Forbidden(HTTPClientError): """HTTP 403 - Forbidden. The request was a valid request, but the server is refusing to respond to it. """ http_status = 403 message = _("Forbidden")
def format_output(output, format='yaml'): """Format the supplied dict as specified.""" output_format = format.lower() try: return supported_formats[output_format](output) except KeyError: raise exc.HTTPUnsupported( _("The format(%s) is unsupported.") % output_format)
class RequestedRangeNotSatisfiable(HTTPClientError): """HTTP 416 - Requested Range Not Satisfiable. The client has asked for a portion of the file, but the server cannot supply that portion. """ http_status = 416 message = _("Requested Range Not Satisfiable")
def strip_endpoint(self, location): if location is None: message = _("Location not returned with 302") raise exc.InvalidEndpoint(message=message) if (self.endpoint_override is not None and location.lower().startswith(self.endpoint_override.lower())): return location[len(self.endpoint_override):] else: return location
def read_url_content(url): try: content = request.urlopen(url).read() except error.URLError: raise exc.CommandError(_('Could not fetch contents for %s') % url) if content: try: content.decode('utf-8') except ValueError: content = base64.encodestring(content) return content
def main(args=None): try: if args is None: args = sys.argv[1:] KingShell().main(args) except KeyboardInterrupt: print(_("... terminating king client"), file=sys.stderr) sys.exit(130) except Exception as e: if '--debug' in args or '-d' in args: raise else: print(encodeutils.safe_encode(six.text_type(e)), file=sys.stderr) sys.exit(1)
def print_list(objs, fields, formatters=None, sortby_index=0, mixed_case_fields=None, field_labels=None): """Print a list of objects as a table, one row per object. :param objs: iterable of :class:`Resource` :param fields: attributes that correspond to columns, in order :param formatters: `dict` of callables for field formatting :param sortby_index: index of the field for sorting table rows :param mixed_case_fields: fields corresponding to object attributes that have mixed case names (e.g., 'serverId') :param field_labels: Labels to use in the heading of the table, default to fields. """ formatters = formatters or {} mixed_case_fields = mixed_case_fields or [] field_labels = field_labels or fields if len(field_labels) != len(fields): raise ValueError(_("Field labels list %(labels)s has different number " "of elements than fields list %(fields)s"), {'labels': field_labels, 'fields': fields}) if sortby_index is None: kwargs = {} else: kwargs = {'sortby': field_labels[sortby_index]} pt = prettytable.PrettyTable(field_labels) pt.align = 'l' for o in objs: row = [] for field in fields: if field in formatters: row.append(formatters[field](o)) else: if field in mixed_case_fields: field_name = field.replace(' ', '_') else: field_name = field.lower().replace(' ', '_') data = getattr(o, field_name, '') row.append(data) pt.add_row(row) if six.PY3: print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode()) else: print(encodeutils.safe_encode(pt.get_string(**kwargs)))
def __init__(self, message=None, code=None): super(HTTPException, self).__init__(message) try: self.error = jsonutils.loads(message) if 'error' not in self.error: raise KeyError(_('Key "error" not exists')) except KeyError: # NOTE(jianingy): If key 'error' happens not exist, # self.message becomes no sense. In this case, we # return doc of current exception class instead. self.error = {'error': {'message': self.__class__.__doc__}} except Exception: self.error = {'error': {'message': self.message or self.__class__.__doc__}} if self.code == "N/A" and code is not None: self.code = code
def find(self, **kwargs): """Find a single item with attributes matching ``**kwargs``. This isn't very efficient: it loads the entire list then filters on the Python side. """ matches = self.findall(**kwargs) num_matches = len(matches) if num_matches == 0: msg = _("No %(name)s matching %(args)s.") % { 'name': self.resource_class.__name__, 'args': kwargs } raise exceptions.NotFound(msg) elif num_matches > 1: raise exceptions.NoUniqueMatch() else: return matches[0]
def get_class(api_name, version, version_map): """Returns the client class for the requested API version :param api_name: the name of the API, e.g. 'compute', 'image', etc :param version: the requested API version :param version_map: a dict of client classes keyed by version :rtype: a client class for the requested API version """ try: client_path = version_map[str(version)] except (KeyError, ValueError): msg = _("Invalid %(api_name)s client version '%(version)s'. " "Must be one of: %(version_map)s") % { 'api_name': api_name, 'version': version, 'version_map': ', '.join(version_map.keys())} raise exceptions.UnsupportedVersion(msg) return importutils.import_class(client_path)
def main(self, argv): # Parse args once to find version parser = self.get_base_parser() (options, args) = parser.parse_known_args(argv) self._setup_logging(options.debug) self._setup_verbose(options.verbose) # build available subcommands based on version api_version = options.king_api_version subcommand_parser = self.get_subcommand_parser(api_version) self.parser = subcommand_parser # Handle top-level --help/-h before attempting to parse # a command off the command line if not args and options.help or not argv: self.do_help(options) return 0 # Parse args again and call whatever callback was selected args = subcommand_parser.parse_args(argv) # Short-circuit and deal with help command 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.os_username and not args.os_auth_token: raise exc.CommandError(_("You must provide a username via either " "--os-username or env[OS_USERNAME] " "or a token via --os-auth-token or " "env[OS_AUTH_TOKEN]")) if not args.os_password and not args.os_auth_token: raise exc.CommandError(_("You must provide a password via either " "--os-password or env[OS_PASSWORD] " "or a token via --os-auth-token or " "env[OS_AUTH_TOKEN]")) if args.os_no_client_auth: if not args.king_url: raise exc.CommandError(_("If you specify --os-no-client-auth " "you must also specify a King API " "URL via either --king-url or " "env[KING_URL]")) else: # Tenant/project name or ID is needed to make keystoneclient # retrieve a service catalog, it's not required if # os_no_client_auth is specified, neither is the auth URL if not (args.os_tenant_id or args.os_tenant_name or args.os_project_id or args.os_project_name): raise exc.CommandError( _("You must provide a tenant id via either " "--os-tenant-id or env[OS_TENANT_ID] or a tenant name " "via either --os-tenant-name or env[OS_TENANT_NAME] " "or a project id via either --os-project-id or " "env[OS_PROJECT_ID] or a project name via " "either --os-project-name or env[OS_PROJECT_NAME]")) if not args.os_auth_url: raise exc.CommandError(_("You must provide an auth url via " "either --os-auth-url or via " "env[OS_AUTH_URL]")) kwargs = { 'insecure': args.insecure, 'cacert': args.os_cacert, 'cert': args.os_cert, 'key': args.os_key, 'timeout': args.api_timeout } endpoint = args.king_url service_type = args.os_service_type or 'charging' if args.os_no_client_auth: # Do not use session since no_client_auth means using king to # to authenticate kwargs = { 'username': args.os_username, 'password': args.os_password, 'auth_url': args.os_auth_url, 'token': args.os_auth_token, 'include_pass': args.include_password, 'insecure': args.insecure, 'timeout': args.api_timeout } else: keystone_session = self._get_keystone_session(**kwargs) endpoint_type = args.os_endpoint_type or 'publicURL' if args.os_auth_token: kwargs = { 'token': args.os_auth_token, 'auth_url': args.os_auth_url } keystone_auth = generic.Token(**kwargs) else: project_id = args.os_project_id or args.os_tenant_id project_name = args.os_project_name or args.os_tenant_name kwargs = { 'username': args.os_username, 'user_id': args.os_user_id, 'user_domain_id': args.os_user_domain_id, 'user_domain_name': args.os_user_domain_name, 'password': args.os_password, 'auth_url': args.os_auth_url, 'project_id': project_id, 'project_name': project_name, 'project_domain_id': args.os_project_domain_id, 'project_domain_name': args.os_project_domain_name, } keystone_auth = generic.Password(**kwargs) if not endpoint: svc_type = service_type region_name = args.os_region_name endpoint = keystone_auth.get_endpoint(keystone_session, service_type=svc_type, interface=endpoint_type, region_name=region_name) kwargs = { 'auth_url': args.os_auth_url, 'session': keystone_session, 'auth': keystone_auth, 'service_type': service_type, 'endpoint_type': endpoint_type, 'region_name': args.os_region_name, 'username': args.os_username, 'password': args.os_password, 'include_pass': args.include_password } client = king_client.Client(api_version, endpoint, **kwargs) profile = osprofiler_profiler and options.profile if profile: osprofiler_profiler.init(options.profile) args.func(client, 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 _append_global_identity_args(self, parser): # FIXME(gyee): these are global identity (Keystone) arguments which # should be consistent and shared by all service clients. Therefore, # they should be provided by python-keystoneclient. We will need to # refactor this code once this functionality is available in # python-keystoneclient. parser.add_argument( '-k', '--insecure', default=False, action='store_true', help=_('Explicitly allow kingclient to perform ' '\"insecure SSL\" (https) requests. ' 'The server\'s certificate will not be verified ' 'against any certificate authorities. ' 'This option should be used with caution.')) parser.add_argument( '--os-cert', default=utils.env('OS_CERT'), help=_('Path of certificate file to use in SSL connection. ' 'This file can optionally be prepended with ' 'the private key.')) # for backward compatibility only parser.add_argument('--cert-file', dest='os_cert', help=_('DEPRECATED! Use %(arg)s.') % {'arg': '--os-cert'}) parser.add_argument('--os-key', default=utils.env('OS_KEY'), help=_('Path of client key to use in SSL ' 'connection. This option is not necessary ' 'if your key is prepended to your cert ' 'file.')) parser.add_argument('--key-file', dest='os_key', help=_('DEPRECATED! Use %(arg)s.') % {'arg': '--os-key'}) parser.add_argument('--os-cacert', metavar='<ca-certificate-file>', dest='os_cacert', default=utils.env('OS_CACERT'), help=_('Path of CA TLS certificate(s) used to ' 'verify the remote server\'s certificate. ' 'Without this option glance looks for the ' 'default system CA certificates.')) parser.add_argument('--ca-file', dest='os_cacert', help=_('DEPRECATED! Use %(arg)s.') % {'arg': '--os-cacert'}) parser.add_argument('--os-username', default=utils.env('OS_USERNAME'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_USERNAME]' }) parser.add_argument('--os_username', help=argparse.SUPPRESS) parser.add_argument('--os-user-id', default=utils.env('OS_USER_ID'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_USER_ID]' }) parser.add_argument('--os_user_id', help=argparse.SUPPRESS) parser.add_argument('--os-user-domain-id', default=utils.env('OS_USER_DOMAIN_ID'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_USER_DOMAIN_ID]' }) parser.add_argument('--os_user_domain_id', help=argparse.SUPPRESS) parser.add_argument('--os-user-domain-name', default=utils.env('OS_USER_DOMAIN_NAME'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_USER_DOMAIN_NAME]' }) parser.add_argument('--os_user_domain_name', help=argparse.SUPPRESS) parser.add_argument('--os-project-id', default=utils.env('OS_PROJECT_ID'), help=(_('Another way to specify tenant ID. ' 'This option is mutually exclusive with ' '%(arg)s. Defaults to %(value)s.') % { 'arg': '--os-tenant-id', 'value': 'env[OS_PROJECT_ID]'})) parser.add_argument('--os_project_id', help=argparse.SUPPRESS) parser.add_argument('--os-project-name', default=utils.env('OS_PROJECT_NAME'), help=(_('Another way to specify tenant name. ' 'This option is mutually exclusive with ' '%(arg)s. Defaults to %(value)s.') % { 'arg': '--os-tenant-name', 'value': 'env[OS_PROJECT_NAME]'})) parser.add_argument('--os_project_name', help=argparse.SUPPRESS) parser.add_argument('--os-project-domain-id', default=utils.env('OS_PROJECT_DOMAIN_ID'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_PROJECT_DOMAIN_ID]' }) parser.add_argument('--os_project_domain_id', help=argparse.SUPPRESS) parser.add_argument('--os-project-domain-name', default=utils.env('OS_PROJECT_DOMAIN_NAME'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_PROJECT_DOMAIN_NAME]' }) parser.add_argument('--os_project_domain_name', help=argparse.SUPPRESS) parser.add_argument('--os-password', default=utils.env('OS_PASSWORD'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_PASSWORD]' }) parser.add_argument('--os_password', help=argparse.SUPPRESS) parser.add_argument('--os-tenant-id', default=utils.env('OS_TENANT_ID'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_TENANT_ID]' }) parser.add_argument('--os_tenant_id', default=utils.env('OS_TENANT_ID'), help=argparse.SUPPRESS) parser.add_argument('--os-tenant-name', default=utils.env('OS_TENANT_NAME'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_TENANT_NAME]' }) parser.add_argument('--os_tenant_name', default=utils.env('OS_TENANT_NAME'), help=argparse.SUPPRESS) parser.add_argument('--os-auth-url', default=utils.env('OS_AUTH_URL'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_AUTH_URL]' }) parser.add_argument('--os_auth_url', help=argparse.SUPPRESS) parser.add_argument('--os-region-name', default=utils.env('OS_REGION_NAME'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_REGION_NAME]' }) parser.add_argument('--os_region_name', help=argparse.SUPPRESS) parser.add_argument('--os-auth-token', default=utils.env('OS_AUTH_TOKEN'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_AUTH_TOKEN]' }) parser.add_argument('--os_auth_token', help=argparse.SUPPRESS) parser.add_argument('--os-service-type', default=utils.env('OS_SERVICE_TYPE'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_SERVICE_TYPE]' }) parser.add_argument('--os_service_type', help=argparse.SUPPRESS) parser.add_argument('--os-endpoint-type', default=utils.env('OS_ENDPOINT_TYPE'), help=_('Defaults to %(value)s.') % { 'value': 'env[OS_ENDPOINT_TYPE]' }) parser.add_argument('--os_endpoint_type', help=argparse.SUPPRESS)
def get_base_parser(self): parser = argparse.ArgumentParser( prog='king', description=__doc__.strip(), epilog=_('See "%(arg)s" for help on a specific command.') % { 'arg': 'king help COMMAND' }, add_help=False, formatter_class=HelpFormatter, ) # Global arguments parser.add_argument('-h', '--help', action='store_true', help=argparse.SUPPRESS) parser.add_argument('--version', action='version', version=kingclient.__version__, help=_("Shows the client version and exits.")) parser.add_argument('-d', '--debug', default=bool(utils.env('KINGCLIENT_DEBUG')), action='store_true', help=_('Defaults to %(value)s.') % { 'value': 'env[KINGCLIENT_DEBUG]' }) parser.add_argument('-v', '--verbose', default=False, action="store_true", help=_("Print more verbose output.")) parser.add_argument('--api-timeout', help=_('Number of seconds to wait for an ' 'API response, ' 'defaults to system socket timeout')) # os-no-client-auth tells kingclient to use token, instead of # env[OS_AUTH_URL] parser.add_argument('--os-no-client-auth', default=utils.env('OS_NO_CLIENT_AUTH'), action='store_true', help=(_("Do not contact keystone for a token. " "Defaults to %(value)s.") % {'value': 'env[OS_NO_CLIENT_AUTH]'})) parser.add_argument('--king-url', default=utils.env('KING_URL'), help=_('Defaults to %(value)s.') % { 'value': 'env[KING_URL]' }) parser.add_argument('--king_url', help=argparse.SUPPRESS) parser.add_argument('--king-api-version', default=utils.env('KING_API_VERSION', default='1'), help=_('Defaults to %(value)s or 1.') % { 'value': 'env[KING_API_VERSION]' }) parser.add_argument('--king_api_version', help=argparse.SUPPRESS) # This unused option should remain so that scripts that # use it do not break. It is suppressed so it will not # appear in the help. parser.add_argument('-t', '--token-only', default=bool(False), action='store_true', help=argparse.SUPPRESS) parser.add_argument('--include-password', default=bool(utils.env('KING_INCLUDE_PASSWORD')), action='store_true', help=_('Send %(arg1)s and %(arg2)s to king.') % { 'arg1': 'os-username', 'arg2': 'os-password' }) # FIXME(gyee): this method should come from python-keystoneclient. # Will refactor this code once it is available. # https://bugs.launchpad.net/python-keystoneclient/+bug/1332337 self._append_global_identity_args(parser) if osprofiler_profiler: parser.add_argument( '--profile', metavar='HMAC_KEY', help=_('HMAC key to use for encrypting context data ' 'for performance profiling of operation. ' 'This key should be the value of HMAC key ' 'configured in osprofiler middleware in king, ' 'it is specified in the paste configuration ' '(/etc/king/api-paste.ini). Without the key, ' 'profiling will not be triggered ' 'even if osprofiler is enabled on server side.')) return parser
def client_request(self, client, method, url, **kwargs): """Send an http request using `client`'s endpoint and specified `url`. If request was rejected as unauthorized (possibly because the token is expired), issue one authorization attempt and send the request once again. :param client: instance of BaseClient descendant :param method: method of HTTP request :param url: URL of HTTP request :param kwargs: any other parameter that can be passed to `HTTPClient.request` """ filter_args = { "endpoint_type": client.endpoint_type or self.endpoint_type, "service_type": client.service_type, } token, endpoint = (self.cached_token, client.cached_endpoint) just_authenticated = False if not (token and endpoint): try: token, endpoint = self.auth_plugin.token_and_endpoint( **filter_args) except exceptions.EndpointException: pass if not (token and endpoint): self.authenticate() just_authenticated = True token, endpoint = self.auth_plugin.token_and_endpoint( **filter_args) if not (token and endpoint): raise exceptions.AuthorizationFailure( _("Cannot find endpoint or token for request")) old_token_endpoint = (token, endpoint) kwargs.setdefault("headers", {})["X-Auth-Token"] = token self.cached_token = token client.cached_endpoint = endpoint # Perform the request once. If we get Unauthorized, then it # might be because the auth token expired, so try to # re-authenticate and try again. If it still fails, bail. try: return self.request( method, self.concat_url(endpoint, url), **kwargs) except exceptions.Unauthorized as unauth_ex: if just_authenticated: raise self.cached_token = None client.cached_endpoint = None if self.auth_plugin.opts.get('token'): self.auth_plugin.opts['token'] = None if self.auth_plugin.opts.get('endpoint'): self.auth_plugin.opts['endpoint'] = None self.authenticate() try: token, endpoint = self.auth_plugin.token_and_endpoint( **filter_args) except exceptions.EndpointException: raise unauth_ex if (not (token and endpoint) or old_token_endpoint == (token, endpoint)): raise unauth_ex self.cached_token = token client.cached_endpoint = endpoint kwargs["headers"]["X-Auth-Token"] = token return self.request( method, self.concat_url(endpoint, url), **kwargs)
def _http_request(self, url, method, **kwargs): """Send an http request with the specified characteristics. Wrapper around requests.request to handle tasks such as setting headers and error handling. """ # Copy the kwargs so we can reuse the original in case of redirects kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) kwargs['headers'].setdefault('User-Agent', USER_AGENT) if self.auth_token: kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) else: kwargs['headers'].update(self.credentials_headers()) if self.auth_url: kwargs['headers'].setdefault('X-Auth-Url', self.auth_url) if self.region_name: kwargs['headers'].setdefault('X-Region-Name', self.region_name) if self.include_pass and 'X-Auth-Key' not in kwargs['headers']: kwargs['headers'].update(self.credentials_headers()) if osprofiler_web: kwargs['headers'].update(osprofiler_web.get_trace_id_headers()) self.log_curl_request(method, url, kwargs) if self.cert_file and self.key_file: kwargs['cert'] = (self.cert_file, self.key_file) if self.verify_cert is not None: kwargs['verify'] = self.verify_cert if self.timeout is not None: kwargs['timeout'] = float(self.timeout) # Allow caller to specify not to follow redirects, in which case we # just return the redirect response. Useful for using stacks:lookup. redirect = kwargs.pop('redirect', True) # Since requests does not follow the RFC when doing redirection to sent # back the same method on a redirect we are simply bypassing it. For # example if we do a DELETE/POST/PUT on a URL and we get a 302 RFC says # that we should follow that URL with the same method as before, # requests doesn't follow that and send a GET instead for the method. # Hopefully this could be fixed as they say in a comment in a future # point version i.e.: 3.x # See issue: https://github.com/kennethreitz/requests/issues/1704 allow_redirects = False # Use fully qualified URL from response header for redirects if not parse.urlparse(url).netloc: url = self.endpoint_url + url try: resp = requests.request( method, url, allow_redirects=allow_redirects, **kwargs) except socket.gaierror as e: message = (_("Error finding address for %(url)s: %(e)s") % {'url': self.endpoint_url + url, 'e': e}) raise exc.InvalidEndpoint(message=message) except (socket.error, socket.timeout) as e: endpoint = self.endpoint message = (_("Error communicating with %(endpoint)s %(e)s") % {'endpoint': endpoint, 'e': e}) raise exc.CommunicationError(message=message) self.log_http_response(resp) if not ('X-Auth-Key' in kwargs['headers']) and ( resp.status_code == 401 or (resp.status_code == 500 and "(HTTP 401)" in resp.content)): raise exc.HTTPUnauthorized(_("Authentication failed: %s") % resp.content) elif 400 <= resp.status_code < 600: raise exc.from_response(resp) elif resp.status_code in (301, 302, 305): # Redirected. Reissue the request to the new location, # unless caller specified redirect=False if redirect: location = resp.headers.get('location') if not location: message = _("Location not returned with redirect") raise exc.InvalidEndpoint(message=message) resp = self._http_request(location, method, **kwargs) elif resp.status_code == 300: raise exc.from_response(resp) return resp
def __init__(self, missing): self.missing = missing msg = _("Missing arguments: %s") % ", ".join(missing) super(MissingArgs, self).__init__(msg)