Simple per-user instance quota checking in the create call. PEP8 fixes.

This commit is contained in:
Ed Cranford 2012-06-15 11:55:50 -05:00
parent 04110bd7ea
commit 25c97fa6c5
12 changed files with 51 additions and 21 deletions

View File

@ -50,6 +50,7 @@ block_device_mapping = /var/lib/mysql
device_path = /var/lib/mysql
mount_point = /var/lib/mysql
max_accepted_volume_size = 10
max_instances_per_user = 5
volume_time_out=30
# Reddwarf DNS

View File

@ -61,7 +61,8 @@ nova_volume_service_type = volume
nova_volume_service_name = Volume Service
device_path = /dev/vdb
mount_point = /var/lib/mysql
max_accepted_volume_size = 10
max_accepted_volume_size = 25
max_instances_per_user = 5
volume_time_out=30
# Auth

View File

@ -82,6 +82,16 @@ class OverLimit(ReddwarfError):
"rate.")
class QuotaExceeded(ReddwarfError):
message = _("User instance quota exceeded.")
class VolumeQuotaExceeded(QuotaExceeded):
message = _("Instance volume quota exceeded.")
class GuestError(ReddwarfError):
message = _("An error occurred communicating with the guest: "

View File

@ -56,6 +56,8 @@ class BaseController(wsgi.Controller):
],
webob.exc.HTTPRequestEntityTooLarge: [
exception.OverLimit,
exception.QuotaExceeded,
exception.VolumeQuotaExceeded,
],
webob.exc.HTTPServerError: [
exception.VolumeCreationFailure
@ -246,6 +248,17 @@ class InstanceController(BaseController):
raise exception.BadValue(msg=e)
else:
volume_size = None
instance_max = int(config.Config.get('max_instances_per_user', 5))
number_instances = models.DBInstance.find_all(tenant_id=tenant_id,
deleted=False).count()
if number_instances >= instance_max:
# That's too many, pal. Got to cut you off.
LOG.error(_("New instance would exceed user instance quota."))
msg = "User instance quota of %d would be exceeded."
raise exception.QuotaExceeded(msg % instance_max)
instance = models.Instance.create(context, name, flavor_id,
image_id, databases, users,
service_type, volume_size)
@ -285,18 +298,18 @@ class InstanceController(BaseController):
"integer value, %s cannot be accepted."
% volume_size)
raise exception.ReddwarfError(msg)
max_size = int(config.Config.get('max_accepted_volume_size',
1))
max_size = int(config.Config.get('max_accepted_volume_size', 1))
if int(volume_size) > max_size:
msg = ("Volume 'size' cannot exceed maximum "
"of %d Gb, %s cannot be accepted."
% (max_size, volume_size))
raise exception.ReddwarfError(msg)
raise exception.VolumeQuotaExceeded(msg)
@staticmethod
def _validate(body):
"""Validate that the request has all the required parameters"""
InstanceController._validate_body_not_empty(body)
try:
body['instance']
body['instance']['flavorRef']
@ -315,6 +328,7 @@ class InstanceController(BaseController):
raise exception.MissingKey(key="size")
elif must_have_vol:
raise exception.MissingKey(key="volume")
except KeyError as e:
LOG.error(_("Create Instance Required field(s) - %s") % e)
raise exception.ReddwarfError("Required element/key - %s "

View File

@ -59,6 +59,7 @@ class API(object):
logging.error("Error running async task:")
logging.error((traceback.format_exception(type_, value, tb)))
raise type_, value, tb
eventlet.spawn_after(0, func)
def _get_routing_key(self):

View File

@ -80,4 +80,3 @@ class TaskManager(service.Manager):
instance_tasks.create_instance(flavor_id, flavor_ram, image_id,
databases, users, service_type,
volume_size)

View File

@ -148,7 +148,8 @@ class FreshInstanceTasks(FreshInstance):
if utils.bool_from_string(dns_support):
def get_server():
return nova_client.servers.get(self.db_info.compute_instance_id)
c_id = self.db_info.compute_instance_id
return nova_client.servers.get(c_id)
def ip_is_available(server):
LOG.info("Polling for ip addresses: $%s " % server.addresses)
@ -200,7 +201,7 @@ class BuiltInstanceTasks(BuiltInstance):
dns_api.delete_instance_entry(instance_id=self.db_info.id)
except Exception as ex:
LOG.error("Error during dns entry for instance %s "
% self.db_info.id )
% self.db_info.id)
LOG.error(ex)
def resize_volume(self, new_size):

View File

@ -21,4 +21,3 @@ from rsdns.client.dns_client import DNSaas
from rsdns.client.dns_client import DNSaasClient
from rsdns.client.domains import DomainsManager
from rsdns.client.records import RecordsManager

View File

@ -38,7 +38,7 @@ LOG = logging.getLogger('rsdns.client.dns_client')
class DNSaasClient(HTTPClient):
def __init__(self, accountId, user, apikey, auth_url, management_base_url):
tenant = "dbaas"
tenant = "dbaas"
super(DNSaasClient, self).__init__(user, apikey, tenant, auth_url)
self.accountId = accountId
self.management_base_url = management_base_url
@ -48,7 +48,8 @@ class DNSaasClient(HTTPClient):
def authenticate(self):
"""Set the management url and auth token"""
req_body = {'credentials':{'username':self.user, 'key':self.api_key}}
req_body = {'credentials': {'username': self.user,
'key': self.api_key}}
resp, body = self.request(self.auth_url, "POST", body=req_body)
if 'access' in body:
if not self.management_url:
@ -103,6 +104,7 @@ class DNSaasClient(HTTPClient):
return resp, body
class DNSaas(Client):
"""
Top-level object to access the DNSaas service
@ -115,8 +117,9 @@ class DNSaas(Client):
from rsdns.client.domains import DomainsManager
from rsdns.client.records import RecordsManager
super(DNSaas, self).__init__(self, accountId, username, apikey, auth_url, management_base_url)
super(DNSaas, self).__init__(self, accountId, username, apikey,
auth_url, management_base_url)
self.client = DNSaasClient(accountId, username, apikey, auth_url,
management_base_url)
self.domains = DomainsManager(self)
self.records = RecordsManager(self)
self.records = RecordsManager(self)

View File

@ -31,6 +31,7 @@ class Domain(base.Resource):
def response_list_name(self):
return "domains"
class FutureDomain(FutureResource):
def convert_callback(self, resp, body):

View File

@ -1,4 +1,5 @@
class RsDnsError(RuntimeError):
def __init__(self, error):
@ -13,9 +14,10 @@ class RsDnsError(RuntimeError):
def __str__(self):
return self.message
class FutureResource(object):
"""Polls a callback url to return a resource."""
def __init__(self, manager, jobId, callbackUrl, status, **kwargs):
self.manager = manager
self.jobId = jobId
@ -41,8 +43,6 @@ class FutureResource(object):
return None
resp_list = body['response'][self.response_list_name()]
self.result = self.manager.create_from_list(resp_list)
#self.resource_class(self, res) for res in list]
#self.result = Domain(self.manager, body['self.convert_callback(resp, body)
return self.result
@property

View File

@ -53,7 +53,8 @@ class RecordsManager(base.ManagerWithFind):
"""
resource_class = Record
def create(self, domain, record_name, record_data, record_type, record_ttl):
def create(self, domain, record_name, record_data, record_type,
record_ttl):
"""
Create a new Record on the given domain
@ -61,14 +62,14 @@ class RecordsManager(base.ManagerWithFind):
:param record: The ID of the :class:`Record` to get.
:rtype: :class:`Record`
"""
data = {"records":[{"type": record_type, "name": record_name,
"data": record_data, "ttl": record_ttl }]}
data = {"records": [{"type": record_type, "name": record_name,
"data": record_data, "ttl": record_ttl}]}
resp, body = self.api.client.post("/domains/%s/records" % \
base.getid(domain), body=data)
if resp.status == 202:
return FutureRecord(self, **body)
raise RuntimeError("Did not expect response when creating a DNS record "
"%s" % str(resp.status))
raise RuntimeError("Did not expect response when creating a DNS "
"record %s" % str(resp.status))
def create_from_list(self, list):
return [self.resource_class(self, res) for res in list]
@ -143,4 +144,3 @@ class RecordsManager(base.ManagerWithFind):
else:
raise RuntimeError("Next href had multiple offset params!")
return (list, next_offset)