def build_option_parser(parser): """Hook to add global options""" parser.add_argument( '--os-application-catalog-api-version', metavar='<application-catalog-api-version>', default=utils.env( 'OS_APPLICATION_CATALOG_API_VERSION', default=DEFAULT_APPLICATION_CATALOG_API_VERSION), help=_("Application catalog API version, default={0}" "(Env:OS_APPLICATION_CATALOG_API_VERSION)").format( DEFAULT_APPLICATION_CATALOG_API_VERSION)) parser.add_argument('--murano-url', default=utils.env('MURANO_URL'), help=_('Defaults to env[MURANO_URL].')) parser.add_argument('--glare-url', default=utils.env('GLARE_URL'), help='Defaults to env[GLARE_URL].') parser.add_argument('--murano-packages-service', choices=['murano', 'glare'], default=utils.env('MURANO_PACKAGES_SERVICE', default='murano'), help='Specifies if murano-api ("murano") or ' 'Glance Artifact Repository ("glare") ' 'should be used to store murano packages. ' 'Defaults to env[MURANO_PACKAGES_SERVICE] or ' 'to "murano"') return parser
def build_option_parser(parser): """Hook to add global options""" parser.add_argument( '--os-application-catalog-api-version', metavar='<application-catalog-api-version>', default=utils.env( 'OS_APPLICATION_CATALOG_API_VERSION', default=DEFAULT_APPLICATION_CATALOG_API_VERSION), help=_("Application catalog API version, default={0}" "(Env:OS_APPLICATION_CATALOG_API_VERSION)").format( DEFAULT_APPLICATION_CATALOG_API_VERSION)) parser.add_argument('--murano-url', default=utils.env('MURANO_URL'), help=_('Defaults to env[MURANO_URL].')) return parser
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 BadRequest(HTTPClientError): """HTTP 400 - Bad Request. The request cannot be fulfilled due to bad syntax. """ http_status = 400 message = _("Bad Request")
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 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")
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")
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(404, msg) elif num > 1: raise exceptions.NoUniqueMatch else: return rl[0]
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)
class RequestTimeout(HTTPClientError): """HTTP 408 - Request Timeout. The server timed out waiting for the request. """ http_status = 408 message = _("Request Timeout")
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 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 PaymentRequired(HTTPClientError): """HTTP 402 - Payment Required. Reserved for future use. """ http_status = 402 message = _("Payment Required")
class MultipleChoices(HTTPRedirection): """HTTP 300 - Multiple Choices. Indicates multiple options for the resource that the client may follow. """ http_status = 300 message = _("Multiple Choices")
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 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 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 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 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 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")
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 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 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 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 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 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")
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 Unauthorized(HTTPClientError): """HTTP 401 - Unauthorized. Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided. """ http_status = 401 message = _("Unauthorized")
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 to_dict(self): keys = ('author', 'categories', 'class_definitions', 'created', 'description', 'enabled', 'fully_qualified_name', 'id', 'is_public', 'name', 'owner_id', 'tags', 'type', 'updated') missing_keys = [key for key in keys if not hasattr(self, key)] if missing_keys: raise KeyError(_("Some attributes are missing in " "%(pkg_name)s: %(attrs)s.") % {'pkg_name': self.name, 'attrs': ", ".join(missing_keys)}) return {key: getattr(self, key) for key in keys}
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 ensure_images(glance_client, image_specs, base_url, local_path=None, is_package_public=False): """Ensure that images are available Ensure that images from image_specs are available in glance. If not attempts: instructs glance to download the images and sets murano-specific metadata for it. """ def _image_valid(image, keys): for key in keys: if key not in image: LOG.warning("Image specification invalid: " "No {0} key in image ".format(key)) return False return True keys = ['Name', 'DiskFormat', 'ContainerFormat', ] installed_images = [] for image_spec in image_specs: if not _image_valid(image_spec, keys): continue filters = { 'name': image_spec["Name"], 'disk_format': image_spec["DiskFormat"], 'container_format': image_spec["ContainerFormat"], } images = glance_client.images.list(filters=filters) try: img = next(images).to_dict() except StopIteration: img = None update_metadata = False if img: LOG.info("Found desired image {0}, id {1}".format( img['name'], img['id'])) # check for murano meta-data if 'murano_image_info' in img.get('properties', {}): LOG.info("Image {0} already has murano meta-data".format( image_spec['Name'])) else: update_metadata = True else: LOG.info("Desired image {0} not found attempting " "to download".format(image_spec['Name'])) update_metadata = True img_file = None if local_path: img_file = os.path.join(local_path, image_spec['Name']) if img_file and not os.path.exists(img_file): LOG.error("Image file {0} does not exist." .format(img_file)) if img_file and os.path.exists(img_file): img = glance_client.images.create( name=image_spec['Name'], container_format=image_spec['ContainerFormat'], disk_format=image_spec['DiskFormat'], data=open(img_file, 'rb'), ) img = img.to_dict() else: download_url = to_url( image_spec.get("Url", image_spec['Name']), base_url=base_url, path='images/', ) LOG.info("Instructing glance to download image {0}".format( image_spec['Name'])) img = glance_client.images.create( name=image_spec["Name"], container_format=image_spec['ContainerFormat'], disk_format=image_spec['DiskFormat'], copy_from=download_url) img = img.to_dict() if is_package_public: try: glance_client.images.update(img['id'], is_public=True) LOG.debug('Success update for image {0}'.format(img['id'])) except Exception as e: LOG.exception(_("Error {0} occurred while setting " "image {1} public").format(e, img['id'])) installed_images.append(img) if update_metadata and 'Meta' in image_spec: LOG.info("Updating image {0} metadata".format( image_spec['Name'])) murano_image_info = jsonutils.dumps(image_spec['Meta']) glance_client.images.update( img['id'], properties={'murano_image_info': murano_image_info}) return installed_images
def __init__(self, missing): self.missing = missing msg = _("Missing arguments: %s") % ", ".join(missing) super(MissingArgs, self).__init__(msg)
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 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 __init__(self, opt_names): super(AuthPluginOptionsMissing, self).__init__( _("Authentication failed. Missing options: %s") % ", ".join(opt_names)) self.opt_names = opt_names
def __init__(self, endpoints=None): super(AmbiguousEndpoints, self).__init__( _("AmbiguousEndpoints: %s") % repr(endpoints)) self.endpoints = endpoints
def __init__(self, auth_system): super(AuthSystemNotFound, self).__init__( _("AuthSystemNotFound: %s") % repr(auth_system)) self.auth_system = auth_system