Commit 3a4db0d3 authored by Ilias Tsitsimpis's avatar Ilias Tsitsimpis

astakosclient: Human readable details message

In case of QuotaLimit exception, fill 'details' with a human readable
message and put the actual JSON response in the 'response' variable.
Synnefo UI shows the 'details' field of an exception to the user so it
has to be human readable.
parent 4b6f82fb
......@@ -30,7 +30,8 @@ except ImportError:
import json
from astakosclient.utils import \
retry_dec, scheme_to_class, parse_request, check_input, join_urls
retry_dec, scheme_to_class, parse_request, check_input, join_urls, \
render_overlimit_exception
from astakosclient.errors import \
AstakosClientException, Unauthorized, BadRequest, NotFound, Forbidden, \
NoUserName, NoUUID, BadValue, QuotaLimit, InvalidResponse, NoEndpoints, \
......@@ -301,7 +302,8 @@ class AstakosClient(object):
elif status == 404:
raise NotFound(message, data)
elif status < 200 or status >= 300:
raise AstakosClientException(message, data, status)
raise AstakosClientException(
message=message, status=status, response=data)
try:
if data:
......@@ -311,7 +313,7 @@ class AstakosClient(object):
except Exception as err:
msg = "Cannot parse response \"%r\" with simplejson: %s"
self.logger.error(msg % (data, str(err)))
raise InvalidResponse(str(err), data)
raise InvalidResponse(message=str(err), response=data)
# ----------------------------------
# do a POST to ``API_USERCATALOGS`` (or ``API_SERVICE_USERCATALOGS``)
......@@ -328,7 +330,7 @@ class AstakosClient(object):
msg = "_uuid_catalog request returned %r. No uuid_catalog found" \
% data
self.logger.error(msg)
raise AstakosClientException(msg)
raise AstakosClientException(message=msg, response=data)
def get_usernames(self, uuids):
"""Return a uuid_catalog dictionary for the given uuids
......@@ -379,7 +381,7 @@ class AstakosClient(object):
msg = "_displayname_catalog request returned %r. " \
"No displayname_catalog found" % data
self.logger.error(msg)
raise AstakosClientException(msg)
raise AstakosClientException(message=msg, response=data)
def get_uuids(self, display_names):
"""Return a displayname_catalog for the given names
......@@ -601,7 +603,17 @@ class AstakosClient(object):
method="POST")
except AstakosClientException as err:
if err.status == 413:
raise QuotaLimit(err.message, err.details)
try:
msg, details = render_overlimit_exception(
err.response, self.logger)
except Exception as perr:
self.logger.error("issue_commission request returned '413'"
" but response '%r' could not be parsed:"
" %s", err.response, str(perr))
msg, details = err.message, ""
raise QuotaLimit(message=msg,
details=details,
response=err.response)
else:
raise
......@@ -611,7 +623,7 @@ class AstakosClient(object):
msg = "issue_commission_core request returned %r. " + \
"No serial found" % response
self.logger.error(msg)
raise AstakosClientException(msg)
raise AstakosClientException(message=msg, response=response)
def _mk_user_provision(self, holder, source, resource, quantity):
holder = "user:" + holder
......
......@@ -20,10 +20,12 @@ Astakos Client Exceptions
class AstakosClientException(Exception):
"""Base AstakosClientException Class"""
def __init__(self, message='', details='', status=500, errobject=None):
def __init__(self, message='', details='', status=500,
response=None, errobject=None):
self.message = message
self.details = details
self.errobject = errobject
self.response = response
if not hasattr(self, 'status'):
self.status = status
super(AstakosClientException,
......@@ -46,8 +48,6 @@ class BadValue(AstakosClientException):
class InvalidResponse(AstakosClientException):
"""Return simplejson parse Exception as AstakosClient one"""
def __init__(self, message, details):
super(InvalidResponse, self).__init__(message, details)
class BadRequest(AstakosClientException):
......
......@@ -102,3 +102,35 @@ def check_input(function_name, logger, **kwargs):
def join_urls(url_a, url_b):
"""Join_urls from synnefo.lib"""
return url_a.rstrip("/") + "/" + url_b.lstrip("/")
def render_overlimit_exception(response, logger):
"""Render a human readable message for QuotaLimit Exception"""
resource_name = {
"cyclades.disk": "Disk",
"cyclades.vm": "Virtual Machine",
"cyclades.cpu": "CPU",
"cyclades.ram": "RAM",
"cyclades.floating_ip": "Floating IP address",
"cyclades.network.private": "Private Network",
"pithos.diskspace": "Storage space",
"astakos.pending_app": "Pending Applications"
}
response = json.loads(response)
data = response['overLimit']['data']
usage = data["usage"]
limit = data["limit"]
available = limit - usage
provision = data['provision']
requested = provision['quantity']
resource = provision['resource']
try:
resource = resource_name[resource]
except KeyError:
logger.error("Unknown resource name '%s'", resource)
msg = "Resource Limit Exceeded for your account."
details = "Limit for resource '%s' exceeded for your account."\
" Available: %s, Requested: %s"\
% (resource, available, requested)
return msg, details
......@@ -13,7 +13,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.utils import simplejson as json
from synnefo.db import transaction
from snf_django.lib.api import faults
......@@ -67,7 +66,7 @@ class AstakosClientExceptionHandler(object):
def __enter__(self):
pass
def check_notFound(self):
def check_not_found(self):
if not self.user or not self.projects:
return
try:
......@@ -90,10 +89,9 @@ class AstakosClientExceptionHandler(object):
if not isinstance(value, errors.AstakosClientException):
return False # reraise
if exc_type is errors.QuotaLimit:
msg, details = render_overlimit_exception(value)
raise faults.OverLimit(msg, details=details)
raise faults.OverLimit(value.message, details=value.details)
if exc_type is errors.NotFound:
self.check_notFound()
self.check_not_found()
log.exception("Unexpected error %s" % value.message)
raise faults.InternalServerError("Unexpected error")
......@@ -251,33 +249,6 @@ def get_quotaholder_pending():
return pending_serials
def render_overlimit_exception(e):
resource_name = {"vm": "Virtual Machine",
"cpu": "CPU",
"ram": "RAM",
"network.private": "Private Network",
"floating_ip": "Floating IP address"}
details = json.loads(e.details)
data = details['overLimit']['data']
usage = data["usage"]
limit = data["limit"]
available = limit - usage
provision = data['provision']
requested = provision['quantity']
resource = provision['resource']
res = resource.replace("cyclades.", "", 1)
try:
resource = resource_name[res]
except KeyError:
resource = res
msg = "Resource Limit Exceeded for your account."
details = "Limit for resource '%s' exceeded for your account."\
" Available: %s, Requested: %s"\
% (resource, available, requested)
return msg, details
@transaction.commit_on_success
def issue_and_accept_commission(resource, action="BUILD", action_fields=None):
"""Issue and accept a commission to Quotaholder.
......@@ -393,7 +364,7 @@ def get_commission_info(resource, action, action_fields=None):
get_volume_size_delta(action, db_volume, info)
return resources
else:
#["CONNECT", "DISCONNECT", "SET_FIREWALL_PROFILE"]:
# ["CONNECT", "DISCONNECT", "SET_FIREWALL_PROFILE"]:
return None
elif isinstance(resource, Network):
resources = {(project, "cyclades.network.private"): 1}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment