summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Still <mikal@stillhq.com>2013-03-05 05:53:43 +1100
committerMichael Still <mikal@stillhq.com>2013-03-15 03:42:48 +1100
commit99429214d4ddb5bdc7de185693b8a53ad50df3c6 (patch)
treef56596c39ac3353d4c41bd8838a38658de82a6b1
parent9df61c0b06dd81f34d97fbc02030f92928e21a78 (diff)
downloadnova-99429214d4ddb5bdc7de185693b8a53ad50df3c6.tar.gz
nova-99429214d4ddb5bdc7de185693b8a53ad50df3c6.tar.xz
nova-99429214d4ddb5bdc7de185693b8a53ad50df3c6.zip
Add quotas for fixed ips.
DocImpact: there is now a default quota of 10 fixed ips per tenant. This will need to be adjusted by deployers if that number does not meet their needs. Resolves bug 1125468. Change-Id: Iffa19583340f80cb2a13ba5fce31f7ff724a52d6
-rw-r--r--doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json1
-rw-r--r--doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml1
-rw-r--r--doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json1
-rw-r--r--doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml1
-rw-r--r--doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json3
-rw-r--r--doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml3
-rw-r--r--doc/api_samples/os-quota-sets/quotas-show-get-resp.json3
-rw-r--r--doc/api_samples/os-quota-sets/quotas-show-get-resp.xml3
-rw-r--r--doc/api_samples/os-quota-sets/quotas-update-post-resp.json3
-rw-r--r--doc/api_samples/os-quota-sets/quotas-update-post-resp.xml3
-rw-r--r--nova/db/api.py6
-rw-r--r--nova/db/sqlalchemy/api.py12
-rw-r--r--nova/exception.py4
-rw-r--r--nova/network/manager.py95
-rw-r--r--nova/quota.py10
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_quota_classes.py23
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_quotas.py27
-rw-r--r--nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.json.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.xml.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.json.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.xml.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.json.tpl1
-rw-r--r--nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.xml.tpl1
-rw-r--r--nova/tests/network/test_manager.py17
-rw-r--r--nova/tests/test_quota.py24
31 files changed, 198 insertions, 54 deletions
diff --git a/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json b/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json
index e4d0a5b47..e5748a4cd 100644
--- a/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json
+++ b/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json
@@ -1,6 +1,7 @@
{
"quota_class_set": {
"cores": 20,
+ "fixed_ips": 10,
"floating_ips": 10,
"id": "test_class",
"injected_file_content_bytes": 10240,
diff --git a/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml b/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml
index 74532bc98..8e7444634 100644
--- a/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml
+++ b/doc/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml
@@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<quota_class_set id="test_class">
<cores>20</cores>
+ <fixed_ips>10</fixed_ips>
<floating_ips>10</floating_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
diff --git a/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json b/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json
index 99a11f4ff..6325bb562 100644
--- a/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json
+++ b/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json
@@ -1,6 +1,7 @@
{
"quota_class_set": {
"cores": 50,
+ "fixed_ips": 10,
"floating_ips": 10,
"injected_file_content_bytes": 10240,
"injected_file_path_bytes": 255,
diff --git a/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml b/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml
index 44c658a41..26a29fc23 100644
--- a/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml
+++ b/doc/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml
@@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<quota_class_set>
<cores>50</cores>
+ <fixed_ips>10</fixed_ips>
<floating_ips>10</floating_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
diff --git a/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json b/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json
index ee1f6a397..efc35cf00 100644
--- a/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json
+++ b/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json
@@ -1,6 +1,7 @@
{
"quota_set": {
"cores": 20,
+ "fixed_ips": 10,
"floating_ips": 10,
"id": "fake_tenant",
"injected_file_content_bytes": 10240,
@@ -13,4 +14,4 @@
"security_group_rules": 20,
"security_groups": 10
}
-}
+} \ No newline at end of file
diff --git a/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml b/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml
index 6a39c8506..dd4c6d66d 100644
--- a/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml
+++ b/doc/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml
@@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<quota_set id="fake_tenant">
<cores>20</cores>
+ <fixed_ips>10</fixed_ips>
<floating_ips>10</floating_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
@@ -11,4 +12,4 @@
<ram>51200</ram>
<security_group_rules>20</security_group_rules>
<security_groups>10</security_groups>
-</quota_set>
+</quota_set> \ No newline at end of file
diff --git a/doc/api_samples/os-quota-sets/quotas-show-get-resp.json b/doc/api_samples/os-quota-sets/quotas-show-get-resp.json
index ee1f6a397..efc35cf00 100644
--- a/doc/api_samples/os-quota-sets/quotas-show-get-resp.json
+++ b/doc/api_samples/os-quota-sets/quotas-show-get-resp.json
@@ -1,6 +1,7 @@
{
"quota_set": {
"cores": 20,
+ "fixed_ips": 10,
"floating_ips": 10,
"id": "fake_tenant",
"injected_file_content_bytes": 10240,
@@ -13,4 +14,4 @@
"security_group_rules": 20,
"security_groups": 10
}
-}
+} \ No newline at end of file
diff --git a/doc/api_samples/os-quota-sets/quotas-show-get-resp.xml b/doc/api_samples/os-quota-sets/quotas-show-get-resp.xml
index 6a39c8506..dd4c6d66d 100644
--- a/doc/api_samples/os-quota-sets/quotas-show-get-resp.xml
+++ b/doc/api_samples/os-quota-sets/quotas-show-get-resp.xml
@@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<quota_set id="fake_tenant">
<cores>20</cores>
+ <fixed_ips>10</fixed_ips>
<floating_ips>10</floating_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
@@ -11,4 +12,4 @@
<ram>51200</ram>
<security_group_rules>20</security_group_rules>
<security_groups>10</security_groups>
-</quota_set>
+</quota_set> \ No newline at end of file
diff --git a/doc/api_samples/os-quota-sets/quotas-update-post-resp.json b/doc/api_samples/os-quota-sets/quotas-update-post-resp.json
index c16dc6bb5..14324e365 100644
--- a/doc/api_samples/os-quota-sets/quotas-update-post-resp.json
+++ b/doc/api_samples/os-quota-sets/quotas-update-post-resp.json
@@ -1,6 +1,7 @@
{
"quota_set": {
"cores": 20,
+ "fixed_ips": 10,
"floating_ips": 10,
"injected_file_content_bytes": 10240,
"injected_file_path_bytes": 255,
@@ -12,4 +13,4 @@
"security_group_rules": 20,
"security_groups": 45
}
-}
+} \ No newline at end of file
diff --git a/doc/api_samples/os-quota-sets/quotas-update-post-resp.xml b/doc/api_samples/os-quota-sets/quotas-update-post-resp.xml
index 126c3fced..5e6bb893e 100644
--- a/doc/api_samples/os-quota-sets/quotas-update-post-resp.xml
+++ b/doc/api_samples/os-quota-sets/quotas-update-post-resp.xml
@@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<quota_set>
<cores>20</cores>
+ <fixed_ips>10</fixed_ips>
<floating_ips>10</floating_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
@@ -11,4 +12,4 @@
<ram>51200</ram>
<security_group_rules>20</security_group_rules>
<security_groups>45</security_groups>
-</quota_set>
+</quota_set> \ No newline at end of file
diff --git a/nova/db/api.py b/nova/db/api.py
index eac31bee5..ae7b913cf 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -510,6 +510,12 @@ def fixed_ip_update(context, address, values):
"""Create a fixed ip from the values dictionary."""
return IMPL.fixed_ip_update(context, address, values)
+
+def fixed_ip_count_by_project(context, project_id, session=None):
+ """Count fixed ips used by project."""
+ return IMPL.fixed_ip_count_by_project(context, project_id,
+ session=session)
+
####################
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 68657ffb4..bc88e19a1 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -1245,6 +1245,18 @@ def fixed_ip_update(context, address, values):
fixed_ip_ref.save(session=session)
+@require_context
+def fixed_ip_count_by_project(context, project_id, session=None):
+ nova.context.authorize_project_context(context, project_id)
+ return model_query(context, models.FixedIp.id,
+ base_model=models.FixedIp, read_deleted="no",
+ session=session).\
+ join((models.Instance,
+ models.Instance.uuid == models.FixedIp.instance_uuid)).\
+ filter(models.Instance.uuid == project_id).\
+ count()
+
+
###################
diff --git a/nova/exception.py b/nova/exception.py
index 046df24c9..eb2b3b3c1 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -1008,6 +1008,10 @@ class FloatingIpLimitExceeded(QuotaError):
message = _("Maximum number of floating ips exceeded")
+class FixedIpLimitExceeded(QuotaError):
+ message = _("Maximum number of fixed ips exceeded")
+
+
class MetadataLimitExceeded(QuotaError):
message = _("Maximum number of metadata items exceeds %(allowed)d")
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 63270a136..9d7bb4d04 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -69,11 +69,14 @@ from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common import timeutils
from nova.openstack.common import uuidutils
+from nova import quota
from nova import servicegroup
from nova import utils
LOG = logging.getLogger(__name__)
+QUOTAS = quota.QUOTAS
+
network_opts = [
cfg.StrOpt('flat_network_bridge',
@@ -823,47 +826,69 @@ class NetworkManager(manager.Manager):
# network_get_by_compute_host
address = None
- if network['cidr']:
- address = kwargs.get('address', None)
- if address:
- address = self.db.fixed_ip_associate(context,
- address,
- instance_id,
- network['id'])
- else:
- address = self.db.fixed_ip_associate_pool(context.elevated(),
- network['id'],
- instance_id)
- self._do_trigger_security_group_members_refresh_for_instance(
- instance_id)
- self._do_trigger_security_group_handler(
- 'instance_add_security_group', instance_id)
- get_vif = self.db.virtual_interface_get_by_instance_and_network
- vif = get_vif(context, instance_id, network['id'])
- values = {'allocated': True,
- 'virtual_interface_id': vif['id']}
- self.db.fixed_ip_update(context, address, values)
+ # Check the quota; can't put this in the API because we get
+ # called into from other places
+ try:
+ reservations = QUOTAS.reserve(context, fixed_ips=1)
+ except exception.OverQuota:
+ pid = context.project_id
+ LOG.warn(_("Quota exceeded for %(pid)s, tried to allocate "
+ "fixed IP") % locals())
+ raise exception.FixedIpLimitExceeded()
- # NOTE(vish) This db query could be removed if we pass az and name
- # (or the whole instance object).
- instance = self.db.instance_get_by_uuid(context, instance_id)
- name = instance['display_name']
+ try:
+ if network['cidr']:
+ address = kwargs.get('address', None)
+ if address:
+ address = self.db.fixed_ip_associate(context,
+ address,
+ instance_id,
+ network['id'])
+ else:
+ address = self.db.fixed_ip_associate_pool(
+ context.elevated(), network['id'], instance_id)
+ self._do_trigger_security_group_members_refresh_for_instance(
+ instance_id)
+ self._do_trigger_security_group_handler(
+ 'instance_add_security_group', instance_id)
+ get_vif = self.db.virtual_interface_get_by_instance_and_network
+ vif = get_vif(context, instance_id, network['id'])
+ values = {'allocated': True,
+ 'virtual_interface_id': vif['id']}
+ self.db.fixed_ip_update(context, address, values)
+
+ # NOTE(vish) This db query could be removed if we pass az and name
+ # (or the whole instance object).
+ instance = self.db.instance_get_by_uuid(context, instance_id)
+ name = instance['display_name']
- if self._validate_instance_zone_for_dns_domain(context, instance):
- self.instance_dns_manager.create_entry(name, address,
- "A",
- self.instance_dns_domain)
- self.instance_dns_manager.create_entry(instance_id, address,
- "A",
- self.instance_dns_domain)
- self._setup_network_on_host(context, network)
- return address
+ if self._validate_instance_zone_for_dns_domain(context, instance):
+ self.instance_dns_manager.create_entry(
+ name, address, "A", self.instance_dns_domain)
+ self.instance_dns_manager.create_entry(
+ instance_id, address, "A", self.instance_dns_domain)
+ self._setup_network_on_host(context, network)
+
+ QUOTAS.commit(context, reservations)
+ return address
+
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ QUOTAS.rollback(context, reservations)
def deallocate_fixed_ip(self, context, address, host=None, teardown=True):
"""Returns a fixed ip to the pool."""
fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
instance_uuid = fixed_ip_ref['instance_uuid']
vif_id = fixed_ip_ref['virtual_interface_id']
+
+ try:
+ reservations = QUOTAS.reserve(context, fixed_ips=-1)
+ except Exception:
+ reservations = None
+ LOG.exception(_("Failed to update usages deallocating "
+ "fixed IP"))
+
self._do_trigger_security_group_members_refresh_for_instance(
instance_uuid)
self._do_trigger_security_group_handler(
@@ -912,6 +937,10 @@ class NetworkManager(manager.Manager):
self._teardown_network_on_host(context, network)
+ # Commit the reservations
+ if reservations:
+ QUOTAS.commit(context, reservations)
+
def lease_fixed_ip(self, context, address):
"""Called by dhcp-bridge when ip is leased."""
LOG.debug(_('Leased IP |%(address)s|'), locals(), context=context)
diff --git a/nova/quota.py b/nova/quota.py
index d8353bbc2..3903a6add 100644
--- a/nova/quota.py
+++ b/nova/quota.py
@@ -43,6 +43,10 @@ quota_opts = [
cfg.IntOpt('quota_floating_ips',
default=10,
help='number of floating ips allowed per project'),
+ cfg.IntOpt('quota_fixed_ips',
+ default=10,
+ help=('number of fixed ips allowed per project (this should be '
+ 'at least the number of instances allowed)')),
cfg.IntOpt('quota_metadata_items',
default=128,
help='number of metadata items allowed per instance'),
@@ -1062,6 +1066,11 @@ def _sync_floating_ips(context, project_id, session):
context, project_id, session=session))
+def _sync_fixed_ips(context, project_id, session):
+ return dict(fixed_ips=db.fixed_ip_count_by_project(
+ context, project_id, session=session))
+
+
def _sync_security_groups(context, project_id, session):
return dict(security_groups=db.security_group_count_by_project(
context, project_id, session=session))
@@ -1076,6 +1085,7 @@ resources = [
ReservableResource('ram', _sync_instances, 'quota_ram'),
ReservableResource('floating_ips', _sync_floating_ips,
'quota_floating_ips'),
+ ReservableResource('fixed_ips', _sync_fixed_ips, 'quota_fixed_ips'),
AbsoluteResource('metadata_items', 'quota_metadata_items'),
AbsoluteResource('injected_files', 'quota_injected_files'),
AbsoluteResource('injected_file_content_bytes',
diff --git a/nova/tests/api/openstack/compute/contrib/test_quota_classes.py b/nova/tests/api/openstack/compute/contrib/test_quota_classes.py
index 7b0b62180..8286661a0 100644
--- a/nova/tests/api/openstack/compute/contrib/test_quota_classes.py
+++ b/nova/tests/api/openstack/compute/contrib/test_quota_classes.py
@@ -24,11 +24,13 @@ from nova.tests.api.openstack import fakes
def quota_set(class_name):
return {'quota_class_set': {'id': class_name, 'metadata_items': 128,
- 'ram': 51200, 'floating_ips': 10, 'instances': 10,
- 'injected_files': 5, 'cores': 20,
- 'injected_file_content_bytes': 10240, 'security_groups': 10,
- 'security_group_rules': 20, 'key_pairs': 100,
- 'injected_file_path_bytes': 255}}
+ 'ram': 51200, 'floating_ips': 10,
+ 'fixed_ips': 10, 'instances': 10,
+ 'injected_files': 5, 'cores': 20,
+ 'injected_file_content_bytes': 10240,
+ 'security_groups': 10,
+ 'security_group_rules': 20, 'key_pairs': 100,
+ 'injected_file_path_bytes': 255}}
class QuotaClassSetsTest(test.TestCase):
@@ -43,6 +45,7 @@ class QuotaClassSetsTest(test.TestCase):
'cores': 20,
'ram': 51200,
'floating_ips': 10,
+ 'fixed_ips': 10,
'metadata_items': 128,
'injected_files': 5,
'injected_file_path_bytes': 255,
@@ -61,6 +64,7 @@ class QuotaClassSetsTest(test.TestCase):
self.assertEqual(qs['cores'], 20)
self.assertEqual(qs['ram'], 51200)
self.assertEqual(qs['floating_ips'], 10)
+ self.assertEqual(qs['fixed_ips'], 10)
self.assertEqual(qs['metadata_items'], 128)
self.assertEqual(qs['injected_files'], 5)
self.assertEqual(qs['injected_file_path_bytes'], 255)
@@ -86,7 +90,8 @@ class QuotaClassSetsTest(test.TestCase):
def test_quotas_update_as_admin(self):
body = {'quota_class_set': {'instances': 50, 'cores': 50,
'ram': 51200, 'floating_ips': 10,
- 'metadata_items': 128, 'injected_files': 5,
+ 'fixed_ips': 10, 'metadata_items': 128,
+ 'injected_files': 5,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'security_groups': 10,
@@ -103,7 +108,8 @@ class QuotaClassSetsTest(test.TestCase):
def test_quotas_update_as_user(self):
body = {'quota_class_set': {'instances': 50, 'cores': 50,
'ram': 51200, 'floating_ips': 10,
- 'metadata_items': 128, 'injected_files': 5,
+ 'fixed_ips': 10, 'metadata_items': 128,
+ 'injected_files': 5,
'injected_file_content_bytes': 10240,
'security_groups': 10,
'security_group_rules': 20,
@@ -130,6 +136,7 @@ class QuotaTemplateXMLSerializerTest(test.TestCase):
injected_file_content_bytes=20,
ram=50,
floating_ips=60,
+ fixed_ips=10,
instances=70,
injected_files=80,
security_groups=10,
@@ -154,6 +161,7 @@ class QuotaTemplateXMLSerializerTest(test.TestCase):
injected_file_content_bytes='20',
ram='50',
floating_ips='60',
+ fixed_ips='10',
instances='70',
injected_files='80',
security_groups='10',
@@ -167,6 +175,7 @@ class QuotaTemplateXMLSerializerTest(test.TestCase):
'</injected_file_content_bytes>'
'<ram>50</ram>'
'<floating_ips>60</floating_ips>'
+ '<fixed_ips>10</fixed_ips>'
'<instances>70</instances>'
'<injected_files>80</injected_files>'
'<cores>90</cores>'
diff --git a/nova/tests/api/openstack/compute/contrib/test_quotas.py b/nova/tests/api/openstack/compute/contrib/test_quotas.py
index 0616c4628..d66584f57 100644
--- a/nova/tests/api/openstack/compute/contrib/test_quotas.py
+++ b/nova/tests/api/openstack/compute/contrib/test_quotas.py
@@ -26,7 +26,7 @@ from nova.tests.api.openstack import fakes
def quota_set(id):
return {'quota_set': {'id': id, 'metadata_items': 128,
- 'ram': 51200, 'floating_ips': 10,
+ 'ram': 51200, 'floating_ips': 10, 'fixed_ips': 10,
'instances': 10, 'injected_files': 5, 'cores': 20,
'injected_file_content_bytes': 10240,
'security_groups': 10, 'security_group_rules': 20,
@@ -45,6 +45,7 @@ class QuotaSetsTest(test.TestCase):
'cores': 20,
'ram': 51200,
'floating_ips': 10,
+ 'fixed_ips': 10,
'metadata_items': 128,
'injected_files': 5,
'injected_file_path_bytes': 255,
@@ -61,6 +62,7 @@ class QuotaSetsTest(test.TestCase):
self.assertEqual(qs['cores'], 20)
self.assertEqual(qs['ram'], 51200)
self.assertEqual(qs['floating_ips'], 10)
+ self.assertEqual(qs['fixed_ips'], 10)
self.assertEqual(qs['metadata_items'], 128)
self.assertEqual(qs['injected_files'], 5)
self.assertEqual(qs['injected_file_path_bytes'], 255)
@@ -81,6 +83,7 @@ class QuotaSetsTest(test.TestCase):
'cores': 20,
'ram': 51200,
'floating_ips': 10,
+ 'fixed_ips': 10,
'metadata_items': 128,
'injected_files': 5,
'injected_file_path_bytes': 255,
@@ -106,12 +109,13 @@ class QuotaSetsTest(test.TestCase):
def test_quotas_update_as_admin(self):
body = {'quota_set': {'instances': 50, 'cores': 50,
'ram': 51200, 'floating_ips': 10,
- 'metadata_items': 128, 'injected_files': 5,
+ 'fixed_ips': 10, 'metadata_items': 128,
+ 'injected_files': 5,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'security_groups': 10,
'security_group_rules': 20,
- 'key_pairs': 100}}
+ 'key_pairs': 100, 'fixed_ips': 10}}
req = fakes.HTTPRequest.blank('/v2/fake4/os-quota-sets/update_me',
use_admin_context=True)
@@ -122,7 +126,8 @@ class QuotaSetsTest(test.TestCase):
def test_quotas_update_as_user(self):
body = {'quota_set': {'instances': 50, 'cores': 50,
'ram': 51200, 'floating_ips': 10,
- 'metadata_items': 128, 'injected_files': 5,
+ 'fixed_ips': 10, 'metadata_items': 128,
+ 'injected_files': 5,
'injected_file_content_bytes': 10240,
'security_groups': 10,
'security_group_rules': 20,
@@ -134,7 +139,7 @@ class QuotaSetsTest(test.TestCase):
def test_quotas_update_invalid_limit(self):
body = {'quota_set': {'instances': -2, 'cores': -2,
- 'ram': -2, 'floating_ips': -2,
+ 'ram': -2, 'floating_ips': -2, 'fixed_ips': -2,
'metadata_items': -2, 'injected_files': -2,
'injected_file_content_bytes': -2}}
@@ -147,7 +152,8 @@ class QuotaSetsTest(test.TestCase):
expected_resp = {'quota_set': {
'instances': 50, 'cores': 50,
'ram': 51200, 'floating_ips': 10,
- 'metadata_items': 128, 'injected_files': 5,
+ 'fixed_ips': 10, 'metadata_items': 128,
+ 'injected_files': 5,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'security_groups': 10,
@@ -157,7 +163,8 @@ class QuotaSetsTest(test.TestCase):
# when PUT JSON format with empty string for quota
body = {'quota_set': {'instances': 50, 'cores': 50,
'ram': '', 'floating_ips': 10,
- 'metadata_items': 128, 'injected_files': 5,
+ 'fixed_ips': 10, 'metadata_items': 128,
+ 'injected_files': 5,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'security_groups': 10,
@@ -171,7 +178,8 @@ class QuotaSetsTest(test.TestCase):
# when PUT XML format with empty string for quota
body = {'quota_set': {'instances': 50, 'cores': 50,
'ram': {}, 'floating_ips': 10,
- 'metadata_items': 128, 'injected_files': 5,
+ 'fixed_ips': 10, 'metadata_items': 128,
+ 'injected_files': 5,
'injected_file_content_bytes': 10240,
'injected_file_path_bytes': 255,
'security_groups': 10,
@@ -197,6 +205,7 @@ class QuotaXMLSerializerTest(test.TestCase):
injected_file_content_bytes=20,
ram=50,
floating_ips=60,
+ fixed_ips=10,
instances=70,
injected_files=80,
security_groups=10,
@@ -220,6 +229,7 @@ class QuotaXMLSerializerTest(test.TestCase):
injected_file_content_bytes='20',
ram='50',
floating_ips='60',
+ fixed_ips='10',
instances='70',
injected_files='80',
security_groups='10',
@@ -233,6 +243,7 @@ class QuotaXMLSerializerTest(test.TestCase):
'</injected_file_content_bytes>'
'<ram>50</ram>'
'<floating_ips>60</floating_ips>'
+ '<fixed_ips>10</fixed_ips>'
'<instances>70</instances>'
'<injected_files>80</injected_files>'
'<security_groups>10</security_groups>'
diff --git a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json.tpl
index 4b430ad7c..c393ab0c7 100644
--- a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.json.tpl
@@ -2,6 +2,7 @@
"quota_class_set": {
"cores": 20,
"floating_ips": 10,
+ "fixed_ips": 10,
"id": "%(set_id)s",
"injected_file_content_bytes": 10240,
"injected_file_path_bytes": 255,
diff --git a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml.tpl
index 3dffd47f0..8ab8436d7 100644
--- a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-show-get-resp.xml.tpl
@@ -2,6 +2,7 @@
<quota_class_set id="%(set_id)s">
<cores>20</cores>
<floating_ips>10</floating_ips>
+ <fixed_ips>10</fixed_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
<injected_files>5</injected_files>
diff --git a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.json.tpl b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.json.tpl
index f074c829f..3974f65db 100644
--- a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.json.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.json.tpl
@@ -4,6 +4,7 @@
"cores": 50,
"ram": 51200,
"floating_ips": 10,
+ "fixed_ips": 10,
"metadata_items": 128,
"injected_files": 5,
"injected_file_content_bytes": 10240,
diff --git a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.xml.tpl
index d14785482..f27082ab3 100644
--- a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-req.xml.tpl
@@ -2,6 +2,7 @@
<quota_class_set>
<cores>50</cores>
<floating_ips>10</floating_ips>
+ <fixed_ips>10</fixed_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
<injected_files>5</injected_files>
diff --git a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json.tpl
index 99a11f4ff..8d195b924 100644
--- a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.json.tpl
@@ -2,6 +2,7 @@
"quota_class_set": {
"cores": 50,
"floating_ips": 10,
+ "fixed_ips": 10,
"injected_file_content_bytes": 10240,
"injected_file_path_bytes": 255,
"injected_files": 5,
diff --git a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml.tpl
index 44c658a41..5c12a81e7 100644
--- a/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-class-sets/quota-classes-update-post-resp.xml.tpl
@@ -2,6 +2,7 @@
<quota_class_set>
<cores>50</cores>
<floating_ips>10</floating_ips>
+ <fixed_ips>10</fixed_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
<injected_files>5</injected_files>
diff --git a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json.tpl
index ee1f6a397..364a59f7a 100644
--- a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.json.tpl
@@ -2,6 +2,7 @@
"quota_set": {
"cores": 20,
"floating_ips": 10,
+ "fixed_ips": 10,
"id": "fake_tenant",
"injected_file_content_bytes": 10240,
"injected_file_path_bytes": 255,
diff --git a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml.tpl
index 6a39c8506..36e6da544 100644
--- a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-defaults-get-resp.xml.tpl
@@ -2,6 +2,7 @@
<quota_set id="fake_tenant">
<cores>20</cores>
<floating_ips>10</floating_ips>
+ <fixed_ips>10</fixed_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
<injected_files>5</injected_files>
diff --git a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.json.tpl
index ee1f6a397..364a59f7a 100644
--- a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.json.tpl
@@ -2,6 +2,7 @@
"quota_set": {
"cores": 20,
"floating_ips": 10,
+ "fixed_ips": 10,
"id": "fake_tenant",
"injected_file_content_bytes": 10240,
"injected_file_path_bytes": 255,
diff --git a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.xml.tpl
index 6a39c8506..36e6da544 100644
--- a/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-sets/quotas-show-get-resp.xml.tpl
@@ -2,6 +2,7 @@
<quota_set id="fake_tenant">
<cores>20</cores>
<floating_ips>10</floating_ips>
+ <fixed_ips>10</fixed_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
<injected_files>5</injected_files>
diff --git a/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.json.tpl
index c16dc6bb5..43525cfd5 100644
--- a/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.json.tpl
@@ -2,6 +2,7 @@
"quota_set": {
"cores": 20,
"floating_ips": 10,
+ "fixed_ips": 10,
"injected_file_content_bytes": 10240,
"injected_file_path_bytes": 255,
"injected_files": 5,
diff --git a/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.xml.tpl
index 126c3fced..3c411e8e5 100644
--- a/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/os-quota-sets/quotas-update-post-resp.xml.tpl
@@ -2,6 +2,7 @@
<quota_set>
<cores>20</cores>
<floating_ips>10</floating_ips>
+ <fixed_ips>10</fixed_ips>
<injected_file_content_bytes>10240</injected_file_content_bytes>
<injected_file_path_bytes>255</injected_file_path_bytes>
<injected_files>5</injected_files>
diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py
index 6121ae8ac..2fe53968b 100644
--- a/nova/tests/network/test_manager.py
+++ b/nova/tests/network/test_manager.py
@@ -34,6 +34,7 @@ from nova.openstack.common import importutils
from nova.openstack.common import log as logging
from nova.openstack.common import rpc
from nova.openstack.common.rpc import common as rpc_common
+from nova import quota
from nova import test
from nova.tests import fake_ldap
from nova.tests import fake_network
@@ -286,6 +287,7 @@ class FlatNetworkTestCase(test.TestCase):
self.mox.StubOutWithMock(db,
'virtual_interface_get_by_instance_and_network')
self.mox.StubOutWithMock(db, 'fixed_ip_update')
+ self.mox.StubOutWithMock(quota.QUOTAS, 'reserve')
self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
self.mox.StubOutWithMock(self.network, 'get_instance_nw_info')
@@ -306,6 +308,10 @@ class FlatNetworkTestCase(test.TestCase):
db.fixed_ip_update(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg())
+
+ quota.QUOTAS.reserve(mox.IgnoreArg(),
+ fixed_ips=mox.IgnoreArg()).AndReturn(None)
+
db.instance_get_by_uuid(self.context,
mox.IgnoreArg()).AndReturn({'display_name': HOST})
@@ -327,6 +333,7 @@ class FlatNetworkTestCase(test.TestCase):
self.mox.StubOutWithMock(db,
'virtual_interface_get_by_instance_and_network')
self.mox.StubOutWithMock(db, 'fixed_ip_update')
+ self.mox.StubOutWithMock(quota.QUOTAS, 'reserve')
self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
self.mox.StubOutWithMock(self.network, 'get_instance_nw_info')
@@ -347,6 +354,10 @@ class FlatNetworkTestCase(test.TestCase):
db.fixed_ip_update(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg())
+
+ quota.QUOTAS.reserve(mox.IgnoreArg(),
+ fixed_ips=mox.IgnoreArg()).AndReturn(None)
+
db.instance_get_by_uuid(self.context,
mox.IgnoreArg()).AndReturn({'display_name': HOST})
@@ -414,6 +425,7 @@ class FlatNetworkTestCase(test.TestCase):
self.mox.StubOutWithMock(db, 'fixed_ip_update')
self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
self.mox.StubOutWithMock(self.network, 'get_instance_nw_info')
+ self.mox.StubOutWithMock(quota.QUOTAS, 'reserve')
db.fixed_ip_associate_pool(mox.IgnoreArg(),
mox.IgnoreArg(),
@@ -432,6 +444,10 @@ class FlatNetworkTestCase(test.TestCase):
db.fixed_ip_update(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg())
+
+ quota.QUOTAS.reserve(mox.IgnoreArg(),
+ fixed_ips=mox.IgnoreArg()).AndReturn(None)
+
db.instance_get_by_uuid(self.context,
mox.IgnoreArg()).AndReturn({'display_name': HOST})
@@ -531,6 +547,7 @@ class VlanNetworkTestCase(test.TestCase):
db.instance_get_by_uuid(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn({'security_groups':
[{'id': 0}]})
+
db.fixed_ip_associate_pool(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn('192.168.0.1')
diff --git a/nova/tests/test_quota.py b/nova/tests/test_quota.py
index 1ea4eea21..1f422748b 100644
--- a/nova/tests/test_quota.py
+++ b/nova/tests/test_quota.py
@@ -719,6 +719,7 @@ class DbQuotaDriverTestCase(test.TestCase):
quota_cores=20,
quota_ram=50 * 1024,
quota_floating_ips=10,
+ quota_fixed_ips=10,
quota_metadata_items=128,
quota_injected_files=5,
quota_injected_file_content_bytes=10 * 1024,
@@ -745,6 +746,7 @@ class DbQuotaDriverTestCase(test.TestCase):
cores=20,
ram=50 * 1024,
floating_ips=10,
+ fixed_ips=10,
metadata_items=128,
injected_files=5,
injected_file_content_bytes=10 * 1024,
@@ -778,6 +780,7 @@ class DbQuotaDriverTestCase(test.TestCase):
cores=20,
ram=25 * 1024,
floating_ips=10,
+ fixed_ips=10,
metadata_items=64,
injected_files=5,
injected_file_content_bytes=5 * 1024,
@@ -830,6 +833,7 @@ class DbQuotaDriverTestCase(test.TestCase):
self._stub_quota_class_get_all_by_name()
def test_get_project_quotas(self):
+ self.maxDiff = None
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('test_project', 'test_class'),
@@ -861,6 +865,11 @@ class DbQuotaDriverTestCase(test.TestCase):
in_use=2,
reserved=0,
),
+ fixed_ips=dict(
+ limit=10,
+ in_use=0,
+ reserved=0,
+ ),
metadata_items=dict(
limit=64,
in_use=0,
@@ -899,6 +908,7 @@ class DbQuotaDriverTestCase(test.TestCase):
))
def test_get_project_quotas_alt_context_no_class(self):
+ self.maxDiff = None
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('other_project', 'other_class'),
@@ -929,6 +939,11 @@ class DbQuotaDriverTestCase(test.TestCase):
in_use=2,
reserved=0,
),
+ fixed_ips=dict(
+ limit=10,
+ in_use=0,
+ reserved=0,
+ ),
metadata_items=dict(
limit=128,
in_use=0,
@@ -967,6 +982,7 @@ class DbQuotaDriverTestCase(test.TestCase):
))
def test_get_project_quotas_alt_context_with_class(self):
+ self.maxDiff = None
self._stub_get_by_project()
result = self.driver.get_project_quotas(
FakeContext('other_project', 'other_class'),
@@ -998,6 +1014,11 @@ class DbQuotaDriverTestCase(test.TestCase):
in_use=2,
reserved=0,
),
+ fixed_ips=dict(
+ limit=10,
+ in_use=0,
+ reserved=0,
+ ),
metadata_items=dict(
limit=64,
in_use=0,
@@ -1087,6 +1108,9 @@ class DbQuotaDriverTestCase(test.TestCase):
floating_ips=dict(
limit=10,
),
+ fixed_ips=dict(
+ limit=10,
+ ),
metadata_items=dict(
limit=64,
),