summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Hagedorn <mike.hagedorn@hp.com>2015-08-06 15:43:16 -0400
committerMatthias Runge <mrunge@redhat.com>2015-09-28 11:32:56 +0200
commitb8e1ce89041dfe6547e875571eb987dd9eae3a03 (patch)
tree2c0ec7ca85ee941eeaf46bd2eb510d86a8b1ad57
parentb55acddc1590095973f7814eb9d06ea7d5b784f7 (diff)
downloadhorizon-b8e1ce89041dfe6547e875571eb987dd9eae3a03.tar.gz
Neutron Quota Settings Flag Disables Neutron GUI
if OPENSTACK_NEUTRON_NETWORK["enable_quotas"] = False buttons will not appear and exceptions are thrown. This is because a dict is searched for a key ("available") which wont be there if its disabled. This generates a KeyError at runtime. As currently written enable_quatas -> False essentially disables Neutron usage. This is not a desirable outcome. This patch shows Neutron related buttons and ignores the quota settings, which seems more in line with the notion of disabling quotas. Closes-Bug:#1482354 Change-Id: I9485ddeece74d87317c2587498f5f79d4ffdb66e (cherry picked from commit 5ba219acbfddb9b9308a75da361fda915ba61f37)
-rw-r--r--openstack_dashboard/dashboards/project/network_topology/views.py2
-rw-r--r--openstack_dashboard/dashboards/project/networks/tables.py8
-rw-r--r--openstack_dashboard/dashboards/project/networks/tests.py94
-rw-r--r--openstack_dashboard/dashboards/project/routers/tables.py4
-rw-r--r--openstack_dashboard/dashboards/project/routers/tests.py52
-rw-r--r--openstack_dashboard/test/test_data/neutron_data.py14
6 files changed, 141 insertions, 33 deletions
diff --git a/openstack_dashboard/dashboards/project/network_topology/views.py b/openstack_dashboard/dashboards/project/network_topology/views.py
index 23b50b8c5..36327638c 100644
--- a/openstack_dashboard/dashboards/project/network_topology/views.py
+++ b/openstack_dashboard/dashboards/project/network_topology/views.py
@@ -111,7 +111,7 @@ class NetworkTopologyView(views.HorizonTemplateView):
def _quota_exceeded(self, quota):
usages = quotas.tenant_quota_usages(self.request)
- available = usages[quota]['available']
+ available = usages.get(quota, {}).get('available', 1)
return available <= 0
def get_context_data(self, **kwargs):
diff --git a/openstack_dashboard/dashboards/project/networks/tables.py b/openstack_dashboard/dashboards/project/networks/tables.py
index e13e3c452..637d0e9d1 100644
--- a/openstack_dashboard/dashboards/project/networks/tables.py
+++ b/openstack_dashboard/dashboards/project/networks/tables.py
@@ -92,7 +92,9 @@ class CreateNetwork(tables.LinkAction):
def allowed(self, request, datum=None):
usages = quotas.tenant_quota_usages(request)
- if usages['networks']['available'] <= 0:
+ # when Settings.OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False
+ # usages["networks"] is empty
+ if usages.get('networks', {}).get('available', 1) <= 0:
if "disabled" not in self.classes:
self.classes = [c for c in self.classes] + ["disabled"]
self.verbose_name = _("Create Network (Quota exceeded)")
@@ -125,7 +127,9 @@ class CreateSubnet(policy.PolicyTargetMixin, CheckNetworkEditable,
def allowed(self, request, datum=None):
usages = quotas.tenant_quota_usages(request)
- if usages['subnets']['available'] <= 0:
+ # when Settings.OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False
+ # usages["subnets'] is empty
+ if usages.get('subnets', {}).get('available', 1) <= 0:
if 'disabled' not in self.classes:
self.classes = [c for c in self.classes] + ['disabled']
self.verbose_name = _('Add Subnet (Quota exceeded)')
diff --git a/openstack_dashboard/dashboards/project/networks/tests.py b/openstack_dashboard/dashboards/project/networks/tests.py
index c56eebcd8..39bc86496 100644
--- a/openstack_dashboard/dashboards/project/networks/tests.py
+++ b/openstack_dashboard/dashboards/project/networks/tests.py
@@ -29,6 +29,7 @@ from openstack_dashboard.dashboards.project.networks import workflows
from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
+
INDEX_URL = reverse('horizon:project:networks:index')
@@ -125,9 +126,7 @@ class NetworkTests(test.TestCase):
@test.create_stubs({api.neutron: ('network_list',),
quotas: ('tenant_quota_usages',)})
def test_index_network_list_exception(self):
- quota_data = self.quota_usages.first()
- quota_data['networks']['available'] = 5
- quota_data['subnets']['available'] = 5
+ quota_data = self.neutron_quota_usages.first()
api.neutron.network_list(
IsA(http.HttpRequest),
tenant_id=self.tenant.id,
@@ -160,8 +159,7 @@ class NetworkTests(test.TestCase):
self._test_network_detail(mac_learning=True)
def _test_network_detail(self, mac_learning=False):
- quota_data = self.quota_usages.first()
- quota_data['subnets']['available'] = 5
+ quota_data = self.neutron_quota_usages.first()
network_id = self.networks.first().id
api.neutron.network_get(IsA(http.HttpRequest), network_id)\
.AndReturn(self.networks.first())
@@ -235,7 +233,7 @@ class NetworkTests(test.TestCase):
def _test_network_detail_subnet_exception(self, mac_learning=False):
network_id = self.networks.first().id
- quota_data = self.quota_usages.first()
+ quota_data = self.neutron_quota_usages.first()
quota_data['networks']['available'] = 5
quota_data['subnets']['available'] = 5
api.neutron.network_get(IsA(http.HttpRequest), network_id).\
@@ -280,7 +278,7 @@ class NetworkTests(test.TestCase):
def _test_network_detail_port_exception(self, mac_learning=False):
network_id = self.networks.first().id
- quota_data = self.quota_usages.first()
+ quota_data = self.neutron_quota_usages.first()
quota_data['subnets']['available'] = 5
api.neutron.network_get(IsA(http.HttpRequest), network_id).\
AndReturn(self.networks.first())
@@ -1659,9 +1657,41 @@ class NetworkPortTests(test.TestCase):
class NetworkViewTests(test.TestCase):
+ def _test_create_button_shown_when_quota_disabled(
+ self, expected_string):
+ # if quota_data doesnt contain a networks|subnets|routers key or
+ # these keys are empty dicts, its disabled
+ quota_data = self.neutron_quota_usages.first()
+
+ quota_data['networks'].pop('available')
+ quota_data['subnets'].pop('available')
+
+ api.neutron.network_list(
+ IsA(http.HttpRequest),
+ tenant_id=self.tenant.id,
+ shared=False).AndReturn(self.networks.list())
+ api.neutron.network_list(
+ IsA(http.HttpRequest),
+ shared=True).AndReturn([])
+ quotas.tenant_quota_usages(
+ IsA(http.HttpRequest)) \
+ .MultipleTimes().AndReturn(quota_data)
+
+ self.mox.ReplayAll()
+
+ res = self.client.get(INDEX_URL)
+ self.assertTemplateUsed(res, 'project/networks/index.html')
+
+ networks = res.context['networks_table'].data
+ self.assertItemsEqual(networks, self.networks.list())
+ self.assertContains(res, expected_string, True, html=True,
+ msg_prefix="The enabled create button not shown")
+
def _test_create_button_disabled_when_quota_exceeded(
self, expected_string, network_quota=5, subnet_quota=5):
- quota_data = self.quota_usages.first()
+
+ quota_data = self.neutron_quota_usages.first()
+
quota_data['networks']['available'] = network_quota
quota_data['subnets']['available'] = subnet_quota
@@ -1683,8 +1713,7 @@ class NetworkViewTests(test.TestCase):
networks = res.context['networks_table'].data
self.assertItemsEqual(networks, self.networks.list())
-
- self.assertContains(res, expected_string, html=True,
+ self.assertContains(res, expected_string, True, html=True,
msg_prefix="The create button is not disabled")
@test.create_stubs({api.neutron: ('network_list',),
@@ -1700,27 +1729,56 @@ class NetworkViewTests(test.TestCase):
"id='networks__action_create'>" \
"<span class='fa fa-plus'></span>%s</a>" \
% (url, link_name, " ".join(classes), link_name)
-
self._test_create_button_disabled_when_quota_exceeded(expected_string,
- network_quota=0)
+ network_quota=0
+ )
@test.create_stubs({api.neutron: ('network_list',),
quotas: ('tenant_quota_usages',)})
def test_subnet_create_button_disabled_when_quota_exceeded_index(self):
network_id = self.networks.first().id
-
create_link = networks_tables.CreateSubnet()
url = reverse(create_link.get_link_url(), args=[network_id])
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (unicode(create_link.verbose_name),
"Quota exceeded")
- expected_string = "<a href='%s' class='%s disabled' "\
+ expected_string = "<a href='%s' class='%s disabled' " \
+ "id='networks__row_%s__action_subnet'>%s</a>" \
+ % (url, " ".join(classes), network_id, link_name)
+ self._test_create_button_disabled_when_quota_exceeded(expected_string,
+ subnet_quota=0
+ )
+
+ @test.create_stubs({api.neutron: ('network_list',),
+ quotas: ('tenant_quota_usages',)})
+ def test_network_create_button_shown_when_quota_disabled_index(self):
+ # if quota_data doesnt contain a networks["available"] key its disabled
+ create_link = networks_tables.CreateNetwork()
+ url = create_link.get_link_url()
+ classes = (list(create_link.get_default_classes())
+ + list(create_link.classes))
+ link_name = "%s" % (unicode(create_link.verbose_name),)
+ expected_string = "<a href='%s' title='%s' class='%s' "\
+ "id='networks__action_create'>" \
+ "<span class='fa fa-plus'></span>%s</a>" \
+ % (url, link_name, " ".join(classes), link_name)
+ self._test_create_button_shown_when_quota_disabled(expected_string)
+
+ @test.create_stubs({api.neutron: ('network_list',),
+ quotas: ('tenant_quota_usages',)})
+ def test_subnet_create_button_shown_when_quota_disabled_index(self):
+ # if quota_data doesnt contain a subnets["available"] key, its disabled
+ network_id = self.networks.first().id
+ create_link = networks_tables.CreateSubnet()
+ url = reverse(create_link.get_link_url(), args=[network_id])
+ classes = (list(create_link.get_default_classes())
+ + list(create_link.classes))
+ link_name = "%s" % (unicode(create_link.verbose_name),)
+ expected_string = "<a href='%s' class='%s' "\
"id='networks__row_%s__action_subnet'>%s</a>" \
% (url, " ".join(classes), network_id, link_name)
-
- self._test_create_button_disabled_when_quota_exceeded(expected_string,
- subnet_quota=0)
+ self._test_create_button_shown_when_quota_disabled(expected_string)
@test.create_stubs({api.neutron: ('network_get',
'subnet_list',
@@ -1729,7 +1787,7 @@ class NetworkViewTests(test.TestCase):
quotas: ('tenant_quota_usages',)})
def test_subnet_create_button_disabled_when_quota_exceeded_detail(self):
network_id = self.networks.first().id
- quota_data = self.quota_usages.first()
+ quota_data = self.neutron_quota_usages.first()
quota_data['subnets']['available'] = 0
api.neutron.network_get(
diff --git a/openstack_dashboard/dashboards/project/routers/tables.py b/openstack_dashboard/dashboards/project/routers/tables.py
index 3ae157cd4..351abe43d 100644
--- a/openstack_dashboard/dashboards/project/routers/tables.py
+++ b/openstack_dashboard/dashboards/project/routers/tables.py
@@ -90,7 +90,9 @@ class CreateRouter(tables.LinkAction):
def allowed(self, request, datum=None):
usages = quotas.tenant_quota_usages(request)
- if usages['routers']['available'] <= 0:
+ # when Settings.OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False
+ # usages['routers'] is empty
+ if usages.get('routers', {}).get('available', 1) <= 0:
if "disabled" not in self.classes:
self.classes = [c for c in self.classes] + ["disabled"]
self.verbose_name = _("Create Router (Quota exceeded)")
diff --git a/openstack_dashboard/dashboards/project/routers/tests.py b/openstack_dashboard/dashboards/project/routers/tests.py
index 586da2756..95687c080 100644
--- a/openstack_dashboard/dashboards/project/routers/tests.py
+++ b/openstack_dashboard/dashboards/project/routers/tests.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
+import six
from django.core.urlresolvers import reverse
from django import http
@@ -81,8 +82,7 @@ class RouterTests(RouterMixin, test.TestCase):
@test.create_stubs({api.neutron: ('router_list', 'network_list'),
quotas: ('tenant_quota_usages',)})
def test_index(self):
- quota_data = self.quota_usages.first()
- quota_data['routers']['available'] = 5
+ quota_data = self.neutron_quota_usages.first()
api.neutron.router_list(
IsA(http.HttpRequest),
tenant_id=self.tenant.id,
@@ -102,8 +102,7 @@ class RouterTests(RouterMixin, test.TestCase):
@test.create_stubs({api.neutron: ('router_list', 'network_list'),
quotas: ('tenant_quota_usages',)})
def test_index_router_list_exception(self):
- quota_data = self.quota_usages.first()
- quota_data['routers']['available'] = 5
+ quota_data = self.neutron_quota_usages.first()
api.neutron.router_list(
IsA(http.HttpRequest),
tenant_id=self.tenant.id,
@@ -124,8 +123,7 @@ class RouterTests(RouterMixin, test.TestCase):
quotas: ('tenant_quota_usages',)})
def test_set_external_network_empty(self):
router = self.routers.first()
- quota_data = self.quota_usages.first()
- quota_data['routers']['available'] = 5
+ quota_data = self.neutron_quota_usages.first()
api.neutron.router_list(
IsA(http.HttpRequest),
tenant_id=self.tenant.id,
@@ -170,8 +168,7 @@ class RouterTests(RouterMixin, test.TestCase):
quotas: ('tenant_quota_usages',)})
def test_router_delete(self):
router = self.routers.first()
- quota_data = self.quota_usages.first()
- quota_data['routers']['available'] = 5
+ quota_data = self.neutron_quota_usages.first()
api.neutron.router_list(
IsA(http.HttpRequest),
tenant_id=self.tenant.id,
@@ -211,8 +208,7 @@ class RouterTests(RouterMixin, test.TestCase):
def test_router_with_interface_delete(self):
router = self.routers.first()
ports = self.ports.list()
- quota_data = self.quota_usages.first()
- quota_data['routers']['available'] = 5
+ quota_data = self.neutron_quota_usages.first()
api.neutron.router_list(
IsA(http.HttpRequest),
tenant_id=self.tenant.id,
@@ -819,7 +815,7 @@ class RouterViewTests(RouterMixin, test.TestCase):
@test.create_stubs({api.neutron: ('router_list', 'network_list'),
quotas: ('tenant_quota_usages',)})
def test_create_button_disabled_when_quota_exceeded(self):
- quota_data = self.quota_usages.first()
+ quota_data = self.neutron_quota_usages.first()
quota_data['routers']['available'] = 0
api.neutron.router_list(
IsA(http.HttpRequest),
@@ -850,3 +846,37 @@ class RouterViewTests(RouterMixin, test.TestCase):
% (url, link_name, " ".join(classes), link_name)
self.assertContains(res, expected_string, html=True,
msg_prefix="The create button is not disabled")
+
+ @test.create_stubs({api.neutron: ('router_list', 'network_list'),
+ quotas: ('tenant_quota_usages',)})
+ def test_create_button_shown_when_quota_disabled(self):
+ quota_data = self.neutron_quota_usages.first()
+ quota_data['routers'].pop('available')
+ api.neutron.router_list(
+ IsA(http.HttpRequest),
+ tenant_id=self.tenant.id,
+ search_opts=None).AndReturn(self.routers.list())
+ quotas.tenant_quota_usages(
+ IsA(http.HttpRequest)) \
+ .MultipleTimes().AndReturn(quota_data)
+
+ self._mock_external_network_list()
+ self.mox.ReplayAll()
+
+ res = self.client.get(self.INDEX_URL)
+ self.assertTemplateUsed(res, 'project/routers/index.html')
+
+ routers = res.context['Routers_table'].data
+ self.assertItemsEqual(routers, self.routers.list())
+
+ create_link = tables.CreateRouter()
+ url = create_link.get_link_url()
+ classes = (list(create_link.get_default_classes())
+ + list(create_link.classes))
+ link_name = "%s" % (six.text_type(create_link.verbose_name))
+ expected_string = "<a href='%s' title='%s' class='%s' "\
+ "id='Routers__action_create'>" \
+ "<span class='fa fa-plus'></span>%s</a>" \
+ % (url, link_name, " ".join(classes), link_name)
+ self.assertContains(res, expected_string, html=True,
+ msg_prefix="The create button is not displayed")
diff --git a/openstack_dashboard/test/test_data/neutron_data.py b/openstack_dashboard/test/test_data/neutron_data.py
index 0bc646e60..0bea29497 100644
--- a/openstack_dashboard/test/test_data/neutron_data.py
+++ b/openstack_dashboard/test/test_data/neutron_data.py
@@ -21,6 +21,7 @@ from openstack_dashboard.api import lbaas
from openstack_dashboard.api import neutron
from openstack_dashboard.api import vpn
from openstack_dashboard.test.test_data import utils
+from openstack_dashboard.usage import quotas as usage_quotas
def data(TEST):
@@ -40,6 +41,7 @@ def data(TEST):
TEST.members = utils.TestDataContainer()
TEST.monitors = utils.TestDataContainer()
TEST.neutron_quotas = utils.TestDataContainer()
+ TEST.neutron_quota_usages = utils.TestDataContainer()
TEST.net_profiles = utils.TestDataContainer()
TEST.policy_profiles = utils.TestDataContainer()
TEST.network_profile_binding = utils.TestDataContainer()
@@ -652,6 +654,18 @@ def data(TEST):
}
TEST.neutron_quotas.add(base.QuotaSet(quota_data))
+ # Quota Usages
+ quota_usage_data = {'networks': {'used': 0, 'quota': 5},
+ 'subnets': {'used': 0, 'quota': 5},
+ 'routers': {'used': 0, 'quota': 5},
+ }
+ quota_usage = usage_quotas.QuotaUsage()
+ for k, v in quota_usage_data.items():
+ quota_usage.add_quota(base.Quota(k, v['quota']))
+ quota_usage.tally(k, v['used'])
+
+ TEST.neutron_quota_usages.add(quota_usage)
+
# Extensions.
extension_1 = {"name": "security-group",
"alias": "security-group",