From 1ed6c85a86bf5935f31710c8fd713a3987ea14e0 Mon Sep 17 00:00:00 2001 From: Victoria Martinez de la Cruz Date: Mon, 30 Jul 2018 23:38:48 -0300 Subject: [PATCH] Fix quotas retrieval for shares and snapshots tables After refactoring manila-ui plugin to adapt to the tabbed quotas interface in horizon, we stopped accesing the usages data structure which (in horizon side) carries quotas information. In this patch set we perform quotas control by querying manilaclient directly. Change-Id: I2896d54fde0d5e3975afbb7274faadf2a1a81d7c Closes-Bug: #1783232 Co-Authored-By: Tom Barron --- .../project/share_snapshots/tables.py | 11 +++-- manila_ui/dashboards/project/shares/tables.py | 11 +++-- .../tests/dashboards/admin/shares/tests.py | 4 -- .../project/share_snapshots/test_tables.py | 35 +++++++++++---- .../tests/dashboards/project/shares/tests.py | 42 ++++-------------- .../tests/dashboards/project/test_data.py | 43 ++++++++----------- ...and-snapshots-tables-63a1fc877029eac8.yaml | 3 ++ 7 files changed, 73 insertions(+), 76 deletions(-) create mode 100644 releasenotes/notes/bug-1783232-fix-quotas-retrieval-for-shares-and-snapshots-tables-63a1fc877029eac8.yaml diff --git a/manila_ui/dashboards/project/share_snapshots/tables.py b/manila_ui/dashboards/project/share_snapshots/tables.py index a609e3f5..287224b4 100644 --- a/manila_ui/dashboards/project/share_snapshots/tables.py +++ b/manila_ui/dashboards/project/share_snapshots/tables.py @@ -21,7 +21,6 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy from horizon import exceptions from horizon import tables -from openstack_dashboard.usage import quotas from manila_ui.api import manila @@ -57,8 +56,13 @@ class CreateShareSnapshot(tables.LinkAction): return {"project_id": project_id} def allowed(self, request, share=None): - usages = quotas.tenant_quota_usages(request) - if usages['snapshots']['available'] <= 0: + usages = manila.tenant_absolute_limits(request) + snapshots_allowed = (usages['maxTotalShareSnapshots'] > + usages['totalShareSnapshotsUsed'] and + usages['maxTotalSnapshotGigabytes'] > + usages['totalSnapshotGigabytesUsed']) + + if not snapshots_allowed: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = string_concat( @@ -145,6 +149,7 @@ class EditShareSnapshot(tables.LinkAction): class ShareSnapshotShareNameColumn(tables.Column): + def get_link_url(self, snapshot): return reverse(self.link, args=(snapshot.share_id,)) diff --git a/manila_ui/dashboards/project/shares/tables.py b/manila_ui/dashboards/project/shares/tables.py index e75a6225..b3b571ed 100644 --- a/manila_ui/dashboards/project/shares/tables.py +++ b/manila_ui/dashboards/project/shares/tables.py @@ -21,7 +21,6 @@ from django.utils.translation import ungettext_lazy from horizon import exceptions from horizon import messages from horizon import tables -from openstack_dashboard.usage import quotas from manila_ui.api import manila from manila_ui.dashboards.project.share_snapshots import tables as ss_tables @@ -87,8 +86,13 @@ class CreateShare(tables.LinkAction): policy_rules = (("share", "share:create"),) def allowed(self, request, share=None): - usages = quotas.tenant_quota_usages(request) - if usages['shares']['available'] <= 0: + usages = manila.tenant_absolute_limits(request) + shares_allowed = (usages['maxTotalShares'] > + usages['totalSharesUsed'] and + usages['maxTotalShareGigabytes'] > + usages['totalShareGigabytesUsed']) + + if not shares_allowed: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = string_concat(self.verbose_name, ' ', @@ -97,6 +101,7 @@ class CreateShare(tables.LinkAction): self.verbose_name = _("Create Share") classes = [c for c in self.classes if c != "disabled"] self.classes = classes + return True diff --git a/manila_ui/tests/dashboards/admin/shares/tests.py b/manila_ui/tests/dashboards/admin/shares/tests.py index f834c66d..103ff04b 100644 --- a/manila_ui/tests/dashboards/admin/shares/tests.py +++ b/manila_ui/tests/dashboards/admin/shares/tests.py @@ -18,7 +18,6 @@ from django.urls import reverse import mock from openstack_dashboard.api import keystone as api_keystone from openstack_dashboard.api import neutron as api_neutron -from openstack_dashboard.usage import quotas from manila_ui.api import manila as api_manila from manila_ui.dashboards.admin import utils @@ -53,9 +52,6 @@ class SharesTests(test.BaseAdminViewTests): api_manila, "share_snapshot_list", mock.Mock(return_value=snaps)) self.mock_object( api_neutron, "is_service_enabled", mock.Mock(return_value=[True])) - self.mock_object( - quotas, "tenant_quota_usages", - mock.Mock(return_value=test_data.quota_usage)) res = self.client.get(INDEX_URL) diff --git a/manila_ui/tests/dashboards/project/share_snapshots/test_tables.py b/manila_ui/tests/dashboards/project/share_snapshots/test_tables.py index a82ab47c..25780ff4 100644 --- a/manila_ui/tests/dashboards/project/share_snapshots/test_tables.py +++ b/manila_ui/tests/dashboards/project/share_snapshots/test_tables.py @@ -17,7 +17,9 @@ import ddt from django.core.handlers import wsgi import mock +from manila_ui.api import manila as api_manila from manila_ui.dashboards.project.share_snapshots import tables +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as base @@ -36,23 +38,38 @@ class CreateSnapshotTests(base.APITestCase): return type("Share", (object, ), kwargs)() @ddt.data(True, False) - @mock.patch('openstack_dashboard.usage.quotas.tenant_quota_usages') - def test_allowed_with_snapshot_support_attr(self, snapshot_support, - mock_quota_usages): - mock_quota_usages.return_value = {'snapshots': {'available': 1}} + def test_allowed_with_snapshot_support_attr(self, snapshot_support): + self.mock_object( + api_manila, "tenant_absolute_limits", + mock.Mock(return_value=test_data.limits)) + share = self._get_fake_share(snapshot_support=snapshot_support) result = self.create_snapshot.allowed(self.request, share) self.assertEqual(snapshot_support, result) - mock_quota_usages.assert_called_once_with(self.request) - @mock.patch('openstack_dashboard.usage.quotas.tenant_quota_usages') - def test_allowed_no_snapshot_support_attr(self, mock_quota_usages): - mock_quota_usages.return_value = {'snapshots': {'available': 1}} + def test_allowed_no_snapshot_support_attr(self): + self.mock_object( + api_manila, "tenant_absolute_limits", + mock.Mock(return_value=test_data.limits)) share = self._get_fake_share() result = self.create_snapshot.allowed(self.request, share) + self.assertNotIn('disabled', self.create_snapshot.classes) + + self.assertTrue(result) + + def test_allowed_no_snapshot_support_attr_no_quota(self): + self.mock_object( + api_manila, "tenant_absolute_limits", + mock.Mock(return_value=test_data.limits_negative)) + + share = self._get_fake_share() + + result = self.create_snapshot.allowed(self.request, share) + + self.assertIn('disabled', self.create_snapshot.classes) + self.assertTrue(result) - mock_quota_usages.assert_called_once_with(self.request) diff --git a/manila_ui/tests/dashboards/project/shares/tests.py b/manila_ui/tests/dashboards/project/shares/tests.py index eacb8b30..5b4f8507 100644 --- a/manila_ui/tests/dashboards/project/shares/tests.py +++ b/manila_ui/tests/dashboards/project/shares/tests.py @@ -18,7 +18,6 @@ from django.urls import reverse from horizon import messages as horizon_messages import mock from openstack_dashboard.api import neutron -from openstack_dashboard.usage import quotas import six from manila_ui.api import manila as api_manila @@ -55,6 +54,9 @@ class ShareViewTests(test.APITestCase): self.mock_object(horizon_messages, "success") FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'} self.request = wsgi.WSGIRequest(FAKE_ENVIRON) + self.mock_object( + api_manila, "tenant_absolute_limits", + mock.Mock(return_value=test_data.limits)) def test_index(self): snaps = [test_data.snapshot, test_data.snapshot_mount_support] @@ -70,10 +72,10 @@ class ShareViewTests(test.APITestCase): api_manila, "share_network_list", mock.Mock(return_value=share_networks)) self.mock_object( - neutron, "is_service_enabled", mock.Mock(return_value=[True])) + api_manila, "tenant_absolute_limits", + mock.Mock(return_value=test_data.limits)) self.mock_object( - quotas, "tenant_quota_usages", - mock.Mock(return_value=test_data.quota_usage)) + neutron, "is_service_enabled", mock.Mock(return_value=[True])) res = self.client.get(INDEX_URL) @@ -83,6 +85,7 @@ class ShareViewTests(test.APITestCase): mock.ANY, detailed=True) api_manila.share_list.assert_called_with(mock.ANY) api_manila.share_network_list.assert_called_with(mock.ANY) + api_manila.tenant_absolute_limits.assert_called_with(mock.ANY) @mock.patch.object(api_manila, 'availability_zone_list') def test_create_share(self, az_list): @@ -354,14 +357,7 @@ class ShareViewTests(test.APITestCase): def test_extend_share_get(self): share = test_data.share - usage_limit = { - 'maxTotalShareGigabytes': 250, - 'totalShareGigabytesUsed': 20, - } url = reverse('horizon:project:shares:extend', args=[share.id]) - self.mock_object( - api_manila, "tenant_absolute_limits", - mock.Mock(return_value=usage_limit)) self.mock_object( neutron, "is_service_enabled", mock.Mock(return_value=[True])) @@ -373,15 +369,8 @@ class ShareViewTests(test.APITestCase): def test_extend_share_open_form_successfully(self): self.share.size = 5 - usage_limit = { - 'maxTotalShareGigabytes': self.share.size + 50, - 'totalShareGigabytesUsed': self.share.size, - } url = reverse('horizon:project:shares:extend', args=[self.share.id]) self.mock_object(api_manila, "share_extend") - self.mock_object( - api_manila, 'tenant_absolute_limits', - mock.Mock(return_value=usage_limit)) response = self.client.get(url) @@ -392,15 +381,8 @@ class ShareViewTests(test.APITestCase): api_manila.tenant_absolute_limits.assert_called_once_with(mock.ANY) def test_extend_share_get_with_api_exception(self): - usage_limit = { - 'maxTotalShareGigabytes': self.share.size + 50, - 'totalShareGigabytesUsed': self.share.size, - } url = reverse('horizon:project:shares:extend', args=[self.share.id]) self.mock_object(api_manila, "share_extend") - self.mock_object( - api_manila, 'tenant_absolute_limits', - mock.Mock(return_value=usage_limit)) self.mock_object( api_manila, "share_get", mock.Mock(return_value=Exception('Fake share NotFound exception'))) @@ -421,6 +403,7 @@ class ShareViewTests(test.APITestCase): usage_limit = { 'maxTotalShareGigabytes': self.share.size + 50, 'totalShareGigabytesUsed': self.share.size, + } url = reverse('horizon:project:shares:extend', args=[self.share.id]) self.mock_object(api_manila, "share_extend") @@ -443,11 +426,11 @@ class ShareViewTests(test.APITestCase): def test_extend_share_post_with_invalid_value(self, new_size): self.share.size = 5 form_data = {'new_size': new_size} + url = reverse('horizon:project:shares:extend', args=[self.share.id]) usage_limit = { 'maxTotalShareGigabytes': self.share.size + 50, 'totalShareGigabytesUsed': self.share.size, } - url = reverse('horizon:project:shares:extend', args=[self.share.id]) self.mock_object(api_manila, "share_extend") self.mock_object( api_manila, 'tenant_absolute_limits', @@ -464,17 +447,10 @@ class ShareViewTests(test.APITestCase): def test_extend_share_post_with_api_exception(self): self.share.size = 5 form_data = {'new_size': 30} - usage_limit = { - 'maxTotalShareGigabytes': self.share.size + 50, - 'totalShareGigabytesUsed': self.share.size, - } url = reverse('horizon:project:shares:extend', args=[self.share.id]) self.mock_object( api_manila, "share_extend", mock.Mock(return_value=Exception('Fake API exception'))) - self.mock_object( - api_manila, 'tenant_absolute_limits', - mock.Mock(return_value=usage_limit)) response = self.client.post(url, form_data) diff --git a/manila_ui/tests/dashboards/project/test_data.py b/manila_ui/tests/dashboards/project/test_data.py index 8da54517..a12c6a58 100644 --- a/manila_ui/tests/dashboards/project/test_data.py +++ b/manila_ui/tests/dashboards/project/test_data.py @@ -13,7 +13,6 @@ # under the License. import collections -from manilaclient.v2 import quotas from manilaclient.v2 import security_services from manilaclient.v2 import share_export_locations from manilaclient.v2 import share_group_snapshots @@ -28,9 +27,6 @@ from manilaclient.v2 import share_snapshots from manilaclient.v2 import share_types from manilaclient.v2 import shares -from openstack_dashboard import api -from openstack_dashboard.usage import quotas as usage_quotas - class FakeAPIClient(object): client = "fake_client" @@ -474,24 +470,23 @@ share_group_snapshot_nameless = share_group_snapshots.ShareGroupSnapshot( 'members': []} ) -# Quota Sets -quota_data = dict(shares='1', - share_snapshots='1', - share_gigabytes='1000') -quota = quotas.QuotaSet(quotas.QuotaSetManager(FakeAPIClient), quota_data) - -# Quota Usages -quota_usage_data = {'gigabytes': {'used': 0, 'quota': 1000}, - 'shares': {'used': 0, 'quota': 10}, - 'snapshots': {'used': 0, 'quota': 10}, - 'share_networks': {'used': 0, 'quota': 10}} -quota_usage = usage_quotas.QuotaUsage() -for k, v in quota_usage_data.items(): - quota_usage.add_quota(api.base.Quota(k, v['quota'])) - quota_usage.tally(k, v['used']) - # Manila Limits -limits = {"absolute": {"totalSharesUsed": 1, - "totalShareGigabytesUsed": 5, - "maxTotalShareGigabytes": 1000, - "maxTotalShares": 10}} +limits = {"totalSharesUsed": 1, + "totalShareSnapshotsUsed": 1, + "totalShareGigabytesUsed": 500, + "totalSnapshotGigabytesUsed": 500, + "maxTotalShares": 10, + "maxTotalShareSnapshots": 10, + "maxTotalShareGigabytes": 1000, + "maxTotalSnapshotGigabytes": 1000, + } + +limits_negative = {"totalSharesUsed": 10, + "totalShareSnapshotsUsed": 10, + "totalShareGigabytesUsed": 1000, + "totalSnapshotGigabytesUsed": 1000, + "maxTotalShares": 10, + "maxTotalShareSnapshots": 10, + "maxTotalShareGigabytes": 1000, + "maxTotalSnapshotGigabytes": 1000, + } diff --git a/releasenotes/notes/bug-1783232-fix-quotas-retrieval-for-shares-and-snapshots-tables-63a1fc877029eac8.yaml b/releasenotes/notes/bug-1783232-fix-quotas-retrieval-for-shares-and-snapshots-tables-63a1fc877029eac8.yaml new file mode 100644 index 00000000..08d4f17d --- /dev/null +++ b/releasenotes/notes/bug-1783232-fix-quotas-retrieval-for-shares-and-snapshots-tables-63a1fc877029eac8.yaml @@ -0,0 +1,3 @@ +fixes: + - | + Fixed missing "Create Share" button on the "Shares" dashboard.