Fix manila quota operations
Some manila quota names overlap with Cinder quota names. It leads to mess of read/update operations. So, introduce unique quota names for Manila UI and translate them into manila quota names there and back. Change-Id: I4e12cfab8200aba83f2d1ca607b230f6c69d30bc Closes-Bug: #1679960 (cherry picked from commit7501353d8d
) (cherry picked from commit11065527f2
)
This commit is contained in:
parent
4ae1bc8432
commit
1c783c5fd3
@ -306,7 +306,20 @@ def tenant_quota_get(request, tenant_id):
|
||||
return base.QuotaSet(manilaclient(request).quotas.get(tenant_id))
|
||||
|
||||
|
||||
def _map_quota_names_for_update(data):
|
||||
mapping = {
|
||||
'share_gigabytes': 'gigabytes',
|
||||
'share_snapshots': 'snapshots',
|
||||
'share_snapshot_gigabytes': 'snapshot_gigabytes',
|
||||
}
|
||||
for k, v in mapping.items():
|
||||
if k in data:
|
||||
data[v] = data.pop(k)
|
||||
return data
|
||||
|
||||
|
||||
def tenant_quota_update(request, tenant_id, **kwargs):
|
||||
_map_quota_names_for_update(kwargs)
|
||||
return manilaclient(request).quotas.update(tenant_id, **kwargs)
|
||||
|
||||
|
||||
@ -315,6 +328,7 @@ def default_quota_get(request, tenant_id):
|
||||
|
||||
|
||||
def default_quota_update(request, **kwargs):
|
||||
_map_quota_names_for_update(kwargs)
|
||||
manilaclient(request).quota_classes.update(DEFAULT_QUOTA_NAME, **kwargs)
|
||||
|
||||
|
||||
|
@ -69,16 +69,20 @@ def wrap(orig_func):
|
||||
|
||||
MANILA_QUOTA_FIELDS = (
|
||||
"shares",
|
||||
"snapshots",
|
||||
"gigabytes",
|
||||
"share_gigabytes",
|
||||
"share_snapshots",
|
||||
"share_snapshot_gigabytes",
|
||||
"share_networks",
|
||||
)
|
||||
MANILA_QUOTA_NAMES = {
|
||||
'shares': _('Shares'),
|
||||
'share_gigabytes': _('Share gigabytes'),
|
||||
'share_snapshots': _('Share snapshots'),
|
||||
'share_snapshot_gigabytes': _('Share snapshot gigabytes'),
|
||||
'share_networks': _('Shares Networks'),
|
||||
}
|
||||
|
||||
quotas.QUOTA_FIELDS = quotas.QUOTA_FIELDS + MANILA_QUOTA_FIELDS
|
||||
quotas.QUOTA_FIELDS += MANILA_QUOTA_FIELDS
|
||||
|
||||
|
||||
def _get_manila_disabled_quotas(request):
|
||||
@ -96,7 +100,15 @@ def _get_manila_quota_data(request, method_name, disabled_quotas=None,
|
||||
if disabled_quotas is None:
|
||||
disabled_quotas = _get_manila_disabled_quotas(request)
|
||||
if 'shares' not in disabled_quotas:
|
||||
return getattr(manila, method_name)(request, tenant_id)
|
||||
manila_quotas = getattr(manila, method_name)(request, tenant_id)
|
||||
for quota in manila_quotas:
|
||||
if quota.name == 'gigabytes':
|
||||
quota.name = 'share_gigabytes'
|
||||
elif quota.name == 'snapshots':
|
||||
quota.name = 'share_snapshots'
|
||||
elif quota.name == 'snapshot_gigabytes':
|
||||
quota.name = 'share_snapshot_gigabytes'
|
||||
return manila_quotas
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -141,9 +153,10 @@ def tenant_quota_usages(f, request, tenant_id=None):
|
||||
sn_l = manila.share_network_list(request)
|
||||
gig_s = sum([int(v.size) for v in shares])
|
||||
gig_ss = sum([int(v.size) for v in snapshots])
|
||||
usages.tally('gigabytes', gig_s + gig_ss)
|
||||
usages.tally('shares', len(shares))
|
||||
usages.tally('snapshots', len(snapshots))
|
||||
usages.tally('share_gigabytes', gig_s)
|
||||
usages.tally('share_snapshots', len(snapshots))
|
||||
usages.tally('share_snapshot_gigabytes', gig_ss)
|
||||
usages.tally('share_networks', len(sn_l))
|
||||
|
||||
return usages
|
||||
@ -159,11 +172,14 @@ def tenant_limit_usages(f, request):
|
||||
limits.update(manila.tenant_absolute_limits(request))
|
||||
shares = manila.share_list(request)
|
||||
snapshots = manila.share_snapshot_list(request)
|
||||
share_networks = manila.share_network_list(request)
|
||||
total_s_size = sum([getattr(share, 'size', 0) for share in shares])
|
||||
total_ss_size = sum([getattr(ss, 'size', 0) for ss in snapshots])
|
||||
limits['totalGigabytesUsed'] = total_s_size + total_ss_size
|
||||
limits['totalSharesUsed'] = len(shares)
|
||||
limits['totalShareGigabytesUsed'] = total_s_size
|
||||
limits['totalSnapshotsUsed'] = len(snapshots)
|
||||
limits['totalSnapshotGigabytesUsed'] = total_ss_size
|
||||
limits['totalShareNetworksUsed'] = len(share_networks)
|
||||
except Exception:
|
||||
msg = _("Unable to retrieve share limit information.")
|
||||
horizon.exceptions.handle(request, msg)
|
||||
@ -187,11 +203,17 @@ def get_quota_name(f, quota):
|
||||
class ManilaUpdateDefaultQuotaAction(
|
||||
default_workflows.UpdateDefaultQuotasAction):
|
||||
shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares"))
|
||||
share_networks = horizon.forms.IntegerField(min_value=-1,
|
||||
label=_("Share Networks"))
|
||||
share_gigabytes = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share gigabytes"))
|
||||
share_snapshots = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share snapshots"))
|
||||
share_snapshot_gigabytes = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share snapshot gigabytes"))
|
||||
share_networks = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share Networks"))
|
||||
|
||||
class Meta(object):
|
||||
name = _("Default Quota")
|
||||
name = _("Default Quotas")
|
||||
slug = 'update_default_quotas'
|
||||
help_text = _("From here you can update the default quotas "
|
||||
"(max limits).")
|
||||
@ -221,8 +243,8 @@ class ManilaUpdateDefaultQuotas(default_workflows.UpdateDefaultQuotas):
|
||||
return True
|
||||
|
||||
|
||||
default_views.UpdateDefaultQuotasView.workflow_class = \
|
||||
ManilaUpdateDefaultQuotas
|
||||
default_views.UpdateDefaultQuotasView.workflow_class = (
|
||||
ManilaUpdateDefaultQuotas)
|
||||
|
||||
#
|
||||
# Add manila fields to Identity/Projects/Modify Quotas
|
||||
@ -232,16 +254,22 @@ default_views.UpdateDefaultQuotasView.workflow_class = \
|
||||
class ManilaUpdateProjectQuotaAction(
|
||||
project_workflows.UpdateProjectQuotaAction):
|
||||
shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares"))
|
||||
share_networks = horizon.forms.IntegerField(min_value=-1,
|
||||
label=_("Share Networks"))
|
||||
share_gigabytes = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share gigabytes"))
|
||||
share_snapshots = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share snapshots"))
|
||||
share_snapshot_gigabytes = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share snapshot gigabytes"))
|
||||
share_networks = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share Networks"))
|
||||
|
||||
class Meta(object):
|
||||
name = _("Quota")
|
||||
slug = 'update_quotas'
|
||||
help_text = _("Set maximum quotas for the project.")
|
||||
|
||||
project_workflows.UpdateProjectQuota.action_class = \
|
||||
ManilaUpdateProjectQuotaAction
|
||||
project_workflows.UpdateProjectQuota.action_class = (
|
||||
ManilaUpdateProjectQuotaAction)
|
||||
project_workflows.UpdateProjectQuota.contributes = quotas.QUOTA_FIELDS
|
||||
|
||||
|
||||
@ -274,16 +302,23 @@ project_views.UpdateProjectView.workflow_class = ManilaUpdateProject
|
||||
class ManilaCreateProjectQuotaAction(
|
||||
project_workflows.CreateProjectQuotaAction):
|
||||
shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares"))
|
||||
share_networks = horizon.forms.IntegerField(min_value=-1,
|
||||
label=_("Share Networks"))
|
||||
share_gigabytes = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share gigabytes"))
|
||||
share_snapshots = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share snapshots"))
|
||||
share_snapshot_gigabytes = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share snapshot gigabytes"))
|
||||
share_networks = horizon.forms.IntegerField(
|
||||
min_value=-1, label=_("Share Networks"))
|
||||
|
||||
class Meta(object):
|
||||
name = _("Quota")
|
||||
slug = 'create_quotas'
|
||||
help_text = _("Set maximum quotas for the project.")
|
||||
|
||||
project_workflows.CreateProjectQuota.action_class = \
|
||||
ManilaCreateProjectQuotaAction
|
||||
|
||||
project_workflows.CreateProjectQuota.action_class = (
|
||||
ManilaCreateProjectQuotaAction)
|
||||
project_workflows.CreateProjectQuota.contributes = quotas.QUOTA_FIELDS
|
||||
|
||||
|
||||
|
@ -249,3 +249,68 @@ class ManilaApiTests(base.APITestCase):
|
||||
|
||||
(self.manilaclient.shares.migration_get_progress.
|
||||
assert_called_once_with('fake_share'))
|
||||
|
||||
@ddt.data(
|
||||
({'share_gigabytes': 333}, {'gigabytes': 333}),
|
||||
({'share_snapshot_gigabytes': 444}, {'snapshot_gigabytes': 444}),
|
||||
({'share_snapshots': 14}, {'snapshots': 14}),
|
||||
({'snapshots': 14}, {'snapshots': 14}),
|
||||
({'gigabytes': 14}, {'gigabytes': 14}),
|
||||
({'snapshot_gigabytes': 314}, {'snapshot_gigabytes': 314}),
|
||||
({'shares': 24}, {'shares': 24}),
|
||||
({'share_networks': 14}, {'share_networks': 14}),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_tenant_quota_update(self, provided_kwargs, expected_kwargs):
|
||||
tenant_id = 'fake_tenant_id'
|
||||
|
||||
api.tenant_quota_update(self.request, tenant_id, **provided_kwargs)
|
||||
|
||||
self.manilaclient.quotas.update.assert_called_once_with(
|
||||
tenant_id, **expected_kwargs)
|
||||
self.manilaclient.quota_classes.update.assert_not_called()
|
||||
|
||||
@ddt.data(
|
||||
({'share_gigabytes': 333}, {'gigabytes': 333}),
|
||||
({'share_snapshot_gigabytes': 444}, {'snapshot_gigabytes': 444}),
|
||||
({'share_snapshots': 14}, {'snapshots': 14}),
|
||||
({'snapshots': 14}, {'snapshots': 14}),
|
||||
({'gigabytes': 14}, {'gigabytes': 14}),
|
||||
({'snapshot_gigabytes': 314}, {'snapshot_gigabytes': 314}),
|
||||
({'shares': 24}, {'shares': 24}),
|
||||
({'share_networks': 14}, {'share_networks': 14}),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_default_quota_update(self, provided_kwargs, expected_kwargs):
|
||||
api.default_quota_update(self.request, **provided_kwargs)
|
||||
|
||||
self.manilaclient.quota_classes.update.assert_called_once_with(
|
||||
api.DEFAULT_QUOTA_NAME, **expected_kwargs)
|
||||
|
||||
@ddt.data(
|
||||
{},
|
||||
{"name": "foo_name"},
|
||||
{"description": "foo_desc"},
|
||||
{"neutron_net_id": "foo_neutron_net_id"},
|
||||
{"neutron_subnet_id": "foo_neutron_subnet_id"},
|
||||
{"nova_net_id": "foo_nova_net_id"},
|
||||
{"name": "foo_name", "description": "foo_desc",
|
||||
"neutron_net_id": "foo_neutron_net_id",
|
||||
"neutron_subnet_id": "foo_neutron_subnet_id",
|
||||
"nova_net_id": "foo_nova_net_id"},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_share_network_create(self, **kwargs):
|
||||
expected_kwargs = {
|
||||
"name": None,
|
||||
"description": None,
|
||||
"neutron_net_id": None,
|
||||
"neutron_subnet_id": None,
|
||||
"nova_net_id": None,
|
||||
}
|
||||
expected_kwargs.update(kwargs)
|
||||
|
||||
api.share_network_create(self.request, **kwargs)
|
||||
|
||||
mock_sn_create = self.manilaclient.share_networks.create
|
||||
mock_sn_create.assert_called_once_with(**expected_kwargs)
|
||||
|
@ -12,6 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils import translation
|
||||
import mock
|
||||
@ -133,3 +134,71 @@ class PieChartsTests(test.TestCase):
|
||||
"text": chart["text"]},
|
||||
expected_charts.pop(name, "NotFound")
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class QuotaTests(test.TestCase):
|
||||
|
||||
@ddt.data(
|
||||
shares.ManilaUpdateDefaultQuotaAction,
|
||||
shares.ManilaUpdateProjectQuotaAction,
|
||||
shares.ManilaCreateProjectQuotaAction,
|
||||
)
|
||||
def test_manila_quota_action(self, class_ref):
|
||||
self.mock_object(
|
||||
quotas, 'get_disabled_quotas', mock.Mock(return_value=[]))
|
||||
class_instance = class_ref(self.request, 'foo')
|
||||
expected_fields = set([
|
||||
'shares', 'share_gigabytes', 'share_snapshots',
|
||||
'share_snapshot_gigabytes', 'share_networks',
|
||||
])
|
||||
# NOTE(vponomaryov): iterate over reversed list of visible fields
|
||||
# because manila's fields are at the end always.
|
||||
for vf in reversed(class_instance.visible_fields()):
|
||||
if expected_fields and vf.name in expected_fields:
|
||||
self.assertEqual(-1, vf.field.min_value)
|
||||
self.assertIsInstance(
|
||||
vf.field, shares.horizon.forms.IntegerField)
|
||||
expected_fields.remove(vf.name)
|
||||
self.assertSetEqual(set([]), expected_fields)
|
||||
self.assertTrue(quotas.get_disabled_quotas.called)
|
||||
|
||||
@ddt.data('default_quota_get', 'tenant_quota_get')
|
||||
def test__get_manila_quota_data(self, method_name):
|
||||
fake_quotas = [
|
||||
type('Fake', (object, ), {'name': name})
|
||||
for name in ('gigabytes', 'snapshots', 'snapshot_gigabytes')
|
||||
]
|
||||
self.mock_object(
|
||||
api_manila, method_name, mock.Mock(return_value=fake_quotas))
|
||||
self.mock_object(
|
||||
shares, '_get_manila_disabled_quotas',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
result = shares._get_manila_quota_data(
|
||||
self.request, method_name)
|
||||
|
||||
expected = [
|
||||
'share_gigabytes',
|
||||
'share_snapshot_gigabytes',
|
||||
'share_snapshots',
|
||||
]
|
||||
self.assertEqual(3, len(result))
|
||||
self.assertEqual(
|
||||
expected,
|
||||
sorted([element.name for element in result]))
|
||||
getattr(api_manila, method_name).assert_called_once_with(
|
||||
self.request, self.request.user.tenant_id)
|
||||
shares._get_manila_disabled_quotas.asssert_called_once_with(
|
||||
self.request)
|
||||
|
||||
def test_manila_quota_fields(self):
|
||||
expected_fields = (
|
||||
"shares",
|
||||
"share_gigabytes",
|
||||
"share_snapshots",
|
||||
"share_snapshot_gigabytes",
|
||||
"share_networks",
|
||||
)
|
||||
for ef in expected_fields:
|
||||
self.assertIn(ef, shares.quotas.QUOTA_FIELDS)
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
fixes:
|
||||
- Fixed quota names overlapping with Cinder's quotas. Now it is possible
|
||||
to read/write any manila quotas not messing up Cinder's quotas.
|
Loading…
Reference in New Issue
Block a user