From 6b4acf19a70732b20da4732de8ec6624217c984e Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Wed, 28 Mar 2018 06:11:02 +0900 Subject: [PATCH] Use EXTRA_TABS/EXTRA_STEPS mechanism to handle manila quotas The previous manila-ui approach to show shared-file-system default quotas is too hacky and fragile as the bug reveals. This commit applies EXTRA_TABS/EXTRA_STEPS plugin interface introduced to horizon in Rocky to show the manila quota tab in the default quotas table and quota related forms. monkey-patching from manila quotas has been dropped. Note that EXTRA_STEPS feature is being reviewd in horizon https://review.openstack.org/#/c/560679/ so workflow steps related to manila in the project quota form and the default quota form are not shown until the corresponding horizon feature is merged. However, this commit will unblock manila-ui CI so I believe this is a good compromise. Note that manila support in the project overview panel is dropped temporarily as further refactoring in the project overview panel is being done in horizon side (which will land in Rocky-2). Closes-Bug: #1759340 Co-Authored-By: Victoria Martinez de la Cruz Change-Id: I22ed7d757c5e5e902f1e85a15c33b34de6c609f1 --- manila_ui/api/manila.py | 8 + .../dashboards/admin/defaults/__init__.py | 0 manila_ui/dashboards/admin/defaults/tables.py | 51 +++ manila_ui/dashboards/admin/defaults/tabs.py | 42 +++ .../dashboards/admin/defaults/workflows.py | 80 +++++ manila_ui/dashboards/identity/__init__.py | 0 .../dashboards/identity/projects/__init__.py | 0 .../dashboards/identity/projects/workflows.py | 54 +++ .../dashboards/project/shares/__init__.py | 340 +----------------- .../_80_manila_admin_add_share_panel_group.py | 16 + manila_ui/tests/dashboards/project/tests.py | 81 ----- 11 files changed, 258 insertions(+), 414 deletions(-) create mode 100644 manila_ui/dashboards/admin/defaults/__init__.py create mode 100644 manila_ui/dashboards/admin/defaults/tables.py create mode 100644 manila_ui/dashboards/admin/defaults/tabs.py create mode 100644 manila_ui/dashboards/admin/defaults/workflows.py create mode 100644 manila_ui/dashboards/identity/__init__.py create mode 100644 manila_ui/dashboards/identity/projects/__init__.py create mode 100644 manila_ui/dashboards/identity/projects/workflows.py diff --git a/manila_ui/api/manila.py b/manila_ui/api/manila.py index 0d9a533a..93231576 100644 --- a/manila_ui/api/manila.py +++ b/manila_ui/api/manila.py @@ -39,6 +39,14 @@ MANILA_SERVICE_TYPE = "sharev2" SHARE_STATE_AVAILABLE = "available" DEFAULT_QUOTA_NAME = 'default' +MANILA_QUOTA_FIELDS = { + "shares", + "share_gigabytes", + "share_snapshots", + "share_snapshot_gigabytes", + "share_networks", +} + def manilaclient(request): insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) diff --git a/manila_ui/dashboards/admin/defaults/__init__.py b/manila_ui/dashboards/admin/defaults/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/manila_ui/dashboards/admin/defaults/tables.py b/manila_ui/dashboards/admin/defaults/tables.py new file mode 100644 index 00000000..bcc7a9fb --- /dev/null +++ b/manila_ui/dashboards/admin/defaults/tables.py @@ -0,0 +1,51 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.utils.translation import ugettext_lazy as _ + +from horizon import tables + +from openstack_dashboard.dashboards.admin.defaults import tables as default_tbl + + +MANILA_QUOTA_NAMES = { + 'shares': _('Shares'), + 'gigabytes': _('Share gigabytes'), + 'snapshots': _('Share snapshots'), + 'snapshot_gigabytes': _('Share snapshot gigabytes'), + 'share_networks': _('Shares Networks'), +} + + +def get_quota_name(quota): + return MANILA_QUOTA_NAMES.get(quota.name, + quota.name.replace("_", " ").title()) + + +class UpdateDefaultShareQuotas(default_tbl.UpdateDefaultQuotas): + name = 'update_share_defaults' + step = 'update_default_share_quotas' + + +class ShareQuotasTable(tables.DataTable): + name = tables.Column(get_quota_name, verbose_name=_('Quota Name')) + limit = tables.Column("limit", verbose_name=_('Limit')) + + def get_object_id(self, obj): + return obj.name + + class Meta(object): + name = "share_quotas" + verbose_name = _("Shared Quotas") + table_actions = (default_tbl.QuotaFilterAction, + UpdateDefaultShareQuotas) + multi_select = False diff --git a/manila_ui/dashboards/admin/defaults/tabs.py b/manila_ui/dashboards/admin/defaults/tabs.py new file mode 100644 index 00000000..4692af44 --- /dev/null +++ b/manila_ui/dashboards/admin/defaults/tabs.py @@ -0,0 +1,42 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import tabs + +from openstack_dashboard import api + +from manila_ui.api import manila as api_manila +from manila_ui.dashboards.admin.defaults import tables + + +class ShareQuotasTab(tabs.TableTab): + table_classes = (tables.ShareQuotasTable,) + name = _("Share Quotas") + slug = "shared_quotas" + template_name = ("horizon/common/_detail_table.html") + + def get_share_quotas_data(self): + request = self.tab_group.request + tenant_id = request.user.tenant_id + try: + data = api_manila.default_quota_get(request, tenant_id) + except Exception: + data = [] + exceptions.handle(self.request, + _('Unable to get manila default quota.')) + return data + + def allowed(self, request): + return api.base.is_service_enabled(request, 'share') diff --git a/manila_ui/dashboards/admin/defaults/workflows.py b/manila_ui/dashboards/admin/defaults/workflows.py new file mode 100644 index 00000000..7f930d1e --- /dev/null +++ b/manila_ui/dashboards/admin/defaults/workflows.py @@ -0,0 +1,80 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import forms +from horizon import workflows + +from openstack_dashboard.api import base + +from manila_ui.api import manila as api_manila + + +class UpdateDefaultShareQuotasAction(workflows.Action): + shares = forms.IntegerField(min_value=-1, label=_("Shares")) + share_gigabytes = forms.IntegerField( + min_value=-1, label=_("Share gigabytes")) + share_snapshots = forms.IntegerField( + min_value=-1, label=_("Share snapshots")) + share_snapshot_gigabytes = forms.IntegerField( + min_value=-1, label=_("Share snapshot gigabytes")) + share_networks = forms.IntegerField( + min_value=-1, label=_("Share Networks")) + + def __init__(self, request, context, *args, **kwargs): + super(UpdateDefaultShareQuotasAction, self).__init__( + request, context, *args, **kwargs) + disabled_quotas = context['disabled_quotas'] + for field in disabled_quotas: + if field in self.fields: + self.fields[field].required = False + self.fields[field].widget = forms.HiddenInput() + + def handle(self, request, data): + try: + if base.is_service_enabled(request, 'share'): + manila_data = dict([(key, data[key]) for key in + api_manila.MANILA_QUOTA_FIELDS]) + api_manila.default_quota_update(request, **manila_data) + return True + except Exception: + exceptions.handle(request, + _('Unable to update default quotas.')) + return False + + class Meta(object): + name = _("Share") + slug = 'update_default_share_quotas' + help_text = _("From here you can update the default share quotas " + "(max limits).") + + +class UpdateDefaultShareQuotasStep(workflows.Step): + action_class = UpdateDefaultShareQuotasAction + contributes = api_manila.MANILA_QUOTA_FIELDS + depends_on = ('disabled_quotas',) + + def prepare_action_context(self, request, context): + try: + quota_defaults = api_manila.default_quota_get( + request, request.user.tenant_id) + for field in api_manila.MANILA_QUOTA_FIELDS: + context[field] = quota_defaults.get(field).limit + except Exception: + exceptions.handle(request, + _('Unable to retrieve default share quotas.')) + return context + + def allowed(self, request): + return base.is_service_enabled(request, 'share') diff --git a/manila_ui/dashboards/identity/__init__.py b/manila_ui/dashboards/identity/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/manila_ui/dashboards/identity/projects/__init__.py b/manila_ui/dashboards/identity/projects/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/manila_ui/dashboards/identity/projects/workflows.py b/manila_ui/dashboards/identity/projects/workflows.py new file mode 100644 index 00000000..82450026 --- /dev/null +++ b/manila_ui/dashboards/identity/projects/workflows.py @@ -0,0 +1,54 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.utils.translation import ugettext_lazy as _ + +from horizon import forms +from horizon import workflows + +from openstack_dashboard.api import base +from openstack_dashboard.dashboards.identity.projects \ + import workflows as project_workflows + +from manila_ui.api import manila as api_manila + + +class ShareQuotaAction(project_workflows.CommonQuotaAction): + shares = forms.IntegerField(min_value=-1, label=_("Shares")) + share_gigabytes = forms.IntegerField( + min_value=-1, label=_("Share gigabytes")) + share_snapshots = forms.IntegerField( + min_value=-1, label=_("Share snapshots")) + share_snapshot_gigabytes = forms.IntegerField( + min_value=-1, label=_("Share snapshot gigabytes")) + share_networks = forms.IntegerField( + min_value=-1, label=_("Share Networks")) + + _quota_fields = api_manila.MANILA_QUOTA_FIELDS + + def _tenant_quota_update(self, request, project_id, data): + api_manila.tenant_quota_update(request, project_id, **data) + + class Meta(object): + name = _("Share") + slug = 'update_share_quotas' + help_text = _("Set maximum quotas for the project.") + permissions = ('openstack.roles.admin', 'openstack.services.share') + + +class UpdateShareQuota(workflows.Step): + action_class = ShareQuotaAction + depends_on = ("project_id", "disabled_quotas") + contributes = api_manila.MANILA_QUOTA_FIELDS + + def allowed(self, request): + return base.is_service_enabled(request, 'share') diff --git a/manila_ui/dashboards/project/shares/__init__.py b/manila_ui/dashboards/project/shares/__init__.py index 3a04dc2f..e8889a53 100644 --- a/manila_ui/dashboards/project/shares/__init__.py +++ b/manila_ui/dashboards/project/shares/__init__.py @@ -10,343 +10,21 @@ # License for the specific language governing permissions and limitations # under the License. -import functools -import sys - from django.utils.translation import ugettext_lazy as _ -import horizon +from horizon import exceptions + +from openstack_dashboard.api import base +from openstack_dashboard.usage import base as usage from manila_ui.api import manila -from openstack_dashboard.api import base -from openstack_dashboard.dashboards.admin.defaults import tables as quota_tbl -from openstack_dashboard.dashboards.admin.defaults import views \ - as default_views -from openstack_dashboard.dashboards.admin.defaults import workflows \ - as default_workflows -from openstack_dashboard.dashboards.identity.projects import views \ - as project_views -from openstack_dashboard.dashboards.identity.projects import workflows \ - as project_workflows -from openstack_dashboard.dashboards.project.overview import views \ - as overview_views -from openstack_dashboard.usage import base as usage_base -from openstack_dashboard.usage import quotas - - -def wrap(orig_func): - """decorator to wrap an existing function - Modified post from http://downgra.de/2009/05/16/python-monkey-patching/ - to work with functions - e.g. - - @wrap(quotas.tenant_limit_usages) - def tenant_limit_usages(orig, self): - limits = orig(request) - limits['disksUsed'] = 100 - return limits - - the first parameter of the new function is the the original, - overwritten function ('orig'). - """ - - def outer(new_func): - @functools.wraps(orig_func) - def wrapper(*args, **kwargs): - return new_func(orig_func, *args, **kwargs) - # Replace the original function in the module with the wrapper - orig_module = sys.modules[orig_func.__module__] - setattr(orig_module, orig_func.__name__, wrapper) - return wrapper - return outer - - -# All public methods in openstack_dashboard.usage.quotas are hardcoded to -# only look at a fixed set of services (nova, cinder, etc.). In order to -# incorporate manila quotas and usage, all public functions must be -# monkey-patched to add that information in. - -MANILA_QUOTA_FIELDS = { - "shares", - "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 - - -def _get_manila_disabled_quotas(request): - disabled_quotas = [] - if not base.is_service_enabled(request, 'share'): - disabled_quotas.extend(MANILA_QUOTA_FIELDS) - - return disabled_quotas - - -def _get_manila_quota_data(request, method_name, disabled_quotas=None, - tenant_id=None): - if not tenant_id: - tenant_id = request.user.tenant_id - if disabled_quotas is None: - disabled_quotas = _get_manila_disabled_quotas(request) - if 'shares' not in disabled_quotas: - 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 - - -@wrap(quotas.get_default_quota_data) -def get_default_quota_data(f, request, disabled_quotas=None, tenant_id=None): - qs = f(request, disabled_quotas, tenant_id) - manila_quota = _get_manila_quota_data(request, "default_quota_get", - disabled_quotas=disabled_quotas, - tenant_id=tenant_id) - if manila_quota: - qs.add(manila_quota) - return qs - - -@wrap(quotas.get_tenant_quota_data) -def get_tenant_quota_data(f, request, disabled_quotas=None, tenant_id=None): - qs = f(request, disabled_quotas, tenant_id) - manila_quota = _get_manila_quota_data(request, "tenant_quota_get", - disabled_quotas=disabled_quotas, - tenant_id=tenant_id) - if manila_quota: - qs.add(manila_quota) - return qs - - -@wrap(quotas.get_disabled_quotas) -def get_disabled_quotas(f, request): - disabled_quotas = f(request) - disabled_quotas.update(_get_manila_disabled_quotas(request)) - return disabled_quotas - - -@wrap(quotas.tenant_quota_usages) -def tenant_quota_usages(f, request, tenant_id=None, targets=None): - - usages = f(request, tenant_id, targets) - - if 'shares' not in _get_manila_disabled_quotas(request): - shares = manila.share_list(request) - snapshots = manila.share_snapshot_list(request) - 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('shares', len(shares)) - 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 - - -@wrap(quotas.tenant_limit_usages) -def tenant_limit_usages(f, request): - - limits = f(request) - - if base.is_service_enabled(request, 'share'): - try: - 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['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) - - return limits - - -@wrap(quota_tbl.get_quota_name) -def get_quota_name(f, quota): - if quota.name in MANILA_QUOTA_NAMES: - return MANILA_QUOTA_NAMES.get(quota.name) - else: - return f(quota) - - # -# Add manila fields to Admin/Defaults/Update Defaults +# Add extra pie charts to project/compute overview # -class ManilaUpdateDefaultQuotaAction( - default_workflows.UpdateDefaultQuotasAction): - shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares")) - 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 Quotas") - slug = 'update_default_quotas' - help_text = _("From here you can update the default quotas " - "(max limits).") - - -class ManilaUpdateDefaultQuotasStep(default_workflows.UpdateDefaultQuotasStep): - action_class = ManilaUpdateDefaultQuotaAction - contributes = quotas.QUOTA_FIELDS - - -class ManilaUpdateDefaultQuotas(default_workflows.UpdateDefaultQuotas): - default_steps = (ManilaUpdateDefaultQuotasStep,) - - def handle(self, request, data): - try: - super(ManilaUpdateDefaultQuotas, self).handle(request, data) - - if base.is_service_enabled(request, 'share'): - manila_data = dict([(key, data[key]) for key in - MANILA_QUOTA_FIELDS]) - manila.default_quota_update(request, **manila_data) - - except Exception: - horizon.exceptions.handle(request, - _('Unable to update default quotas.')) - - return True - - -default_views.UpdateDefaultQuotasView.workflow_class = ( - ManilaUpdateDefaultQuotas) - -# -# Add manila fields to Identity/Projects/Modify Quotas -# - - -class ManilaUpdateProjectQuotaAction( - project_workflows.UpdateProjectQuotaAction): - shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares")) - 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.contributes = quotas.QUOTA_FIELDS - - -class ManilaUpdateProject(project_workflows.UpdateProject): - def handle(self, request, data): - try: - super(ManilaUpdateProject, self).handle(request, data) - - if base.is_service_enabled(request, 'share'): - manila_data = dict([(key, data[key]) for key in - MANILA_QUOTA_FIELDS]) - manila.tenant_quota_update(request, - data['project_id'], - **manila_data) - - except Exception: - horizon.exceptions.handle(request, - _('Modified project information and ' - 'members, but unable to modify ' - 'project quotas.')) - return True - -project_views.UpdateProjectView.workflow_class = ManilaUpdateProject - -# -# Add manila fields to Identity/Projects/Create Project -# - - -class ManilaCreateProjectQuotaAction( - project_workflows.CreateProjectQuotaAction): - shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares")) - 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.contributes = quotas.QUOTA_FIELDS - - -class ManilaCreateProject(project_workflows.CreateProject): - def handle(self, request, data): - try: - super(ManilaCreateProject, self).handle(request, data) - - if base.is_service_enabled(request, 'share'): - manila_data = dict([(key, data[key]) for key in - MANILA_QUOTA_FIELDS]) - manila.tenant_quota_update(request, - self.object.id, - **manila_data) - - except Exception: - horizon.exceptions.handle(request, - _('Unable to set project quotas.')) - return True - -project_views.CreateProjectView.workflow_class = ManilaCreateProject - -# -# Add extra pie charts to Project/Compute Overview -# - - -class ManilaUsage(usage_base.ProjectUsage): +class ManilaUsage(usage.ProjectUsage): def get_manila_limits(self): """Get share limits if manila is enabled.""" @@ -356,7 +34,7 @@ class ManilaUsage(usage_base.ProjectUsage): self.limits.update(manila.tenant_absolute_limits(self.request)) except Exception: msg = _("Unable to retrieve share limit information.") - horizon.exceptions.handle(self.request, msg) + exceptions.handle(self.request, msg) return def get_limits(self): @@ -387,7 +65,3 @@ def get_context_data(self, **kwargs): 'text': False, }) return context - - -overview_views.ProjectOverview.get_context_data = get_context_data -overview_views.ProjectOverview.usage_class = ManilaUsage diff --git a/manila_ui/local/enabled/_80_manila_admin_add_share_panel_group.py b/manila_ui/local/enabled/_80_manila_admin_add_share_panel_group.py index 90a8b980..d071d6ee 100644 --- a/manila_ui/local/enabled/_80_manila_admin_add_share_panel_group.py +++ b/manila_ui/local/enabled/_80_manila_admin_add_share_panel_group.py @@ -18,3 +18,19 @@ PANEL_GROUP = 'share' PANEL_GROUP_NAME = 'Share' # The slug of the dashboard the PANEL_GROUP associated with. Required. PANEL_GROUP_DASHBOARD = 'admin' + +EXTRA_TABS = { + 'openstack_dashboard.dashboards.admin.defaults.tabs.DefaultsTabs': ( + 'manila_ui.dashboards.admin.defaults.tabs.ShareQuotasTab', + ), +} +EXTRA_STEPS = { + 'openstack_dashboard.dashboards.identity.projects.workflows.UpdateQuota': ( + 'manila_ui.dashboards.identity.projects.workflows.UpdateShareQuota', + ), + 'openstack_dashboard.dashboards.admin.defaults.workflows.' + 'UpdateDefaultQuotas': ( + 'manila_ui.dashboards.admin.defaults.workflows.' + 'UpdateDefaultShareQuotasStep', + ), +} diff --git a/manila_ui/tests/dashboards/project/tests.py b/manila_ui/tests/dashboards/project/tests.py index 626333d8..9926595e 100644 --- a/manila_ui/tests/dashboards/project/tests.py +++ b/manila_ui/tests/dashboards/project/tests.py @@ -12,14 +12,10 @@ # 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 -from openstack_dashboard.api import base -from openstack_dashboard.usage import quotas -from manila_ui.api import manila as api_manila from manila_ui.dashboards.project import shares from manila_ui.tests import helpers as test @@ -85,80 +81,3 @@ class PieChartsTests(test.TestCase): "text": chart["text"]}, expected_charts.pop(name, "NotFound") ) - - -@ddt.ddt -class QuotaTests(test.TestCase): - - def test_get_disabled_quotas(self): - self.mock_object( - base, "is_service_enabled", mock.Mock(return_value=False)) - - result_quotas = quotas.get_disabled_quotas(self.request) - - expected_quotas = set(quotas.QUOTA_FIELDS) - self.assertItemsEqual(result_quotas, expected_quotas) - - @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)