database support for quotas
This commit is contained in:
@@ -32,6 +32,7 @@ from twisted.internet import defer
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import quota
|
||||
from nova import rpc
|
||||
from nova import utils
|
||||
from nova.auth import rbac
|
||||
@@ -44,6 +45,11 @@ FLAGS = flags.FLAGS
|
||||
flags.DECLARE('storage_availability_zone', 'nova.volume.manager')
|
||||
|
||||
|
||||
class QuotaError(exception.ApiError):
|
||||
"""Quota Exceeeded"""
|
||||
pass
|
||||
|
||||
|
||||
def _gen_key(user_id, key_name):
|
||||
""" Tuck this into AuthManager """
|
||||
try:
|
||||
@@ -276,6 +282,14 @@ class CloudController(object):
|
||||
|
||||
@rbac.allow('projectmanager', 'sysadmin')
|
||||
def create_volume(self, context, size, **kwargs):
|
||||
# check quota
|
||||
size = int(size)
|
||||
if quota.allowed_volumes(context, 1, size) < 1:
|
||||
logging.warn("Quota exceeeded for %s, tried to create %sG volume",
|
||||
context.project.id, size)
|
||||
raise QuotaError("Volume quota exceeded. You cannot "
|
||||
"create a volume of size %s" %
|
||||
size)
|
||||
vol = {}
|
||||
vol['size'] = size
|
||||
vol['user_id'] = context.user.id
|
||||
@@ -435,6 +449,12 @@ class CloudController(object):
|
||||
@rbac.allow('netadmin')
|
||||
@defer.inlineCallbacks
|
||||
def allocate_address(self, context, **kwargs):
|
||||
# check quota
|
||||
if quota.allowed_floating_ips(context, 1) < 1:
|
||||
logging.warn("Quota exceeeded for %s, tried to allocate address",
|
||||
context.project.id)
|
||||
raise QuotaError("Address quota exceeded. You cannot "
|
||||
"allocate any more addresses")
|
||||
network_topic = yield self._get_network_topic(context)
|
||||
public_ip = yield rpc.call(network_topic,
|
||||
{"method": "allocate_floating_ip",
|
||||
@@ -487,14 +507,30 @@ class CloudController(object):
|
||||
host = network_ref['host']
|
||||
if not host:
|
||||
host = yield rpc.call(FLAGS.network_topic,
|
||||
{"method": "set_network_host",
|
||||
"args": {"context": None,
|
||||
"project_id": context.project.id}})
|
||||
{"method": "set_network_host",
|
||||
"args": {"context": None,
|
||||
"project_id": context.project.id}})
|
||||
defer.returnValue(db.queue_get_for(context, FLAGS.network_topic, host))
|
||||
|
||||
@rbac.allow('projectmanager', 'sysadmin')
|
||||
@defer.inlineCallbacks
|
||||
def run_instances(self, context, **kwargs):
|
||||
instance_type = kwargs.get('instance_type', 'm1.small')
|
||||
if instance_type not in INSTANCE_TYPES:
|
||||
raise exception.ApiError("Unknown instance type: %s",
|
||||
instance_type)
|
||||
# check quota
|
||||
max_instances = int(kwargs.get('max_count', 1))
|
||||
min_instances = int(kwargs.get('min_count', max_instances))
|
||||
num_instances = quota.allowed_instances(context,
|
||||
max_instances,
|
||||
instance_type)
|
||||
if num_instances < min_instances:
|
||||
logging.warn("Quota exceeeded for %s, tried to run %s instances",
|
||||
context.project.id, min_instances)
|
||||
raise QuotaError("Instance quota exceeded. You can only "
|
||||
"run %s more instances of this type." %
|
||||
num_instances)
|
||||
# make sure user can access the image
|
||||
# vpn image is private so it doesn't show up on lists
|
||||
vpn = kwargs['image_id'] == FLAGS.vpn_image_id
|
||||
@@ -516,7 +552,7 @@ class CloudController(object):
|
||||
images.get(context, kernel_id)
|
||||
images.get(context, ramdisk_id)
|
||||
|
||||
logging.debug("Going to run instances...")
|
||||
logging.debug("Going to run %s instances...", num_instances)
|
||||
launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
|
||||
key_data = None
|
||||
if kwargs.has_key('key_name'):
|
||||
@@ -540,10 +576,15 @@ class CloudController(object):
|
||||
base_options['user_id'] = context.user.id
|
||||
base_options['project_id'] = context.project.id
|
||||
base_options['user_data'] = kwargs.get('user_data', '')
|
||||
base_options['instance_type'] = kwargs.get('instance_type', 'm1.small')
|
||||
base_options['security_group'] = security_group
|
||||
base_options['instance_type'] = instance_type
|
||||
|
||||
for num in range(int(kwargs['max_count'])):
|
||||
type_data = INSTANCE_TYPES['instance_type']
|
||||
base_options['memory_mb'] = type_data['memory_mb']
|
||||
base_options['vcpus'] = type_data['vcpus']
|
||||
base_options['local_gb'] = type_data['local_gb']
|
||||
|
||||
for num in range():
|
||||
inst_id = db.instance_create(context, base_options)
|
||||
|
||||
inst = {}
|
||||
|
||||
@@ -50,6 +50,7 @@ class ComputeTestCase(test.TrialTestCase):
|
||||
def tearDown(self): # pylint: disable-msg=C0103
|
||||
self.manager.delete_user(self.user)
|
||||
self.manager.delete_project(self.project)
|
||||
super(ComputeTestCase, self).tearDown()
|
||||
|
||||
def _create_instance(self):
|
||||
"""Create a test instance"""
|
||||
|
||||
@@ -58,6 +58,7 @@ from nova.tests.flags_unittest import *
|
||||
from nova.tests.network_unittest import *
|
||||
from nova.tests.objectstore_unittest import *
|
||||
from nova.tests.process_unittest import *
|
||||
from nova.tests.quota_unittest import *
|
||||
from nova.tests.rpc_unittest import *
|
||||
from nova.tests.service_unittest import *
|
||||
from nova.tests.validator_unittest import *
|
||||
|
||||
Reference in New Issue
Block a user