From a4fe656d0d59b163c4701d7419833aae725fa79f Mon Sep 17 00:00:00 2001 From: Valeriy Ponomaryov Date: Tue, 16 May 2017 19:19:04 +0300 Subject: [PATCH] Refactor project dashboard Separating tabs of single panel to separate panels. It will reduce amount of redundant calls, because it is very unlikely that someone will need all tabs at once. Also, it is current approach that is used by core projects. Similar refactor for admin dashboard is located at [1] [1] I874253e0e9a35ede8239bc1bdf0a330a44ade413 Change-Id: Ia8a432e136a9c06f3db887b9289d90853dd027e6 Partially-Implements BluePrint create-share-panel-group --- .../templates/security_services/index.html | 2 +- .../admin/security_services/views.py | 2 +- .../dashboards/admin/share_networks/tables.py | 2 +- .../dashboards/admin/share_networks/views.py | 2 +- .../admin/share_snapshots/tables.py | 6 +- .../dashboards/admin/share_snapshots/views.py | 4 +- manila_ui/dashboards/admin/shares/tables.py | 2 +- manila_ui/dashboards/admin/shares/views.py | 2 +- .../security_services/__init__.py | 0 .../{shares => }/security_services/forms.py | 3 +- .../project/security_services/panel.py | 28 + .../{shares => }/security_services/tables.py | 8 +- .../{shares => }/security_services/tabs.py | 30 +- .../templates/security_services/_add.html} | 4 +- .../templates/security_services/_create.html} | 0 .../templates/security_services/_detail.html} | 0 .../templates}/security_services/_update.html | 0 .../templates/security_services/add.html} | 2 +- .../templates/security_services/create.html} | 2 +- .../templates}/security_services/detail.html | 0 .../templates/security_services/index.html | 11 + .../templates}/security_services/update.html | 2 +- .../project/security_services/urls.py | 37 + .../{shares => }/security_services/views.py | 66 +- .../{shares => }/share_networks/__init__.py | 0 .../{shares => }/share_networks/forms.py | 6 +- .../project/share_networks/panel.py | 28 + .../{shares => }/share_networks/tables.py | 62 +- .../dashboards/project/share_networks/tabs.py | 31 + .../templates/share_networks/_create.html} | 0 .../templates/share_networks/_detail.html} | 9 +- .../templates/share_networks/_update.html} | 4 +- .../templates/share_networks/create.html} | 2 +- .../templates/share_networks}/detail.html | 2 +- .../templates/share_networks/index.html | 11 + .../templates/share_networks/update.html} | 0 .../dashboards/project/share_networks/urls.py | 37 + .../{shares => }/share_networks/views.py | 70 +- .../{shares => }/share_networks/workflows.py | 2 +- .../shares => share_snapshots}/__init__.py | 0 .../snapshots => share_snapshots}/forms.py | 35 +- .../project/share_snapshots/panel.py | 28 + .../snapshots => share_snapshots}/tables.py | 150 ++-- .../project/share_snapshots/tabs.py | 31 + .../templates/share_snapshots/_create.html} | 2 +- .../templates/share_snapshots/_detail.html} | 2 +- .../templates/share_snapshots/_limits.html} | 0 .../templates/share_snapshots}/_rule_add.html | 0 .../templates/share_snapshots}/_update.html | 0 .../templates/share_snapshots/create.html} | 2 +- .../templates/share_snapshots/detail.html} | 2 +- .../templates/share_snapshots/index.html | 11 + .../share_snapshots}/manage_rules.html | 2 +- .../templates/share_snapshots}/rule_add.html | 2 +- .../templates/share_snapshots}/update.html | 2 +- .../project/share_snapshots/urls.py | 45 + .../snapshots => share_snapshots}/views.py | 134 +-- .../project/shares/{shares => }/forms.py | 0 .../project/shares/share_networks/tabs.py | 79 -- .../dashboards/project/shares/shares/tabs.py | 77 -- .../dashboards/project/shares/shares/views.py | 319 ------- .../project/shares/snapshots/tabs.py | 64 -- .../project/shares/{shares => }/tables.py | 5 +- manila_ui/dashboards/project/shares/tabs.py | 30 + .../{shares/_extend.html => _create.html} | 2 +- .../_detail_overview.html => _detail.html} | 4 +- .../{shares/_create.html => _extend.html} | 2 +- .../shares/{shares => }/_extend_limits.html | 0 .../shares/{shares => }/_limits.html | 0 .../shares/{shares => }/_manage_rules.html | 0 .../shares/{shares => }/_revert.html | 0 .../shares/{shares => }/_rule_add.html | 0 .../shares/{shares => }/_update.html | 0 .../shares/{shares => }/_update_metadata.html | 0 .../templates/shares/{shares => }/create.html | 2 +- .../shares/{share_networks => }/detail.html | 0 .../templates/shares/{shares => }/extend.html | 4 +- .../shares/templates/shares/index.html | 2 +- .../shares/{shares => }/manage_rules.html | 0 .../templates/shares/{shares => }/revert.html | 2 +- .../shares/{shares => }/rule_add.html | 2 +- .../shares/shares/_add_security_service.html | 60 -- .../templates/shares/{shares => }/update.html | 2 +- .../shares/{shares => }/update_metadata.html | 2 +- manila_ui/dashboards/project/shares/urls.py | 94 +- manila_ui/dashboards/project/shares/views.py | 347 +++++++- .../_80_manila_admin_add_share_panel_group.py | 14 + ...0_manila_project_add_share_panel_group.py} | 15 +- ...t_add_shares_panel_to_share_panel_group.py | 18 + ...re_snapshots_panel_to_share_panel_group.py | 18 + ...are_networks_panel_to_share_panel_group.py | 18 + ...ity_services_panel_to_share_panel_group.py | 19 + .../admin/security_services/tests.py | 2 +- .../dashboards/admin/share_instances/tests.py | 2 +- .../dashboards/admin/share_networks/tests.py | 2 +- .../dashboards/admin/share_servers/tests.py | 2 +- .../dashboards/admin/share_snapshots/tests.py | 2 +- .../dashboards/admin/share_types/tests.py | 2 +- .../dashboards/admin/shares/replicas/tests.py | 2 +- .../tests/dashboards/admin/shares/tests.py | 2 +- .../project/security_services}/__init__.py | 0 .../{shares => }/security_services/tests.py | 48 +- .../__init__.py | 0 .../{shares => }/share_networks/tests.py | 28 +- .../__init__.py | 0 .../test_tables.py | 4 +- .../snapshots => share_snapshots}/tests.py | 105 ++- .../project/shares/replicas/tests.py | 11 +- .../project/shares/shares/__init__.py | 0 .../dashboards/project/shares/shares/tests.py | 709 --------------- .../project/shares/snapshots/__init__.py | 0 .../tests/dashboards/project/shares/tests.py | 811 ++++++++++++++---- .../project/{shares => }/test_data.py | 0 manila_ui/tests/dashboards/project/tests.py | 164 ++++ ...to-project-dashboard-722ab48392588728.yaml | 12 + 115 files changed, 2058 insertions(+), 1978 deletions(-) rename manila_ui/dashboards/project/{shares => }/security_services/__init__.py (100%) rename manila_ui/dashboards/project/{shares => }/security_services/forms.py (98%) create mode 100644 manila_ui/dashboards/project/security_services/panel.py rename manila_ui/dashboards/project/{shares => }/security_services/tables.py (90%) rename manila_ui/dashboards/project/{shares => }/security_services/tabs.py (52%) rename manila_ui/dashboards/project/{shares/templates/shares/security_services/_add_security_service.html => security_services/templates/security_services/_add.html} (86%) rename manila_ui/dashboards/project/{shares/templates/shares/security_services/_create_security_service.html => security_services/templates/security_services/_create.html} (100%) rename manila_ui/dashboards/project/{shares/templates/shares/security_services/_detail_overview.html => security_services/templates/security_services/_detail.html} (100%) rename manila_ui/dashboards/project/{shares/templates/shares => security_services/templates}/security_services/_update.html (100%) rename manila_ui/dashboards/project/{shares/templates/shares/security_services/add_security_service.html => security_services/templates/security_services/add.html} (64%) rename manila_ui/dashboards/project/{shares/templates/shares/security_services/create_security_service.html => security_services/templates/security_services/create.html} (63%) rename manila_ui/dashboards/project/{shares/templates/shares => security_services/templates}/security_services/detail.html (100%) create mode 100644 manila_ui/dashboards/project/security_services/templates/security_services/index.html rename manila_ui/dashboards/project/{shares/templates/shares => security_services/templates}/security_services/update.html (68%) create mode 100644 manila_ui/dashboards/project/security_services/urls.py rename manila_ui/dashboards/project/{shares => }/security_services/views.py (71%) rename manila_ui/dashboards/project/{shares => }/share_networks/__init__.py (100%) rename manila_ui/dashboards/project/{shares => }/share_networks/forms.py (99%) create mode 100644 manila_ui/dashboards/project/share_networks/panel.py rename manila_ui/dashboards/project/{shares => }/share_networks/tables.py (71%) create mode 100644 manila_ui/dashboards/project/share_networks/tabs.py rename manila_ui/dashboards/project/{shares/templates/shares/share_networks/_create_share_network.html => share_networks/templates/share_networks/_create.html} (100%) rename manila_ui/dashboards/project/{shares/templates/shares/share_networks/_detail_overview.html => share_networks/templates/share_networks/_detail.html} (77%) rename manila_ui/dashboards/project/{shares/templates/shares/share_networks/_share_network_update.html => share_networks/templates/share_networks/_update.html} (74%) rename manila_ui/dashboards/project/{shares/templates/shares/share_networks/create_share_network.html => share_networks/templates/share_networks/create.html} (64%) rename manila_ui/dashboards/project/{shares/templates/shares/shares => share_networks/templates/share_networks}/detail.html (70%) create mode 100644 manila_ui/dashboards/project/share_networks/templates/share_networks/index.html rename manila_ui/dashboards/project/{shares/templates/shares/share_networks/share_network_update.html => share_networks/templates/share_networks/update.html} (100%) create mode 100644 manila_ui/dashboards/project/share_networks/urls.py rename manila_ui/dashboards/project/{shares => }/share_networks/views.py (67%) rename manila_ui/dashboards/project/{shares => }/share_networks/workflows.py (99%) rename manila_ui/dashboards/project/{shares/shares => share_snapshots}/__init__.py (100%) rename manila_ui/dashboards/project/{shares/snapshots => share_snapshots}/forms.py (74%) create mode 100644 manila_ui/dashboards/project/share_snapshots/panel.py rename manila_ui/dashboards/project/{shares/snapshots => share_snapshots}/tables.py (69%) create mode 100644 manila_ui/dashboards/project/share_snapshots/tabs.py rename manila_ui/dashboards/project/{shares/templates/shares/snapshots/_create_snapshot.html => share_snapshots/templates/share_snapshots/_create.html} (57%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots/_snapshot_detail_overview.html => share_snapshots/templates/share_snapshots/_detail.html} (96%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots/_limits_snapshots.html => share_snapshots/templates/share_snapshots/_limits.html} (100%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots => share_snapshots/templates/share_snapshots}/_rule_add.html (100%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots => share_snapshots/templates/share_snapshots}/_update.html (100%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots/create_snapshot.html => share_snapshots/templates/share_snapshots/create.html} (67%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots/snapshot_detail.html => share_snapshots/templates/share_snapshots/detail.html} (70%) create mode 100644 manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/index.html rename manila_ui/dashboards/project/{shares/templates/shares/snapshots => share_snapshots/templates/share_snapshots}/manage_rules.html (59%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots => share_snapshots/templates/share_snapshots}/rule_add.html (68%) rename manila_ui/dashboards/project/{shares/templates/shares/snapshots => share_snapshots/templates/share_snapshots}/update.html (70%) create mode 100644 manila_ui/dashboards/project/share_snapshots/urls.py rename manila_ui/dashboards/project/{shares/snapshots => share_snapshots}/views.py (60%) rename manila_ui/dashboards/project/shares/{shares => }/forms.py (100%) delete mode 100644 manila_ui/dashboards/project/shares/share_networks/tabs.py delete mode 100644 manila_ui/dashboards/project/shares/shares/tabs.py delete mode 100644 manila_ui/dashboards/project/shares/shares/views.py delete mode 100644 manila_ui/dashboards/project/shares/snapshots/tabs.py rename manila_ui/dashboards/project/shares/{shares => }/tables.py (99%) create mode 100644 manila_ui/dashboards/project/shares/tabs.py rename manila_ui/dashboards/project/shares/templates/shares/{shares/_extend.html => _create.html} (64%) rename manila_ui/dashboards/project/shares/templates/shares/{shares/_detail_overview.html => _detail.html} (94%) rename manila_ui/dashboards/project/shares/templates/shares/{shares/_create.html => _extend.html} (71%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/_extend_limits.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/_limits.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/_manage_rules.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/_revert.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/_rule_add.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/_update.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/_update_metadata.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/create.html (70%) rename manila_ui/dashboards/project/shares/templates/shares/{share_networks => }/detail.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/extend.html (63%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/manage_rules.html (100%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/revert.html (70%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/rule_add.html (69%) delete mode 100644 manila_ui/dashboards/project/shares/templates/shares/shares/_add_security_service.html rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/update.html (70%) rename manila_ui/dashboards/project/shares/templates/shares/{shares => }/update_metadata.html (68%) rename manila_ui/local/enabled/{_90_manila_project_shares.py => _80_manila_project_add_share_panel_group.py} (70%) create mode 100644 manila_ui/local/enabled/_9010_manila_project_add_shares_panel_to_share_panel_group.py create mode 100644 manila_ui/local/enabled/_9020_manila_project_add_share_snapshots_panel_to_share_panel_group.py create mode 100644 manila_ui/local/enabled/_9040_manila_project_add_share_networks_panel_to_share_panel_group.py create mode 100644 manila_ui/local/enabled/_9050_manila_project_add_security_services_panel_to_share_panel_group.py rename manila_ui/{dashboards/project/shares/snapshots => tests/dashboards/project/security_services}/__init__.py (100%) rename manila_ui/tests/dashboards/project/{shares => }/security_services/tests.py (82%) rename manila_ui/tests/dashboards/project/{shares/security_services => share_networks}/__init__.py (100%) rename manila_ui/tests/dashboards/project/{shares => }/share_networks/tests.py (92%) rename manila_ui/tests/dashboards/project/{shares/share_networks => share_snapshots}/__init__.py (100%) rename manila_ui/tests/dashboards/project/{shares/snapshots => share_snapshots}/test_tables.py (94%) rename manila_ui/tests/dashboards/project/{shares/snapshots => share_snapshots}/tests.py (81%) delete mode 100644 manila_ui/tests/dashboards/project/shares/shares/__init__.py delete mode 100644 manila_ui/tests/dashboards/project/shares/shares/tests.py delete mode 100644 manila_ui/tests/dashboards/project/shares/snapshots/__init__.py rename manila_ui/tests/dashboards/project/{shares => }/test_data.py (100%) create mode 100644 manila_ui/tests/dashboards/project/tests.py create mode 100644 releasenotes/notes/add-share-panel-group-to-project-dashboard-722ab48392588728.yaml diff --git a/manila_ui/dashboards/admin/security_services/templates/security_services/index.html b/manila_ui/dashboards/admin/security_services/templates/security_services/index.html index dd0bdfc2..b33eee68 100644 --- a/manila_ui/dashboards/admin/security_services/templates/security_services/index.html +++ b/manila_ui/dashboards/admin/security_services/templates/security_services/index.html @@ -1,6 +1,6 @@ {% extends 'base.html' %} {% load i18n %} -{% block title %}{% trans "Shares" %}{% endblock %} +{% block title %}{% trans "Security Services" %}{% endblock %} {% block main %}
diff --git a/manila_ui/dashboards/admin/security_services/views.py b/manila_ui/dashboards/admin/security_services/views.py index b2f6914e..d1766e04 100644 --- a/manila_ui/dashboards/admin/security_services/views.py +++ b/manila_ui/dashboards/admin/security_services/views.py @@ -26,7 +26,7 @@ from manila_ui.api import manila import manila_ui.dashboards.admin.security_services.tables as ss_tables import manila_ui.dashboards.admin.security_services.tabs as ss_tabs from manila_ui.dashboards.admin import utils -import manila_ui.dashboards.project.shares.security_services.views as ss_views +import manila_ui.dashboards.project.security_services.views as ss_views class SecurityServicesView(tables.MultiTableView): diff --git a/manila_ui/dashboards/admin/share_networks/tables.py b/manila_ui/dashboards/admin/share_networks/tables.py index 18fbc01f..a654989a 100644 --- a/manila_ui/dashboards/admin/share_networks/tables.py +++ b/manila_ui/dashboards/admin/share_networks/tables.py @@ -14,7 +14,7 @@ from django.utils.translation import ugettext_lazy as _ from horizon import tables import six -import manila_ui.dashboards.project.shares.share_networks.tables as sn_tables +import manila_ui.dashboards.project.share_networks.tables as sn_tables class ShareNetworksTable(tables.DataTable): diff --git a/manila_ui/dashboards/admin/share_networks/views.py b/manila_ui/dashboards/admin/share_networks/views.py index 7a2842e2..cf3d7c1f 100644 --- a/manila_ui/dashboards/admin/share_networks/views.py +++ b/manila_ui/dashboards/admin/share_networks/views.py @@ -28,7 +28,7 @@ from manila_ui.api import manila from manila_ui.dashboards.admin.share_networks import tables as sn_tables from manila_ui.dashboards.admin.share_networks import tabs as sn_tabs from manila_ui.dashboards.admin import utils -import manila_ui.dashboards.project.shares.share_networks.views as p_views +from manila_ui.dashboards.project.share_networks import views as p_views class ShareNetworksView(tables.MultiTableView): diff --git a/manila_ui/dashboards/admin/share_snapshots/tables.py b/manila_ui/dashboards/admin/share_snapshots/tables.py index 7316198b..9d0815fa 100644 --- a/manila_ui/dashboards/admin/share_snapshots/tables.py +++ b/manila_ui/dashboards/admin/share_snapshots/tables.py @@ -20,8 +20,8 @@ from horizon import exceptions from horizon import tables from manila_ui.api import manila -from manila_ui.dashboards.project.shares.shares import tables as shares_tables -import manila_ui.dashboards.project.shares.snapshots.tables as ss_tables +import manila_ui.dashboards.project.share_snapshots.tables as ss_tables +from manila_ui.dashboards.project.shares import tables as shares_tables def get_size(share): @@ -118,7 +118,7 @@ class ShareSnapshotsTable(tables.DataTable): name = "share_snapshots" verbose_name = _("Share Snapshots") status_columns = ["status"] - row_class = ss_tables.UpdateRow + row_class = ss_tables.UpdateShareSnapshotRow table_actions = ( tables.NameFilterAction, DeleteShareSnapshot, diff --git a/manila_ui/dashboards/admin/share_snapshots/views.py b/manila_ui/dashboards/admin/share_snapshots/views.py index 61868802..5fc31f11 100644 --- a/manila_ui/dashboards/admin/share_snapshots/views.py +++ b/manila_ui/dashboards/admin/share_snapshots/views.py @@ -26,7 +26,7 @@ from manila_ui.api import manila from manila_ui.dashboards.admin.share_snapshots import tables as ss_tables from manila_ui.dashboards.admin.share_snapshots import tabs as ss_tabs from manila_ui.dashboards.admin import utils -import manila_ui.dashboards.project.shares.snapshots.views as snapshot_views +import manila_ui.dashboards.project.share_snapshots.views as snapshot_views class ShareSnapshotsView(tables.MultiTableView): @@ -57,7 +57,7 @@ class ShareSnapshotsView(tables.MultiTableView): return snapshots -class ShareSnapshotDetailView(snapshot_views.SnapshotDetailView): +class ShareSnapshotDetailView(snapshot_views.ShareSnapshotDetailView): tab_group_class = ss_tabs.SnapshotDetailTabs template_name = "admin/share_snapshots/detail.html" redirect_url = reverse_lazy("horizon:admin:share_snapshots:index") diff --git a/manila_ui/dashboards/admin/shares/tables.py b/manila_ui/dashboards/admin/shares/tables.py index 78de7b17..32a66570 100644 --- a/manila_ui/dashboards/admin/shares/tables.py +++ b/manila_ui/dashboards/admin/shares/tables.py @@ -15,7 +15,7 @@ from django.utils.translation import ugettext_lazy as _ from horizon import tables from manila_ui.api import manila -from manila_ui.dashboards.project.shares.shares import tables as shares_tables +from manila_ui.dashboards.project.shares import tables as shares_tables class MigrationStartAction(tables.LinkAction): diff --git a/manila_ui/dashboards/admin/shares/views.py b/manila_ui/dashboards/admin/shares/views.py index ae3f7870..c2004910 100644 --- a/manila_ui/dashboards/admin/shares/views.py +++ b/manila_ui/dashboards/admin/shares/views.py @@ -29,7 +29,7 @@ from manila_ui.dashboards.admin.shares import forms as project_forms from manila_ui.dashboards.admin.shares import tables as s_tables from manila_ui.dashboards.admin.shares import tabs as s_tabs from manila_ui.dashboards.admin import utils -from manila_ui.dashboards.project.shares.shares import views as share_views +from manila_ui.dashboards.project.shares import views as share_views class SharesView(tables.MultiTableView, share_views.ShareTableMixIn): diff --git a/manila_ui/dashboards/project/shares/security_services/__init__.py b/manila_ui/dashboards/project/security_services/__init__.py similarity index 100% rename from manila_ui/dashboards/project/shares/security_services/__init__.py rename to manila_ui/dashboards/project/security_services/__init__.py diff --git a/manila_ui/dashboards/project/shares/security_services/forms.py b/manila_ui/dashboards/project/security_services/forms.py similarity index 98% rename from manila_ui/dashboards/project/shares/security_services/forms.py rename to manila_ui/dashboards/project/security_services/forms.py index ee8dcbd2..2384a82e 100644 --- a/manila_ui/dashboards/project/shares/security_services/forms.py +++ b/manila_ui/dashboards/project/security_services/forms.py @@ -18,7 +18,6 @@ from django.forms import ValidationError # noqa from django.template.defaultfilters import filesizeformat # noqa from django.utils.translation import ugettext_lazy as _ from django.views.decorators.debug import sensitive_variables # noqa - from horizon import exceptions from horizon import forms from horizon import messages @@ -88,7 +87,7 @@ class Update(forms.SelfHandlingForm): messages.success(request, message) return True except Exception: - redirect = reverse("horizon:project:shares:index") + redirect = reverse("horizon:project:security_services:index") exceptions.handle(request, _('Unable to update security service.'), redirect=redirect) diff --git a/manila_ui/dashboards/project/security_services/panel.py b/manila_ui/dashboards/project/security_services/panel.py new file mode 100644 index 00000000..fe89f57d --- /dev/null +++ b/manila_ui/dashboards/project/security_services/panel.py @@ -0,0 +1,28 @@ +# Copyright 2017 Mirantis, Inc. +# +# 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 _ +import horizon +from openstack_dashboard.dashboards.project import dashboard + + +class SecurityServices(horizon.Panel): + name = _("Security Services") + slug = 'security_services' + permissions = ( + 'openstack.services.share', + ) + + +dashboard.Project.register(SecurityServices) diff --git a/manila_ui/dashboards/project/shares/security_services/tables.py b/manila_ui/dashboards/project/security_services/tables.py similarity index 90% rename from manila_ui/dashboards/project/shares/security_services/tables.py rename to manila_ui/dashboards/project/security_services/tables.py index 669c72c1..fcbc65de 100644 --- a/manila_ui/dashboards/project/shares/security_services/tables.py +++ b/manila_ui/dashboards/project/security_services/tables.py @@ -22,7 +22,7 @@ from manila_ui.api import manila class Create(tables.LinkAction): name = "create_security_service" verbose_name = _("Create Security Service") - url = "horizon:project:shares:create_security_service" + url = "horizon:project:security_services:security_service_create" classes = ("ajax-modal", "btn-create") icon = "plus" policy_rules = (("share", "security_service:create"),) @@ -54,15 +54,15 @@ class Delete(tables.DeleteAction): class Edit(tables.LinkAction): name = "edit" verbose_name = _("Edit Security Service") - url = "horizon:project:shares:update_security_service" + url = "horizon:project:security_services:security_service_update" classes = ("ajax-modal", "btn-create") policy_rules = (("share", "security_service:update"),) -class SecurityServiceTable(tables.DataTable): +class SecurityServicesTable(tables.DataTable): name = tables.WrappingColumn( "name", verbose_name=_("Name"), - link="horizon:project:shares:security_service_detail") + link="horizon:project:security_services:security_service_detail") dns_ip = tables.Column("dns_ip", verbose_name=_("DNS IP")) server = tables.Column("server", verbose_name=_("Server")) domain = tables.Column("domain", verbose_name=_("Domain")) diff --git a/manila_ui/dashboards/project/shares/security_services/tabs.py b/manila_ui/dashboards/project/security_services/tabs.py similarity index 52% rename from manila_ui/dashboards/project/shares/security_services/tabs.py rename to manila_ui/dashboards/project/security_services/tabs.py index 5c2a5ec5..fbdacd23 100644 --- a/manila_ui/dashboards/project/shares/security_services/tabs.py +++ b/manila_ui/dashboards/project/security_services/tabs.py @@ -12,37 +12,13 @@ # under the License. from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions from horizon import tabs -from manila_ui.api import manila - -from manila_ui.dashboards.project.shares.security_services \ - import tables as security_services_tables - - -class SecurityServiceTab(tabs.TableTab): - table_classes = (security_services_tables.SecurityServiceTable,) - name = _("Security Services") - slug = "security_services_tab" - template_name = "horizon/common/_detail_table.html" - - def get_security_services_data(self): - try: - security_services = manila.security_service_list(self.request) - except Exception: - security_services = [] - exceptions.handle(self.request, - _("Unable to retrieve security services")) - - return security_services - class OverviewTab(tabs.Tab): name = _("Overview") slug = "overview" - template_name = ("project/shares/security_services/_detail_overview.html") + template_name = ("project/security_services/_detail.html") def get_context_data(self, request): return {"sec_service": self.tab_group.kwargs['sec_service']} @@ -50,4 +26,6 @@ class OverviewTab(tabs.Tab): class SecurityServiceDetailTabs(tabs.TabGroup): slug = "security_service_details" - tabs = (OverviewTab,) + tabs = ( + OverviewTab, + ) diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/_add_security_service.html b/manila_ui/dashboards/project/security_services/templates/security_services/_add.html similarity index 86% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/_add_security_service.html rename to manila_ui/dashboards/project/security_services/templates/security_services/_add.html index a241a9c4..bf582847 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/security_services/_add_security_service.html +++ b/manila_ui/dashboards/project/security_services/templates/security_services/_add.html @@ -2,7 +2,7 @@ {% load i18n %} {% block form_id %}{% endblock %} -{% block form_action %}{% url 'horizon:project:shares:add_security_service' share_network.id %}{% endblock %} +{% block form_action %}{% url 'horizon:project:security_service:add_security_service' share_network.id %}{% endblock %} {% block modal_id %}add_security_service_modal{% endblock %} {% block modal-header %}{% trans "Add Security Service" %}{% endblock %} @@ -56,5 +56,5 @@ {% block modal-footer %} - {% trans "Cancel" %} + {% trans "Cancel" %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/_create_security_service.html b/manila_ui/dashboards/project/security_services/templates/security_services/_create.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/_create_security_service.html rename to manila_ui/dashboards/project/security_services/templates/security_services/_create.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/_detail_overview.html b/manila_ui/dashboards/project/security_services/templates/security_services/_detail.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/_detail_overview.html rename to manila_ui/dashboards/project/security_services/templates/security_services/_detail.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/_update.html b/manila_ui/dashboards/project/security_services/templates/security_services/_update.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/_update.html rename to manila_ui/dashboards/project/security_services/templates/security_services/_update.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/add_security_service.html b/manila_ui/dashboards/project/security_services/templates/security_services/add.html similarity index 64% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/add_security_service.html rename to manila_ui/dashboards/project/security_services/templates/security_services/add.html index 42ba935f..df3c7792 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/security_services/add_security_service.html +++ b/manila_ui/dashboards/project/security_services/templates/security_services/add.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Create Security Service" %}{% endblock %} {% block main %} - {% include 'project/shares/security_services/_add_security_service.html' %} + {% include 'project/security_services/_add.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/create_security_service.html b/manila_ui/dashboards/project/security_services/templates/security_services/create.html similarity index 63% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/create_security_service.html rename to manila_ui/dashboards/project/security_services/templates/security_services/create.html index ace9c337..5ed94193 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/security_services/create_security_service.html +++ b/manila_ui/dashboards/project/security_services/templates/security_services/create.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Create Security Service" %}{% endblock %} {% block main %} - {% include 'project/shares/security_services/_create_security_service.html' %} + {% include 'project/security_services/_create.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/detail.html b/manila_ui/dashboards/project/security_services/templates/security_services/detail.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/detail.html rename to manila_ui/dashboards/project/security_services/templates/security_services/detail.html diff --git a/manila_ui/dashboards/project/security_services/templates/security_services/index.html b/manila_ui/dashboards/project/security_services/templates/security_services/index.html new file mode 100644 index 00000000..b33eee68 --- /dev/null +++ b/manila_ui/dashboards/project/security_services/templates/security_services/index.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Security Services" %}{% endblock %} + +{% block main %} +
+
+ {{ security_services_table.render }} +
+
+{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/security_services/update.html b/manila_ui/dashboards/project/security_services/templates/security_services/update.html similarity index 68% rename from manila_ui/dashboards/project/shares/templates/shares/security_services/update.html rename to manila_ui/dashboards/project/security_services/templates/security_services/update.html index 61247a2f..b23b204d 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/security_services/update.html +++ b/manila_ui/dashboards/project/security_services/templates/security_services/update.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Edit Security Service" %}{% endblock %} {% block main %} - {% include 'project/shares/security_services/_update.html' %} + {% include 'project/security_services/_update.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/security_services/urls.py b/manila_ui/dashboards/project/security_services/urls.py new file mode 100644 index 00000000..0b2b8a19 --- /dev/null +++ b/manila_ui/dashboards/project/security_services/urls.py @@ -0,0 +1,37 @@ +# Copyright 2012 Nebula, Inc. +# +# 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.conf import urls + +from manila_ui.dashboards.project.security_services import views + + +urlpatterns = [ + urls.url( + r'^$', + views.SecurityServicesView.as_view(), + name='index'), + urls.url( + r'^create_security_service$', + views.CreateView.as_view(), + name='security_service_create'), + urls.url( + r'^(?P[^/]+)/update/$', + views.UpdateView.as_view(), + name='security_service_update'), + urls.url( + r'^(?P[^/]+)$', + views.Detail.as_view(), + name='security_service_detail'), +] diff --git a/manila_ui/dashboards/project/shares/security_services/views.py b/manila_ui/dashboards/project/security_services/views.py similarity index 71% rename from manila_ui/dashboards/project/shares/security_services/views.py rename to manila_ui/dashboards/project/security_services/views.py index b9b45e81..5ee9aaf5 100644 --- a/manila_ui/dashboards/project/shares/security_services/views.py +++ b/manila_ui/dashboards/project/security_services/views.py @@ -15,31 +15,48 @@ from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse_lazy from django.utils.translation import ugettext_lazy as _ - from horizon import exceptions from horizon import forms +from horizon import tables from horizon import tabs from horizon.utils import memoized from manila_ui.api import manila -from manila_ui.dashboards.project.shares.security_services import\ - forms as sec_services_forms -from manila_ui.dashboards.project.shares.security_services \ - import tabs as security_services_tabs -from manila_ui.dashboards.project.shares.share_networks import forms\ - as share_net_forms +from manila_ui.dashboards.project.security_services import forms as ss_forms +from manila_ui.dashboards.project.security_services import tables as ss_tables +from manila_ui.dashboards.project.security_services import tabs as ss_tabs +from manila_ui.dashboards.project.share_networks import forms as sn_forms from manila_ui.dashboards import utils +class SecurityServicesView(tables.MultiTableView): + table_classes = ( + ss_tables.SecurityServicesTable, + ) + template_name = "project/security_services/index.html" + page_title = _("Security Services") + + @memoized.memoized_method + def get_security_services_data(self): + try: + security_services = manila.security_service_list(self.request) + except Exception: + security_services = [] + exceptions.handle( + self.request, _("Unable to retrieve security services")) + + return security_services + + class UpdateView(forms.ModalFormView): - template_name = "project/shares/security_services/update.html" - form_class = sec_services_forms.Update + template_name = "project/security_services/update.html" + form_class = ss_forms.Update form_id = "update_security_service" modal_header = _("Edit Security Service") modal_id = "update_security_service_modal" submit_label = _("Edit") - submit_url = "horizon:project:shares:update_security_service" - success_url = 'horizon:project:shares:index' + submit_url = "horizon:project:security_services:security_service_update" + success_url = 'horizon:project:security_services:index' page_title = _('Edit Security Service') def get_success_url(self): @@ -53,7 +70,7 @@ class UpdateView(forms.ModalFormView): self.request, sec_service_id) except Exception: msg = _('Unable to retrieve security_service.') - url = reverse('horizon:project:shares:index') + url = reverse('horizon:project:security_services:index') exceptions.handle(self.request, msg, redirect=url) return self._object @@ -70,15 +87,15 @@ class UpdateView(forms.ModalFormView): class CreateView(forms.ModalFormView): - form_class = sec_services_forms.Create + form_class = ss_forms.Create form_id = "create_security_service" - template_name = ('project/shares/security_services' - '/create_security_service.html') + template_name = 'project/security_services/create.html' modal_header = _("Create Security Service") modal_id = "create_security_service_modal" submit_label = _("Create") - submit_url = reverse_lazy("horizon:project:shares:create_security_service") - success_url = 'horizon:project:shares:index' + submit_url = reverse_lazy( + "horizon:project:security_services:security_service_create") + success_url = 'horizon:project:security_services:index' page_title = _('Create Security Service') def get_success_url(self): @@ -86,10 +103,9 @@ class CreateView(forms.ModalFormView): class AddSecurityServiceView(forms.ModalFormView): - form_class = share_net_forms.AddSecurityServiceForm - template_name = ('project/shares/security_services' - '/add_security_service.html') - success_url = 'horizon:project:shares:index' + form_class = sn_forms.AddSecurityServiceForm + template_name = 'project/security_services/add.html' + success_url = 'horizon:project:security_services:index' page_title = _('Add Security Service') def get_object(self): @@ -99,7 +115,7 @@ class AddSecurityServiceView(forms.ModalFormView): self._object = manila.share_network_get(self.request, share_id) except Exception: msg = _('Unable to retrieve share network.') - url = reverse('horizon:project:shares:index') + url = reverse('horizon:project:security_services:index') exceptions.handle(self.request, msg, redirect=url) return self._object @@ -117,9 +133,9 @@ class AddSecurityServiceView(forms.ModalFormView): class Detail(tabs.TabView): - tab_group_class = security_services_tabs.SecurityServiceDetailTabs - template_name = 'project/shares/security_services/detail.html' - redirect_url = reverse_lazy('horizon:project:shares:index') + tab_group_class = ss_tabs.SecurityServiceDetailTabs + template_name = 'project/security_services/detail.html' + redirect_url = reverse_lazy('horizon:project:security_services:index') def get_context_data(self, **kwargs): context = super(Detail, self).get_context_data(**kwargs) diff --git a/manila_ui/dashboards/project/shares/share_networks/__init__.py b/manila_ui/dashboards/project/share_networks/__init__.py similarity index 100% rename from manila_ui/dashboards/project/shares/share_networks/__init__.py rename to manila_ui/dashboards/project/share_networks/__init__.py diff --git a/manila_ui/dashboards/project/shares/share_networks/forms.py b/manila_ui/dashboards/project/share_networks/forms.py similarity index 99% rename from manila_ui/dashboards/project/shares/share_networks/forms.py rename to manila_ui/dashboards/project/share_networks/forms.py index dd02c485..f5314e24 100644 --- a/manila_ui/dashboards/project/shares/share_networks/forms.py +++ b/manila_ui/dashboards/project/share_networks/forms.py @@ -17,18 +17,16 @@ from django.core.urlresolvers import reverse from django.forms import ValidationError # noqa from django.template.defaultfilters import filesizeformat # noqa from django.utils.translation import ugettext_lazy as _ - from horizon import exceptions from horizon import forms from horizon import messages from horizon.utils.memoized import memoized # noqa +from openstack_dashboard.api import base +from openstack_dashboard.api import neutron from manila_ui.api import manila from manila_ui.api import network -from openstack_dashboard.api import base -from openstack_dashboard.api import neutron - class Create(forms.SelfHandlingForm): name = forms.CharField(max_length="255", label=_("Name")) diff --git a/manila_ui/dashboards/project/share_networks/panel.py b/manila_ui/dashboards/project/share_networks/panel.py new file mode 100644 index 00000000..83efd63f --- /dev/null +++ b/manila_ui/dashboards/project/share_networks/panel.py @@ -0,0 +1,28 @@ +# Copyright 2017 Mirantis, Inc. +# +# 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 _ +import horizon +from openstack_dashboard.dashboards.project import dashboard + + +class ShareNetworks(horizon.Panel): + name = _("Share Networks") + slug = 'share_networks' + permissions = ( + 'openstack.services.share', + ) + + +dashboard.Project.register(ShareNetworks) diff --git a/manila_ui/dashboards/project/shares/share_networks/tables.py b/manila_ui/dashboards/project/share_networks/tables.py similarity index 71% rename from manila_ui/dashboards/project/shares/share_networks/tables.py rename to manila_ui/dashboards/project/share_networks/tables.py index 1ac8a747..87c080ca 100644 --- a/manila_ui/dashboards/project/shares/share_networks/tables.py +++ b/manila_ui/dashboards/project/share_networks/tables.py @@ -18,15 +18,13 @@ from django.utils.translation import pgettext_lazy from django.utils.translation import string_concat # noqa from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy - from horizon import tables +from openstack_dashboard.api import base +from openstack_dashboard.api import neutron from manila_ui.api import manila from manila_ui.api import network -from openstack_dashboard.api import base -from openstack_dashboard.api import neutron - DELETABLE_STATES = ("INACTIVE", "ERROR") EDITABLE_STATES = ("INACTIVE", ) @@ -35,7 +33,7 @@ EDITABLE_STATES = ("INACTIVE", ) class Create(tables.LinkAction): name = "create_share_network" verbose_name = _("Create Share Network") - url = "horizon:project:shares:create_share_network" + url = "horizon:project:share_networks:share_network_create" classes = ("ajax-modal", "btn-create") icon = "plus" policy_rules = (("share", "share_network:create"),) @@ -74,7 +72,7 @@ class Delete(tables.DeleteAction): class EditShareNetwork(tables.LinkAction): name = "edit" verbose_name = _("Edit Share Network") - url = "horizon:project:shares:update_share_network" + url = "horizon:project:share_networks:share_network_update" classes = ("ajax-modal", "btn-create") policy_rules = (("share", "share_network:update"),) @@ -102,36 +100,6 @@ class UpdateRow(tables.Row): return share_net -class NovaShareNetworkTable(tables.DataTable): - name = tables.WrappingColumn( - "name", verbose_name=_("Name"), - link="horizon:project:shares:share_network_detail") - nova_net = tables.Column("nova_net", verbose_name=_("Nova Net")) - ip_version = tables.Column("ip_version", verbose_name=_("IP Version")) - network_type = tables.Column("network_type", - verbose_name=_("Network Type")) - segmentation_id = tables.Column("segmentation_id", - verbose_name=_("Segmentation Id")) - - def get_object_display(self, share_network): - return share_network.name or str(share_network.id) - - def get_object_id(self, share_network): - return str(share_network.id) - - class Meta(object): - name = "share_networks" - verbose_name = _("Share Networks") - table_actions = ( - tables.NameFilterAction, - Create, - Delete) - row_class = UpdateRow - row_actions = ( - EditShareNetwork, - Delete) - - class ShareNetworksTable(tables.DataTable): STATUS_CHOICES = ( ("ACTIVE", True), @@ -147,20 +115,15 @@ class ShareNetworksTable(tables.DataTable): ) name = tables.WrappingColumn( "name", verbose_name=_("Name"), - link="horizon:project:shares:share_network_detail") + link="horizon:project:share_networks:share_network_detail") neutron_net = tables.Column("neutron_net", verbose_name=_("Neutron Net")) neutron_subnet = tables.Column( "neutron_subnet", verbose_name=_("Neutron Subnet")) ip_version = tables.Column("ip_version", verbose_name=_("IP Version")) - network_type = tables.Column("network_type", - verbose_name=_("Network Type")) - segmentation_id = tables.Column("segmentation_id", - verbose_name=_("Segmentation Id")) - # NOTE: disable status column until it become used - # status = tables.Column("status", verbose_name=_("Status"), - # status=True, - # status_choices=STATUS_CHOICES) - # display_choices=STATUS_DISPLAY_CHOICES) + network_type = tables.Column( + "network_type", verbose_name=_("Network Type")) + segmentation_id = tables.Column( + "segmentation_id", verbose_name=_("Segmentation Id")) def get_object_display(self, share_network): return share_network.name or str(share_network.id) @@ -174,9 +137,10 @@ class ShareNetworksTable(tables.DataTable): table_actions = ( tables.NameFilterAction, Create, - Delete) - # status_columns = ["status"] + Delete, + ) row_class = UpdateRow row_actions = ( EditShareNetwork, - Delete) + Delete, + ) diff --git a/manila_ui/dashboards/project/share_networks/tabs.py b/manila_ui/dashboards/project/share_networks/tabs.py new file mode 100644 index 00000000..709a58f9 --- /dev/null +++ b/manila_ui/dashboards/project/share_networks/tabs.py @@ -0,0 +1,31 @@ +# +# 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 tabs + + +class OverviewTab(tabs.Tab): + name = _("Overview") + slug = "overview" + template_name = "project/share_networks/_detail.html" + + def get_context_data(self, request): + return {"share_network": self.tab_group.kwargs['share_network']} + + +class ShareNetworkDetailTabs(tabs.TabGroup): + slug = "share_network_details" + tabs = ( + OverviewTab, + ) diff --git a/manila_ui/dashboards/project/shares/templates/shares/share_networks/_create_share_network.html b/manila_ui/dashboards/project/share_networks/templates/share_networks/_create.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/share_networks/_create_share_network.html rename to manila_ui/dashboards/project/share_networks/templates/share_networks/_create.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/share_networks/_detail_overview.html b/manila_ui/dashboards/project/share_networks/templates/share_networks/_detail.html similarity index 77% rename from manila_ui/dashboards/project/shares/templates/shares/share_networks/_detail_overview.html rename to manila_ui/dashboards/project/share_networks/templates/share_networks/_detail.html index 354c7f19..51858c01 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/share_networks/_detail_overview.html +++ b/manila_ui/dashboards/project/share_networks/templates/share_networks/_detail.html @@ -12,13 +12,6 @@
{% trans "Description" %}
{{ share_network.description }}
{% endif %} - {% if share_network.share_servers %} -
{% trans "Share Servers" %}
- {% for server in share_network.share_servers %} - {% url 'horizon:admin:shares:share_server_detail' server.id as server_url %} -
{{ server.id }}
- {% endfor %} - {% endif %}
@@ -42,7 +35,7 @@

{% trans "Security Services" %}


{% for sec_service in share_network.sec_services %} - {% url 'horizon:project:shares:security_service_detail' sec_service.id as sec_service_url%} + {% url 'horizon:project:security_services:security_service_detail' sec_service.id as sec_service_url%}
{% trans "Id" %}
{{ sec_service.id }}
diff --git a/manila_ui/dashboards/project/shares/templates/shares/share_networks/_share_network_update.html b/manila_ui/dashboards/project/share_networks/templates/share_networks/_update.html similarity index 74% rename from manila_ui/dashboards/project/shares/templates/shares/share_networks/_share_network_update.html rename to manila_ui/dashboards/project/share_networks/templates/share_networks/_update.html index 228e4dd1..021a617d 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/share_networks/_share_network_update.html +++ b/manila_ui/dashboards/project/share_networks/templates/share_networks/_update.html @@ -2,7 +2,7 @@ {% load i18n %} {% block form_id %}{% endblock %} -{% block form_action %}{% url 'horizon:project:shares:update_share_network' share_network.id %}{% endblock %} +{% block form_action %}{% url 'horizon:project:share_networks:share_network_update' share_network.id %}{% endblock %} {% block modal_id %}update_share_network_modal{% endblock %} {% block modal-header %}{% trans "Edit Share network" %}{% endblock %} @@ -21,5 +21,5 @@ {% block modal-footer %} - {% trans "Cancel" %} + {% trans "Cancel" %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/share_networks/create_share_network.html b/manila_ui/dashboards/project/share_networks/templates/share_networks/create.html similarity index 64% rename from manila_ui/dashboards/project/shares/templates/shares/share_networks/create_share_network.html rename to manila_ui/dashboards/project/share_networks/templates/share_networks/create.html index f750449f..96d222b5 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/share_networks/create_share_network.html +++ b/manila_ui/dashboards/project/share_networks/templates/share_networks/create.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Create Share Network" %}{% endblock %} {% block main %} - {% include 'project/shares/share_networks/_create_share_network.html' %} + {% include 'project/share_networks/_create.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/detail.html b/manila_ui/dashboards/project/share_networks/templates/share_networks/detail.html similarity index 70% rename from manila_ui/dashboards/project/shares/templates/shares/shares/detail.html rename to manila_ui/dashboards/project/share_networks/templates/share_networks/detail.html index 00f595fb..208776dc 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/detail.html +++ b/manila_ui/dashboards/project/share_networks/templates/share_networks/detail.html @@ -1,6 +1,6 @@ {% extends 'base.html' %} {% load i18n %} -{% block title %}{% trans "Share Details" %}{% endblock %} +{% block title %}{% trans "Share Network Details" %}{% endblock %} {% block main %}
diff --git a/manila_ui/dashboards/project/share_networks/templates/share_networks/index.html b/manila_ui/dashboards/project/share_networks/templates/share_networks/index.html new file mode 100644 index 00000000..a9285d56 --- /dev/null +++ b/manila_ui/dashboards/project/share_networks/templates/share_networks/index.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Share Networks" %}{% endblock %} + +{% block main %} +
+
+ {{ share_networks_table.render }} +
+
+{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/share_networks/share_network_update.html b/manila_ui/dashboards/project/share_networks/templates/share_networks/update.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/share_networks/share_network_update.html rename to manila_ui/dashboards/project/share_networks/templates/share_networks/update.html diff --git a/manila_ui/dashboards/project/share_networks/urls.py b/manila_ui/dashboards/project/share_networks/urls.py new file mode 100644 index 00000000..7a8a2899 --- /dev/null +++ b/manila_ui/dashboards/project/share_networks/urls.py @@ -0,0 +1,37 @@ +# Copyright 2017 Mirantis, Inc. +# +# 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.conf import urls + +from manila_ui.dashboards.project.share_networks import views + + +urlpatterns = [ + urls.url( + r'^$', + views.ShareNetworksView.as_view(), + name='index'), + urls.url( + r'^create_share_network$', + views.Create.as_view(), + name='share_network_create'), + urls.url( + r'^(?P[^/]+)/update$', + views.Update.as_view(), + name='share_network_update'), + urls.url( + r'^(?P[^/]+)$', + views.Detail.as_view(), + name='share_network_detail'), +] diff --git a/manila_ui/dashboards/project/shares/share_networks/views.py b/manila_ui/dashboards/project/share_networks/views.py similarity index 67% rename from manila_ui/dashboards/project/shares/share_networks/views.py rename to manila_ui/dashboards/project/share_networks/views.py index 2080c582..ad00d7c8 100644 --- a/manila_ui/dashboards/project/shares/share_networks/views.py +++ b/manila_ui/dashboards/project/share_networks/views.py @@ -17,28 +17,55 @@ from django.core.urlresolvers import reverse_lazy from django.utils.translation import ugettext_lazy as _ from horizon import exceptions from horizon import forms +from horizon import tables from horizon import tabs from horizon.utils import memoized from horizon import workflows - -from manila_ui.api import manila -from manila_ui.api import network -from manila_ui.dashboards.project.shares.share_networks import forms \ - as share_net_forms -from manila_ui.dashboards.project.shares.share_networks import tabs \ - as share_net_tabs -from manila_ui.dashboards.project.shares.share_networks \ - import workflows as share_net_workflows -from manila_ui.dashboards import utils - from openstack_dashboard.api import base from openstack_dashboard.api import neutron +from manila_ui.api import manila +from manila_ui.api import network +from manila_ui.dashboards.project.share_networks import forms as sn_forms +from manila_ui.dashboards.project.share_networks import tables as sn_tables +from manila_ui.dashboards.project.share_networks import tabs as sn_tabs +import manila_ui.dashboards.project.share_networks.workflows as sn_workflows +from manila_ui.dashboards import utils + + +class ShareNetworksView(tables.MultiTableView): + table_classes = ( + sn_tables.ShareNetworksTable, + ) + template_name = "admin/share_networks/index.html" + page_title = _("Share Networks") + + @memoized.memoized_method + def get_share_networks_data(self): + try: + share_networks = manila.share_network_list( + self.request, detailed=True) + if base.is_service_enabled(self.request, 'network'): + neutron_net_names = dict((net.id, net.name) for net in + neutron.network_list(self.request)) + neutron_subnet_names = dict((net.id, net.name) for net in + neutron.subnet_list(self.request)) + for sn in share_networks: + sn.neutron_net = neutron_net_names.get( + sn.neutron_net_id) or sn.neutron_net_id or "-" + sn.neutron_subnet = neutron_subnet_names.get( + sn.neutron_subnet_id) or sn.neutron_subnet_id or "-" + except Exception: + share_networks = [] + exceptions.handle( + self.request, _("Unable to retrieve share networks")) + return share_networks + class Update(workflows.WorkflowView): - workflow_class = share_net_workflows.UpdateShareNetworkWorkflow - template_name = "project/shares/share_networks/share_network_update.html" - success_url = 'horizon:project:shares:index' + workflow_class = sn_workflows.UpdateShareNetworkWorkflow + template_name = "project/share_networks/update.html" + success_url = 'horizon:project:share_networks:index' page_title = _('Update Share Network') def get_initial(self): @@ -51,13 +78,14 @@ class Update(workflows.WorkflowView): class Create(forms.ModalFormView): - form_class = share_net_forms.Create + form_class = sn_forms.Create form_id = "create_share_network" - template_name = 'project/shares/share_networks/create_share_network.html' + template_name = 'project/share_networks/create.html' modal_header = _("Create Share Network") submit_label = _("Create") - submit_url = reverse_lazy("horizon:project:shares:create_share_network") - success_url = 'horizon:project:shares:index' + submit_url = reverse_lazy( + "horizon:project:share_networks:share_network_create") + success_url = 'horizon:project:share_networks:index' page_title = _('Create Share Network') def get_success_url(self): @@ -65,9 +93,9 @@ class Create(forms.ModalFormView): class Detail(tabs.TabView): - tab_group_class = share_net_tabs.ShareNetworkDetailTabs - template_name = 'project/shares/share_networks/detail.html' - redirect_url = reverse_lazy('horizon:project:shares:index') + tab_group_class = sn_tabs.ShareNetworkDetailTabs + template_name = 'project/share_networks/detail.html' + redirect_url = reverse_lazy('horizon:project:share_networks:index') def get_context_data(self, **kwargs): context = super(Detail, self).get_context_data(**kwargs) diff --git a/manila_ui/dashboards/project/shares/share_networks/workflows.py b/manila_ui/dashboards/project/share_networks/workflows.py similarity index 99% rename from manila_ui/dashboards/project/shares/share_networks/workflows.py rename to manila_ui/dashboards/project/share_networks/workflows.py index 6e713b9d..03802f62 100644 --- a/manila_ui/dashboards/project/shares/share_networks/workflows.py +++ b/manila_ui/dashboards/project/share_networks/workflows.py @@ -112,7 +112,7 @@ class UpdateShareNetworkWorkflow(workflows.Workflow): finalize_button_name = _("Update Share Network") success_message = _('Updated share network "%s".') failure_message = _('Unable to update share network "%s".') - success_url = 'horizon:project:shares:index' + success_url = 'horizon:project:share_networks:index' default_steps = (UpdateShareNetworkInfoStep, AddSecurityServiceStep) def format_status_message(self, message): diff --git a/manila_ui/dashboards/project/shares/shares/__init__.py b/manila_ui/dashboards/project/share_snapshots/__init__.py similarity index 100% rename from manila_ui/dashboards/project/shares/shares/__init__.py rename to manila_ui/dashboards/project/share_snapshots/__init__.py diff --git a/manila_ui/dashboards/project/shares/snapshots/forms.py b/manila_ui/dashboards/project/share_snapshots/forms.py similarity index 74% rename from manila_ui/dashboards/project/shares/snapshots/forms.py rename to manila_ui/dashboards/project/share_snapshots/forms.py index 591c2a5a..3328dc75 100644 --- a/manila_ui/dashboards/project/shares/snapshots/forms.py +++ b/manila_ui/dashboards/project/share_snapshots/forms.py @@ -14,7 +14,7 @@ # under the License. """ -Views for managing snapshots. +Views for managing share snapshots. """ from django.core.urlresolvers import reverse @@ -22,7 +22,6 @@ from django.forms import ValidationError # noqa from django.template.defaultfilters import filesizeformat # noqa from django.utils.http import urlencode # noqa from django.utils.translation import ugettext_lazy as _ - from horizon import exceptions from horizon import forms from horizon import messages @@ -30,19 +29,18 @@ from horizon import messages from manila_ui.api import manila -class CreateSnapshotForm(forms.SelfHandlingForm): - name = forms.CharField(max_length="255", label=_("Snapshot Name")) +class CreateShareSnapshotForm(forms.SelfHandlingForm): + name = forms.CharField(max_length="255", label=_("Share Snapshot Name")) description = forms.CharField( widget=forms.Textarea, label=_("Description"), required=False) def __init__(self, request, *args, **kwargs): - super(CreateSnapshotForm, self).__init__(request, *args, **kwargs) - + super(self.__class__, self).__init__(request, *args, **kwargs) # populate share_id share_id = kwargs.get('initial', {}).get('share_id', []) - self.fields['share_id'] = forms.CharField(widget=forms.HiddenInput(), - initial=share_id) + self.fields['share_id'] = forms.CharField( + widget=forms.HiddenInput(), initial=share_id) def handle(self, request, data): try: @@ -52,30 +50,30 @@ class CreateSnapshotForm(forms.SelfHandlingForm): messages.success(request, message) return snapshot except Exception: - redirect = reverse("horizon:project:shares:index") + redirect = reverse("horizon:project:share_snapshots:index") exceptions.handle(request, _('Unable to create share snapshot.'), redirect=redirect) -class UpdateForm(forms.SelfHandlingForm): - name = forms.CharField(max_length="255", label=_("Snapshot Name")) - description = forms.CharField(widget=forms.Textarea, - label=_("Description"), required=False) +class UpdateShareSnapshotForm(forms.SelfHandlingForm): + name = forms.CharField(max_length="255", label=_("Share Snapshot Name")) + description = forms.CharField( + widget=forms.Textarea, label=_("Description"), required=False) def handle(self, request, data): snapshot_id = self.initial['snapshot_id'] try: manila.share_snapshot_update( request, snapshot_id, data['name'], data['description']) - message = _('Updating snapshot "%s"') % data['name'] + message = _('Updating share snapshot "%s"') % data['name'] messages.success(request, message) return True except Exception: - exceptions.handle(request, _('Unable to update snapshot.')) + exceptions.handle(request, _('Unable to update share snapshot.')) -class AddRule(forms.SelfHandlingForm): +class AddShareSnapshotRule(forms.SelfHandlingForm): access_type = forms.ChoiceField( label=_("Access Type"), required=True, choices=(('ip', 'ip'), ('user', 'user'), ('cephx', 'cephx'), @@ -94,7 +92,8 @@ class AddRule(forms.SelfHandlingForm): messages.success(request, message) return True except Exception: - redirect = reverse("horizon:project:shares:snapshot_manage_rules", - args=[self.initial['snapshot_id']]) + redirect = reverse( + "horizon:project:share_snapshots:share_snapshot_manage_rules", + args=[self.initial['snapshot_id']]) exceptions.handle( request, _('Unable to add snapshot rule.'), redirect=redirect) diff --git a/manila_ui/dashboards/project/share_snapshots/panel.py b/manila_ui/dashboards/project/share_snapshots/panel.py new file mode 100644 index 00000000..8b074ad8 --- /dev/null +++ b/manila_ui/dashboards/project/share_snapshots/panel.py @@ -0,0 +1,28 @@ +# Copyright 2017 Mirantis, Inc. +# +# 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 _ +import horizon +from openstack_dashboard.dashboards.project import dashboard + + +class ShareSnapshots(horizon.Panel): + name = _("Share Snapshots") + slug = 'share_snapshots' + permissions = ( + 'openstack.services.share', + ) + + +dashboard.Project.register(ShareSnapshots) diff --git a/manila_ui/dashboards/project/shares/snapshots/tables.py b/manila_ui/dashboards/project/share_snapshots/tables.py similarity index 69% rename from manila_ui/dashboards/project/shares/snapshots/tables.py rename to manila_ui/dashboards/project/share_snapshots/tables.py index e7947070..fa918588 100644 --- a/manila_ui/dashboards/project/shares/snapshots/tables.py +++ b/manila_ui/dashboards/project/share_snapshots/tables.py @@ -20,18 +20,17 @@ from django.utils.translation import pgettext_lazy from django.utils.translation import string_concat # noqa 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 -from openstack_dashboard.usage import quotas DELETABLE_STATES = ("available", "error") -class UpdateRow(tables.Row): +class UpdateShareSnapshotRow(tables.Row): ajax = True def get_data(self, request, snapshot_id): @@ -45,10 +44,10 @@ def get_size(snapshot): return _("%sGiB") % snapshot.size -class CreateSnapshot(tables.LinkAction): - name = "snapshots" - verbose_name = _("Create Snapshot") - url = "horizon:project:shares:create_snapshot" +class CreateShareSnapshot(tables.LinkAction): + name = "create_share_snapshot" + verbose_name = _("Create Share Snapshot") + url = "horizon:project:share_snapshots:share_snapshot_create" classes = ("ajax-modal", "btn-camera") policy_rules = (("share", "share:create_snapshot"),) @@ -63,10 +62,10 @@ class CreateSnapshot(tables.LinkAction): if usages['snapshots']['available'] <= 0: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] - self.verbose_name = string_concat(self.verbose_name, ' ', - _("(Quota exceeded)")) + self.verbose_name = string_concat( + self.verbose_name, ' ', _("(Quota exceeded)")) else: - self.verbose_name = _("Create Snapshot") + self.verbose_name = _("Create Share Snapshot") classes = [c for c in self.classes if c != "disabled"] self.classes = classes @@ -81,22 +80,22 @@ class CreateSnapshot(tables.LinkAction): return share.status in ("available", "in-use") and snapshot_support -class DeleteSnapshot(tables.DeleteAction): +class DeleteShareSnapshot(tables.DeleteAction): policy_rules = (("share", "share:delete_snapshot"),) @staticmethod def action_present(count): return ungettext_lazy( - u"Delete Snapshot", - u"Delete Snapshots", + u"Delete Share Snapshot", + u"Delete Share Snapshots", count ) @staticmethod def action_past(count): return ungettext_lazy( - u"Deleted Snapshot", - u"Deleted Snapshots", + u"Deleted Share Snapshot", + u"Deleted Share Snapshots", count ) @@ -123,8 +122,8 @@ class DeleteSnapshot(tables.DeleteAction): return True -class CreateShareFromSnapshot(tables.LinkAction): - name = "create_from_snapshot" +class CreateShareFromShareSnapshot(tables.LinkAction): + name = "create_share_from_share_snapshot" verbose_name = _("Create Share") url = "horizon:project:shares:create" classes = ("ajax-modal", "btn-camera") @@ -139,22 +138,22 @@ class CreateShareFromSnapshot(tables.LinkAction): return share.status == "available" -class EditSnapshot(tables.LinkAction): - name = "edit_snapshot" - verbose_name = _("Edit Snapshot") - url = "horizon:project:shares:edit_snapshot" +class EditShareSnapshot(tables.LinkAction): + name = "edit_share_snapshot" + verbose_name = _("Edit Share Snapshot") + url = "horizon:project:share_snapshots:share_snapshot_edit" classes = ("ajax-modal", "btn-camera") -class SnapshotShareNameColumn(tables.Column): +class ShareSnapshotShareNameColumn(tables.Column): def get_link_url(self, snapshot): return reverse(self.link, args=(snapshot.share_id,)) -class ManageRules(tables.LinkAction): - name = "snapshot_manage_rules" - verbose_name = _("Manage Rules") - url = "horizon:project:shares:snapshot_manage_rules" +class ManageShareSnapshotRules(tables.LinkAction): + name = "share_snapshot_manage_rules" + verbose_name = _("Manage Share Snapshot Rules") + url = "horizon:project:share_snapshots:share_snapshot_manage_rules" classes = ("btn-edit",) policy_rules = (("share", "share:access_get_all"),) @@ -163,10 +162,10 @@ class ManageRules(tables.LinkAction): return share.mount_snapshot_support -class AddRule(tables.LinkAction): - name = "snapshot_rule_add" - verbose_name = _("Add rule") - url = 'horizon:project:shares:snapshot_rule_add' +class AddShareSnapshotRule(tables.LinkAction): + name = "share_snapshot_rule_add" + verbose_name = _("Add Share Snapshot Rule") + url = 'horizon:project:share_snapshots:share_snapshot_rule_add' classes = ("ajax-modal", "btn-create") icon = "plus" policy_rules = (("share", "share:allow_access"),) @@ -180,22 +179,22 @@ class AddRule(tables.LinkAction): return reverse(self.url, args=[self.table.kwargs['snapshot_id']]) -class DeleteRule(tables.DeleteAction): +class DeleteShareSnapshotRule(tables.DeleteAction): policy_rules = (("share", "share:deny_access"),) @staticmethod def action_present(count): return ungettext_lazy( - u"Delete Rule", - u"Delete Rules", + u"Delete Share Snapshot Rule", + u"Delete Share Snapshot Rules", count ) @staticmethod def action_past(count): return ungettext_lazy( - u"Deleted Rule", - u"Deleted Rules", + u"Deleted Share Snapshot Rule", + u"Deleted Share Snapshot Rules", count ) @@ -208,7 +207,7 @@ class DeleteRule(tables.DeleteAction): exceptions.handle(request, msg) -class UpdateRuleRow(tables.Row): +class UpdateShareSnapshotRuleRow(tables.Row): ajax = True def get_data(self, request, rule_id): @@ -221,7 +220,7 @@ class UpdateRuleRow(tables.Row): raise exceptions.NotFound -class RulesTable(tables.DataTable): +class ShareSnapshotRulesTable(tables.DataTable): access_type = tables.Column("access_type", verbose_name=_("Access Type")) access_to = tables.Column("access_to", verbose_name=_("Access to")) status = tables.Column("state", verbose_name=_("Status")) @@ -231,17 +230,19 @@ class RulesTable(tables.DataTable): class Meta(object): name = "rules" - verbose_name = _("Rules") + verbose_name = _("Share Snapshot Rules") status_columns = ["status"] - row_class = UpdateRuleRow + row_class = UpdateShareSnapshotRuleRow table_actions = ( - AddRule, - DeleteRule) + AddShareSnapshotRule, + DeleteShareSnapshotRule, + ) row_actions = ( - DeleteRule,) + DeleteShareSnapshotRule, + ) -class SnapshotsTable(tables.DataTable): +class ShareSnapshotsTable(tables.DataTable): STATUS_CHOICES = ( ("in-use", True), ("available", True), @@ -250,43 +251,50 @@ class SnapshotsTable(tables.DataTable): ) STATUS_DISPLAY_CHOICES = ( ("in-use", pgettext_lazy("Current status of snapshot", u"In-use")), - ("available", pgettext_lazy("Current status of snapshot", - u"Available")), + ("available", + pgettext_lazy("Current status of snapshot", u"Available")), ("creating", pgettext_lazy("Current status of snapshot", u"Creating")), ("error", pgettext_lazy("Current status of snapshot", u"Error")), ) - name = tables.Column("name", - verbose_name=_("Name"), - link="horizon:project:shares:snapshot-detail") - description = tables.Column("description", - verbose_name=_("Description"), - truncate=40) - size = tables.Column(get_size, - verbose_name=_("Size"), - attrs={'data-type': 'size'}) - status = tables.Column("status", - filters=(title,), - verbose_name=_("Status"), - status=True, - status_choices=STATUS_CHOICES, - display_choices=STATUS_DISPLAY_CHOICES) - source = SnapshotShareNameColumn("share", - verbose_name=_("Source"), - link="horizon:project:shares:detail") + name = tables.Column( + "name", + verbose_name=_("Name"), + link="horizon:project:share_snapshots:share_snapshot_detail") + description = tables.Column( + "description", + verbose_name=_("Description"), + truncate=40) + size = tables.Column( + get_size, + verbose_name=_("Size"), + attrs={'data-type': 'size'}) + status = tables.Column( + "status", + filters=(title,), + verbose_name=_("Status"), + status=True, + status_choices=STATUS_CHOICES, + display_choices=STATUS_DISPLAY_CHOICES) + source = ShareSnapshotShareNameColumn( + "share", + verbose_name=_("Source"), + link="horizon:project:shares:detail") def get_object_display(self, obj): return obj.name class Meta(object): - name = "snapshots" - verbose_name = _("Snapshots") + name = "share_snapshots" + verbose_name = _("Share Snapshots") status_columns = ["status"] - row_class = UpdateRow + row_class = UpdateShareSnapshotRow table_actions = ( tables.NameFilterAction, - DeleteSnapshot) + DeleteShareSnapshot, + ) row_actions = ( - EditSnapshot, - CreateShareFromSnapshot, - ManageRules, - DeleteSnapshot) + EditShareSnapshot, + CreateShareFromShareSnapshot, + ManageShareSnapshotRules, + DeleteShareSnapshot, + ) diff --git a/manila_ui/dashboards/project/share_snapshots/tabs.py b/manila_ui/dashboards/project/share_snapshots/tabs.py new file mode 100644 index 00000000..9d326bc1 --- /dev/null +++ b/manila_ui/dashboards/project/share_snapshots/tabs.py @@ -0,0 +1,31 @@ +# +# 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 tabs + + +class ShareSnapshotOverviewTab(tabs.Tab): + name = _("Share Snapshot Overview") + slug = "share_snapshot_overview_tab" + template_name = "project/share_snapshots/_detail.html" + + def get_context_data(self, request): + return {"snapshot": self.tab_group.kwargs['snapshot']} + + +class ShareSnapshotDetailTabs(tabs.TabGroup): + slug = "share_snapshot_details" + tabs = ( + ShareSnapshotOverviewTab, + ) diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/_create_snapshot.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_create.html similarity index 57% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/_create_snapshot.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_create.html index bde30f06..e9ccb5b9 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/snapshots/_create_snapshot.html +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_create.html @@ -2,6 +2,6 @@ {% load i18n %} {% block modal-body-right %}
- {% include "project/shares/snapshots/_limits_snapshots.html" with usages=usages snapshot_quota=True %} + {% include "project/share_snapshots/_limits.html" with usages=usages snapshot_quota=True %}
{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/_snapshot_detail_overview.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_detail.html similarity index 96% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/_snapshot_detail_overview.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_detail.html index 23002ced..862a210c 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/snapshots/_snapshot_detail_overview.html +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_detail.html @@ -8,7 +8,7 @@
{{ snapshot.name }}
{% trans "ID" %}
{{ snapshot.id }}
- {% url 'horizon:admin:shares:detail' snapshot.share_id as share_url %} + {% url 'horizon:project:shares:detail' snapshot.share_id as share_url %}
{% trans "Source" %}
{{ snapshot.share_name_or_id }}
{% if snapshot.description %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/_limits_snapshots.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_limits.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/_limits_snapshots.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_limits.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/_rule_add.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_rule_add.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/_rule_add.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_rule_add.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/_update.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_update.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/_update.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/_update.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/create_snapshot.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/create.html similarity index 67% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/create_snapshot.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/create.html index 316c660d..002c50ac 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/snapshots/create_snapshot.html +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/create.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Create Share Snapshot" %}{% endblock %} {% block main %} - {% include 'project/shares/snapshots/_create_snapshot.html' %} + {% include 'project/share_snapshots/_create.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/snapshot_detail.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/detail.html similarity index 70% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/snapshot_detail.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/detail.html index fcd788ab..aaf0d965 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/snapshots/snapshot_detail.html +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/detail.html @@ -1,6 +1,6 @@ {% extends 'base.html' %} {% load i18n %} -{% block title %}{% trans "Snapshot Details" %}{% endblock %} +{% block title %}{% trans "Share Snapshot Details" %}{% endblock %} {% block main %}
diff --git a/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/index.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/index.html new file mode 100644 index 00000000..bb1f212e --- /dev/null +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/index.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Share Snapshots" %}{% endblock %} + +{% block main %} +
+
+ {{ share_snapshots_table.render }} +
+
+{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/manage_rules.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/manage_rules.html similarity index 59% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/manage_rules.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/manage_rules.html index fed2c700..ee9e8fdb 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/snapshots/manage_rules.html +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/manage_rules.html @@ -1,6 +1,6 @@ {% extends 'base.html' %} {% load i18n %} -{% block title %}{% trans "Share Rules" %}{% endblock %} +{% block title %}{% trans "Share Snapshot Rules" %}{% endblock %} {% block main %} {{ table.render }} diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/rule_add.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/rule_add.html similarity index 68% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/rule_add.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/rule_add.html index 4c6b9c26..1107e159 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/snapshots/rule_add.html +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/rule_add.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Add Rule" %}{% endblock %} {% block main %} - {% include 'project/shares/snapshots/_rule_add.html' %} + {% include 'project/share_snapshots/_rule_add.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/snapshots/update.html b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/update.html similarity index 70% rename from manila_ui/dashboards/project/shares/templates/shares/snapshots/update.html rename to manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/update.html index 4af191c8..73567b1e 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/snapshots/update.html +++ b/manila_ui/dashboards/project/share_snapshots/templates/share_snapshots/update.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Edit Share Snapshot" %}{% endblock %} {% block main %} - {% include 'project/shares/snapshots/_update.html' %} + {% include 'project/share_snapshots/_update.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/share_snapshots/urls.py b/manila_ui/dashboards/project/share_snapshots/urls.py new file mode 100644 index 00000000..3162b0a8 --- /dev/null +++ b/manila_ui/dashboards/project/share_snapshots/urls.py @@ -0,0 +1,45 @@ +# Copyright 2017 Mirantis, Inc. +# +# 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.conf import urls + +from manila_ui.dashboards.project.share_snapshots import views + + +urlpatterns = [ + urls.url( + r'^$', + views.ShareSnapshotsView.as_view(), + name='index'), + urls.url( + r'^(?P[^/]+)/share_snapshot_create/$', + views.CreateShareSnapshotView.as_view(), + name='share_snapshot_create'), + urls.url( + r'^(?P[^/]+)/share_snapshot_edit/$', + views.UpdateShareSnapshotView.as_view(), + name='share_snapshot_edit'), + urls.url( + r'^(?P[^/]+)$', + views.ShareSnapshotDetailView.as_view(), + name='share_snapshot_detail'), + urls.url( + r'^(?P[^/]+)/share_snapshot_rules/$', + views.ManageShareSnapshotRulesView.as_view(), + name='share_snapshot_manage_rules'), + urls.url( + r'^(?P[^/]+)/share_snapshot_rule_add/$', + views.AddShareSnapshotRuleView.as_view(), + name='share_snapshot_rule_add'), +] diff --git a/manila_ui/dashboards/project/shares/snapshots/views.py b/manila_ui/dashboards/project/share_snapshots/views.py similarity index 60% rename from manila_ui/dashboards/project/shares/snapshots/views.py rename to manila_ui/dashboards/project/share_snapshots/views.py index 282ff7a9..ce3130fb 100644 --- a/manila_ui/dashboards/project/shares/snapshots/views.py +++ b/manila_ui/dashboards/project/share_snapshots/views.py @@ -15,31 +15,52 @@ from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse_lazy from django.utils.translation import ugettext_lazy as _ - from horizon import exceptions from horizon import forms from horizon import tables from horizon import tabs from horizon.utils import memoized - -from manila_ui.api import manila -from manila_ui.dashboards.project.shares.snapshots import forms \ - as snapshot_forms -from manila_ui.dashboards.project.shares.snapshots \ - import tables as snapshot_tables -from manila_ui.dashboards.project.shares.snapshots \ - import tabs as snapshot_tabs -from manila_ui.dashboards import utils as ui_utils from openstack_dashboard.usage import quotas +from manila_ui.api import manila +from manila_ui.dashboards.project.share_snapshots import forms as ss_forms +from manila_ui.dashboards.project.share_snapshots import tables as ss_tables +from manila_ui.dashboards.project.share_snapshots import tabs as ss_tabs +from manila_ui.dashboards import utils as ui_utils -class SnapshotDetailView(tabs.TabView): - tab_group_class = snapshot_tabs.SnapshotDetailTabs - template_name = 'project/shares/snapshots/snapshot_detail.html' - redirect_url = reverse_lazy('horizon:project:shares:index') + +class ShareSnapshotsView(tables.MultiTableView): + table_classes = ( + ss_tables.ShareSnapshotsTable, + ) + template_name = "project/share_snapshots/index.html" + page_title = _("Share Snapshots") + + @memoized.memoized_method + def get_share_snapshots_data(self): + try: + snapshots = manila.share_snapshot_list(self.request) + shares = manila.share_list(self.request) + share_names = dict([(share.id, share.name or share.id) + for share in shares]) + for snapshot in snapshots: + snapshot.share = share_names.get(snapshot.share_id) + except Exception: + msg = _("Unable to retrieve share snapshots list.") + exceptions.handle(self.request, msg) + return [] + # Gather our tenants to correlate against IDs + return snapshots + + +class ShareSnapshotDetailView(tabs.TabView): + tab_group_class = ss_tabs.ShareSnapshotDetailTabs + template_name = 'project/share_snapshots/detail.html' + redirect_url = reverse_lazy('horizon:project:share_snapshots:index') def get_context_data(self, **kwargs): - context = super(SnapshotDetailView, self).get_context_data(**kwargs) + context = super(ShareSnapshotDetailView, self).get_context_data( + **kwargs) snapshot = self.get_data() snapshot_display_name = snapshot.name or snapshot.id context["snapshot"] = snapshot @@ -69,9 +90,10 @@ class SnapshotDetailView(tabs.TabView): snapshot.share_name_or_id = share.name or share.id except Exception: - exceptions.handle(self.request, - _('Unable to retrieve snapshot details.'), - redirect=self.redirect_url) + exceptions.handle( + self.request, + _('Unable to retrieve snapshot details.'), + redirect=self.redirect_url) return snapshot def get_tabs(self, request, *args, **kwargs): @@ -79,19 +101,19 @@ class SnapshotDetailView(tabs.TabView): return self.tab_group_class(request, snapshot=snapshot, **kwargs) -class CreateSnapshotView(forms.ModalFormView): - form_class = snapshot_forms.CreateSnapshotForm +class CreateShareSnapshotView(forms.ModalFormView): + form_class = ss_forms.CreateShareSnapshotForm form_id = "create_share_snapshot" - template_name = 'project/shares/snapshots/create_snapshot.html' + template_name = 'project/share_snapshots/create.html' modal_header = _("Create Share Snapshot") modal_id = "create_share_snapshot_modal" submit_label = _("Create Share Snapshot") - submit_url = "horizon:project:shares:create_snapshot" - success_url = reverse_lazy('horizon:project:shares:snapshots_tab') + submit_url = "horizon:project:share_snapshots:share_snapshot_create" + success_url = reverse_lazy('horizon:project:share_snapshots:index') page_title = _('Create Share Snapshot') def get_context_data(self, **kwargs): - context = super(CreateSnapshotView, self).get_context_data(**kwargs) + context = super(self.__class__, self).get_context_data(**kwargs) context['share_id'] = self.kwargs['share_id'] try: context['usages'] = quotas.tenant_limit_usages(self.request) @@ -104,16 +126,16 @@ class CreateSnapshotView(forms.ModalFormView): return {'share_id': self.kwargs["share_id"]} -class UpdateView(forms.ModalFormView): - form_class = snapshot_forms.UpdateForm - form_id = "update_snapshot" - template_name = 'project/shares/snapshots/update.html' - modal_header = _("Edit Snapshot") - modal_id = "update_snapshot_modal" - submit_label = _("Edit") - submit_url = "horizon:project:shares:edit_snapshot" - success_url = reverse_lazy('horizon:project:shares:snapshots_tab') - page_title = _('Edit Snapshot') +class UpdateShareSnapshotView(forms.ModalFormView): + form_class = ss_forms.UpdateShareSnapshotForm + form_id = "update_share_snapshot" + template_name = 'project/share_snapshots/update.html' + modal_header = _("Update Share Snapshot") + modal_id = "update_share_snapshot_modal" + submit_label = _("Update") + submit_url = "horizon:project:share_snapshots:share_snapshot_edit" + success_url = reverse_lazy('horizon:project:share_snapshots:index') + page_title = _('Edit Share Snapshot') @memoized.memoized_method def get_object(self): @@ -122,13 +144,13 @@ class UpdateView(forms.ModalFormView): try: self._object = manila.share_snapshot_get(self.request, snap_id) except Exception: - msg = _('Unable to retrieve snapshot.') - url = reverse('horizon:project:shares:index') + msg = _('Unable to retrieve share snapshot.') + url = reverse('horizon:project:share_snapshots:index') exceptions.handle(self.request, msg, redirect=url) return self._object def get_context_data(self, **kwargs): - context = super(UpdateView, self).get_context_data(**kwargs) + context = super(self.__class__, self).get_context_data(**kwargs) args = (self.get_object().id,) context['submit_url'] = reverse(self.submit_url, args=args) return context @@ -140,15 +162,15 @@ class UpdateView(forms.ModalFormView): 'description': snapshot.description} -class AddRuleView(forms.ModalFormView): - form_class = snapshot_forms.AddRule +class AddShareSnapshotRuleView(forms.ModalFormView): + form_class = ss_forms.AddShareSnapshotRule form_id = "rule_add_snap" - template_name = 'project/shares/snapshots/rule_add.html' + template_name = 'project/share_snapshots/rule_add.html' modal_header = _("Add Rule") - modal_id = "rule_add_snap_modal" + modal_id = "rule_add_share_snapshot_modal" submit_label = _("Add") - submit_url = "horizon:project:shares:snapshot_rule_add" - success_url = reverse_lazy("horizon:project:shares:index") + submit_url = "horizon:project:share_snapshots:share_snapshot_rule_add" + success_url = reverse_lazy("horizon:project:share_snapshots:index") page_title = _('Add Rule') def get_object(self): @@ -159,12 +181,12 @@ class AddRuleView(forms.ModalFormView): self.request, snapshot_id) except Exception: msg = _('Unable to retrieve snapshot.') - url = reverse('horizon:project:shares:index') + url = reverse('horizon:project:share_snapshots:index') exceptions.handle(self.request, msg, redirect=url) return self._object def get_context_data(self, **kwargs): - context = super(AddRuleView, self).get_context_data(**kwargs) + context = super(self.__class__, self).get_context_data(**kwargs) args = (self.get_object().id,) context['submit_url'] = reverse(self.submit_url, args=args) return context @@ -176,16 +198,17 @@ class AddRuleView(forms.ModalFormView): 'description': snapshot.description} def get_success_url(self): - return reverse("horizon:project:shares:snapshot_manage_rules", - args=[self.kwargs['snapshot_id']]) + return reverse( + "horizon:project:share_snapshots:share_snapshot_manage_rules", + args=[self.kwargs['snapshot_id']]) -class ManageRulesView(tables.DataTableView): - table_class = snapshot_tables.RulesTable - template_name = 'project/shares/snapshots/manage_rules.html' +class ManageShareSnapshotRulesView(tables.DataTableView): + table_class = ss_tables.ShareSnapshotRulesTable + template_name = 'project/share_snapshots/manage_rules.html' def get_context_data(self, **kwargs): - context = super(ManageRulesView, self).get_context_data(**kwargs) + context = super(self.__class__, self).get_context_data(**kwargs) snapshot = manila.share_snapshot_get( self.request, self.kwargs['snapshot_id']) context['snapshot_display_name'] = snapshot.name or snapshot.id @@ -202,8 +225,9 @@ class ManageRulesView(tables.DataTableView): rules = manila.share_snapshot_rules_list( self.request, snapshot_id) except Exception: - redirect = reverse('horizon:project:shares:index') - exceptions.handle(self.request, - _('Unable to retrieve snapshot rules.'), - redirect=redirect) + redirect = reverse('horizon:project:share_snapshots:index') + exceptions.handle( + self.request, + _('Unable to retrieve share snapshot rules.'), + redirect=redirect) return rules diff --git a/manila_ui/dashboards/project/shares/shares/forms.py b/manila_ui/dashboards/project/shares/forms.py similarity index 100% rename from manila_ui/dashboards/project/shares/shares/forms.py rename to manila_ui/dashboards/project/shares/forms.py diff --git a/manila_ui/dashboards/project/shares/share_networks/tabs.py b/manila_ui/dashboards/project/shares/share_networks/tabs.py deleted file mode 100644 index 4b1d0ed1..00000000 --- a/manila_ui/dashboards/project/shares/share_networks/tabs.py +++ /dev/null @@ -1,79 +0,0 @@ -# -# 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 manila_ui.api import manila -from manila_ui.api import network -from manila_ui.dashboards.project.shares.share_networks\ - import tables as share_net_tables - -from openstack_dashboard.api import base -from openstack_dashboard.api import neutron - - -class ShareNetworkTab(tabs.TableTab): - name = _("Share Networks") - slug = "share_networks_tab" - template_name = "horizon/common/_detail_table.html" - - def __init__(self, tab_group, request): - if base.is_service_enabled(request, 'network'): - self.table_classes = (share_net_tables.ShareNetworksTable,) - else: - self.table_classes = (share_net_tables.NovaShareNetworkTable,) - super(ShareNetworkTab, self).__init__(tab_group, request) - - def get_share_networks_data(self): - try: - share_networks = manila.share_network_list(self.request, - detailed=True) - if base.is_service_enabled(self.request, 'network'): - neutron_net_names = dict((net.id, net.name) for net in - neutron.network_list(self.request)) - neutron_subnet_names = dict((net.id, net.name) for net in - neutron.subnet_list(self.request)) - for sn in share_networks: - sn.neutron_net = neutron_net_names.get( - sn.neutron_net_id) or sn.neutron_net_id or "-" - sn.neutron_subnet = neutron_subnet_names.get( - sn.neutron_subnet_id) or sn.neutron_subnet_id or "-" - else: - nova_net_names = dict( - [(net.id, net.label) - for net in network.network_list(self.request)]) - for sn in share_networks: - sn.nova_net = nova_net_names.get( - sn.nova_net_id) or sn.nova_net_id or "-" - except Exception: - share_networks = [] - exceptions.handle(self.request, - _("Unable to retrieve share networks")) - return share_networks - - -class OverviewTab(tabs.Tab): - name = _("Overview") - slug = "overview" - template_name = ("project/shares/share_networks/_detail_overview.html") - - def get_context_data(self, request): - return {"share_network": self.tab_group.kwargs['share_network']} - - -class ShareNetworkDetailTabs(tabs.TabGroup): - slug = "share_network_details" - tabs = (OverviewTab,) diff --git a/manila_ui/dashboards/project/shares/shares/tabs.py b/manila_ui/dashboards/project/shares/shares/tabs.py deleted file mode 100644 index 7a126d85..00000000 --- a/manila_ui/dashboards/project/shares/shares/tabs.py +++ /dev/null @@ -1,77 +0,0 @@ -# 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 manila_ui.api import manila - -from manila_ui.dashboards.project.shares.shares \ - import tables as share_tables -from manila_ui.dashboards import utils - - -class SharesTab(tabs.TableTab): - table_classes = (share_tables.SharesTable, ) - name = _("Shares") - slug = "shares_tab" - template_name = "horizon/common/_detail_table.html" - - def _set_id_if_nameless(self, shares): - for share in shares: - if not share.name: - share.name = share.id - - def get_shares_data(self): - share_nets_names = {} - share_nets = manila.share_network_list(self.request) - for share_net in share_nets: - share_nets_names[share_net.id] = share_net.name - try: - shares = manila.share_list(self.request) - for share in shares: - share.share_network = ( - share_nets_names.get(share.share_network_id) or - share.share_network_id) - share.metadata = utils.metadata_to_str(share.metadata) - - snapshots = manila.share_snapshot_list(self.request, detailed=True) - share_ids_with_snapshots = [] - for snapshot in snapshots: - share_ids_with_snapshots.append(snapshot.to_dict()['share_id']) - for share in shares: - if share.to_dict()['id'] in share_ids_with_snapshots: - setattr(share, 'has_snapshot', True) - else: - setattr(share, 'has_snapshot', False) - except Exception: - exceptions.handle(self.request, - _('Unable to retrieve share list.')) - return [] - # Gather our tenants to correlate against IDs - return shares - - -class OverviewTab(tabs.Tab): - name = _("Overview") - slug = "overview" - template_name = "project/shares/shares/_detail_overview.html" - - def get_context_data(self, request): - return {"share": self.tab_group.kwargs['share']} - - -class ShareDetailTabs(tabs.TabGroup): - slug = "share_details" - tabs = (OverviewTab,) diff --git a/manila_ui/dashboards/project/shares/shares/views.py b/manila_ui/dashboards/project/shares/shares/views.py deleted file mode 100644 index 2ab28bfa..00000000 --- a/manila_ui/dashboards/project/shares/shares/views.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright 2012 Nebula, Inc. -# -# 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.core.urlresolvers import reverse -from django.core.urlresolvers import reverse_lazy -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import tables -from horizon import tabs -from horizon.utils import memoized - -from manila_ui.api import manila -from manila_ui.dashboards.project.shares.shares import forms \ - as share_form -from manila_ui.dashboards.project.shares.shares \ - import tables as shares_tables -from manila_ui.dashboards.project.shares.shares \ - import tabs as shares_tabs -from manila_ui.dashboards import utils as ui_utils -from openstack_dashboard.usage import quotas - - -class ShareTableMixIn(object): - def _get_shares(self, search_opts=None): - try: - return manila.share_list(self.request, search_opts=search_opts) - except Exception: - exceptions.handle(self.request, - _('Unable to retrieve share list.')) - return [] - - def _set_id_if_nameless(self, shares): - for share in shares: - # It is possible to create a share with no name - if not share.name: - share.name = share.id - - -class DetailView(tabs.TabView): - tab_group_class = shares_tabs.ShareDetailTabs - template_name = 'project/shares/shares/detail.html' - - def get_context_data(self, **kwargs): - context = super(DetailView, self).get_context_data(**kwargs) - share = self.get_data() - share_display_name = share.name or share.id - context["share"] = share - context["share_display_name"] = share_display_name - context["page_title"] = _("Share Details: " - "%(share_display_name)s") % { - 'share_display_name': share_display_name} - return context - - @memoized.memoized_method - def get_data(self): - try: - share_id = self.kwargs['share_id'] - share = manila.share_get(self.request, share_id) - share.rules = manila.share_rules_list(self.request, share_id) - share.export_locations = manila.share_export_location_list( - self.request, share_id) - export_locations = [ - exp['path'] for exp in share.export_locations] - share.el_size = ui_utils.calculate_longest_str_size( - export_locations) - except Exception: - redirect = reverse('horizon:project:shares:index') - exceptions.handle(self.request, - _('Unable to retrieve share details.'), - redirect=redirect) - return share - - def get_tabs(self, request, *args, **kwargs): - share = self.get_data() - return self.tab_group_class(request, share=share, **kwargs) - - -class CreateView(forms.ModalFormView): - form_class = share_form.CreateForm - form_id = "create_share" - template_name = 'project/shares/shares/create.html' - modal_header = _("Create Share") - modal_id = "create_share_modal" - submit_label = _("Create") - submit_url = reverse_lazy("horizon:project:shares:create") - success_url = reverse_lazy("horizon:project:shares:index") - page_title = _('Create a Share') - - def get_context_data(self, **kwargs): - context = super(CreateView, self).get_context_data(**kwargs) - try: - context['usages'] = quotas.tenant_limit_usages(self.request) - except Exception: - exceptions.handle(self.request) - return context - - -class UpdateView(forms.ModalFormView): - form_class = share_form.UpdateForm - form_id = "update_share" - template_name = 'project/shares/shares/update.html' - modal_header = _("Edit Share") - modal_id = "update_share_modal" - submit_label = _("Edit") - submit_url = "horizon:project:shares:update" - success_url = reverse_lazy("horizon:project:shares:index") - page_title = _('Edit Share') - - def get_object(self): - if not hasattr(self, "_object"): - vol_id = self.kwargs['share_id'] - try: - self._object = manila.share_get(self.request, vol_id) - except Exception: - msg = _('Unable to retrieve share.') - url = reverse('horizon:project:shares:index') - exceptions.handle(self.request, msg, redirect=url) - return self._object - - def get_context_data(self, **kwargs): - context = super(UpdateView, self).get_context_data(**kwargs) - return context - - def get_initial(self): - self.submit_url = reverse(self.submit_url, kwargs=self.kwargs) - share = self.get_object() - return {'share_id': self.kwargs["share_id"], - 'name': share.name, - 'description': share.description} - - -class UpdateMetadataView(forms.ModalFormView): - form_class = share_form.UpdateMetadataForm - form_id = "update_share_metadata" - template_name = 'project/shares/shares/update_metadata.html' - modal_header = _("Edit Share Metadata") - modal_id = "update_share_metadata_modal" - submit_label = _("Save Changes") - submit_url = "horizon:project:shares:update_metadata" - success_url = reverse_lazy("horizon:project:shares:index") - page_title = _('Edit Share Metadata') - - def get_object(self): - if not hasattr(self, "_object"): - sh_id = self.kwargs['share_id'] - try: - self._object = manila.share_get(self.request, sh_id) - except Exception: - msg = _('Unable to retrieve share.') - url = reverse('horizon:project:shares:index') - exceptions.handle(self.request, msg, redirect=url) - return self._object - - def get_context_data(self, **kwargs): - context = super(UpdateMetadataView, self).get_context_data(**kwargs) - args = (self.get_object().id,) - context['submit_url'] = reverse(self.submit_url, args=args) - return context - - def get_initial(self): - share = self.get_object() - return {'share_id': self.kwargs["share_id"], - 'metadata': share.metadata} - - -class AddRuleView(forms.ModalFormView): - form_class = share_form.AddRule - form_id = "rule_add" - template_name = 'project/shares/shares/rule_add.html' - modal_header = _("Add Rule") - modal_id = "rule_add_modal" - submit_label = _("Add") - submit_url = "horizon:project:shares:rule_add" - success_url = reverse_lazy("horizon:project:shares:index") - page_title = _('Add Rule') - - def get_object(self): - if not hasattr(self, "_object"): - vol_id = self.kwargs['share_id'] - try: - self._object = manila.share_get(self.request, vol_id) - except Exception: - msg = _('Unable to retrieve share.') - url = reverse('horizon:project:shares:index') - exceptions.handle(self.request, msg, redirect=url) - return self._object - - def get_context_data(self, **kwargs): - context = super(AddRuleView, self).get_context_data(**kwargs) - args = (self.get_object().id,) - context['submit_url'] = reverse(self.submit_url, args=args) - return context - - def get_initial(self): - share = self.get_object() - return {'share_id': self.kwargs["share_id"], - 'name': share.name, - 'description': share.description} - - def get_success_url(self): - return reverse("horizon:project:shares:manage_rules", - args=[self.kwargs['share_id']]) - - -class ManageRulesView(tables.DataTableView): - table_class = shares_tables.RulesTable - template_name = 'project/shares/shares/manage_rules.html' - - def get_context_data(self, **kwargs): - context = super(ManageRulesView, self).get_context_data(**kwargs) - share = manila.share_get(self.request, self.kwargs['share_id']) - context['share_display_name'] = share.name or share.id - context["share"] = self.get_data() - context["page_title"] = _("Share Rules: " - "%(share_display_name)s") % { - 'share_display_name': context['share_display_name']} - return context - - @memoized.memoized_method - def get_data(self): - try: - share_id = self.kwargs['share_id'] - rules = manila.share_rules_list(self.request, share_id) - except Exception: - redirect = reverse('horizon:project:shares:index') - exceptions.handle(self.request, - _('Unable to retrieve share rules.'), - redirect=redirect) - return rules - - -class ExtendView(forms.ModalFormView): - form_class = share_form.ExtendForm - form_id = "extend_share" - template_name = 'project/shares/shares/extend.html' - modal_header = _("Extend Share") - modal_id = "extend_share_modal" - submit_label = _("Extend") - submit_url = "horizon:project:shares:extend" - success_url = reverse_lazy("horizon:project:shares:index") - page_title = _('Extend Share') - - @memoized.memoized_method - def get_object(self): - try: - return manila.share_get(self.request, self.kwargs['share_id']) - except Exception: - exceptions.handle(self.request, _('Unable to retrieve share.')) - - def get_context_data(self, **kwargs): - context = super(ExtendView, self).get_context_data(**kwargs) - args = (self.get_object().id,) - context['submit_url'] = reverse(self.submit_url, args=args) - try: - context['usages'] = quotas.tenant_limit_usages(self.request) - context['usages']['totalShareGigabytesUsed'] -= int( - self.get_object().size) - except Exception: - exceptions.handle(self.request) - - return context - - def get_initial(self): - share = self.get_object() - if not share or isinstance(share, Exception): - raise exceptions.NotFound() - return { - 'share_id': self.kwargs["share_id"], - 'name': share.name or share.id, - 'orig_size': share.size, - 'new_size': int(share.size) + 1, - } - - -class RevertView(forms.ModalFormView): - form_class = share_form.RevertForm - form_id = "revert_share" - template_name = 'project/shares/shares/revert.html' - modal_header = _("Revert Share to a Snapshot") - modal_id = "revert_share_modal" - submit_label = _("Revert share to a snapshot") - submit_url = "horizon:project:shares:revert" - success_url = reverse_lazy("horizon:project:shares:index") - page_title = _('Revert Share to a Snapshot') - - @memoized.memoized_method - def get_object(self): - try: - return manila.share_get(self.request, self.kwargs['share_id']) - except Exception: - exceptions.handle(self.request, _('Unable to retrieve share.')) - - def get_context_data(self, **kwargs): - context = super(self.__class__, self).get_context_data(**kwargs) - args = (self.get_object().id,) - context['submit_url'] = reverse(self.submit_url, args=args) - return context - - def get_initial(self): - share = self.get_object() - if not share or isinstance(share, Exception): - raise exceptions.NotFound() - return { - 'share_id': self.kwargs["share_id"], - 'name': share.name or share.id, - } diff --git a/manila_ui/dashboards/project/shares/snapshots/tabs.py b/manila_ui/dashboards/project/shares/snapshots/tabs.py deleted file mode 100644 index b20e62a1..00000000 --- a/manila_ui/dashboards/project/shares/snapshots/tabs.py +++ /dev/null @@ -1,64 +0,0 @@ -# -# 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 manila_ui.api import manila - -from manila_ui.dashboards.project.shares.snapshots \ - import tables as snapshot_tables - - -class SnapshotsTab(tabs.TableTab): - table_classes = (snapshot_tables.SnapshotsTable, ) - name = _("Snapshots") - slug = "snapshots_tab" - template_name = "horizon/common/_detail_table.html" - - def _set_id_if_nameless(self, snapshots): - for snap in snapshots: - if not snap.name: - snap.name = snap.id - - def get_snapshots_data(self): - try: - snapshots = manila.share_snapshot_list(self.request) - shares = manila.share_list(self.request) - share_names = dict([(share.id, share.name or share.id) - for share in shares]) - for snapshot in snapshots: - snapshot.share = share_names.get(snapshot.share_id) - except Exception: - msg = _("Unable to retrieve share snapshots list.") - exceptions.handle(self.request, msg) - return [] - # Gather our tenants to correlate against IDs - return snapshots - - -class SnapshotOverviewTab(tabs.Tab): - name = _("Overview") - slug = "overview" - template_name = ("project/shares/snapshots/" - "_snapshot_detail_overview.html") - - def get_context_data(self, request): - return {"snapshot": self.tab_group.kwargs['snapshot']} - - -class SnapshotDetailTabs(tabs.TabGroup): - slug = "snapshot_details" - tabs = (SnapshotOverviewTab,) diff --git a/manila_ui/dashboards/project/shares/shares/tables.py b/manila_ui/dashboards/project/shares/tables.py similarity index 99% rename from manila_ui/dashboards/project/shares/shares/tables.py rename to manila_ui/dashboards/project/shares/tables.py index 0e85d493..946564c3 100644 --- a/manila_ui/dashboards/project/shares/shares/tables.py +++ b/manila_ui/dashboards/project/shares/tables.py @@ -23,8 +23,7 @@ from horizon import exceptions from horizon import messages from horizon import tables from manila_ui.api import manila -from manila_ui.dashboards.project.shares.snapshots \ - import tables as snapshot_tables +from manila_ui.dashboards.project.share_snapshots import tables as ss_tables from manila_ui.dashboards import utils from openstack_dashboard.usage import quotas @@ -383,7 +382,7 @@ class SharesTable(SharesTableBase): EditShare, ExtendShare, RevertShare, - snapshot_tables.CreateSnapshot, + ss_tables.CreateShareSnapshot, ManageRules, ManageReplicas, EditShareMetadata, diff --git a/manila_ui/dashboards/project/shares/tabs.py b/manila_ui/dashboards/project/shares/tabs.py new file mode 100644 index 00000000..c2168434 --- /dev/null +++ b/manila_ui/dashboards/project/shares/tabs.py @@ -0,0 +1,30 @@ +# 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 tabs + + +class OverviewTab(tabs.Tab): + name = _("Overview") + slug = "overview" + template_name = "project/shares/_detail.html" + + def get_context_data(self, request): + return {"share": self.tab_group.kwargs['share']} + + +class ShareDetailTabs(tabs.TabGroup): + slug = "share_details" + tabs = ( + OverviewTab, + ) diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_extend.html b/manila_ui/dashboards/project/shares/templates/shares/_create.html similarity index 64% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_extend.html rename to manila_ui/dashboards/project/shares/templates/shares/_create.html index 79e2f0ba..2109f605 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/_extend.html +++ b/manila_ui/dashboards/project/shares/templates/shares/_create.html @@ -2,6 +2,6 @@ {% load i18n %} {% block modal-body-right %}
- {% include "project/shares/shares/_extend_limits.html" with usages=usages %} + {% include "project/shares/_limits.html" with usages=usages %}
{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_detail_overview.html b/manila_ui/dashboards/project/shares/templates/shares/_detail.html similarity index 94% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_detail_overview.html rename to manila_ui/dashboards/project/shares/templates/shares/_detail.html index ae95363e..32f3018f 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/_detail_overview.html +++ b/manila_ui/dashboards/project/shares/templates/shares/_detail.html @@ -33,7 +33,7 @@ {% endfor %} {% if share.snapshot_id %}
{% trans "Snapshot ID" %}
- {% url 'horizon:project:shares:snapshot-detail' share.snapshot_id as snapshot_url%} + {% url 'horizon:project:share_snapshots:share_snapshot_detail' share.snapshot_id as snapshot_url%}
{{ share.snapshot_id }}
{% endif %}
{% trans "Visibility" %}
@@ -58,7 +58,7 @@ {% endif %} {% if share.share_network_id %}
{% trans "Share network" %}
- {% url 'horizon:project:shares:share_network_detail' share.share_network_id as sn_url%} + {% url 'horizon:project:share_networks:share_network_detail' share.share_network_id as sn_url%}
{{ share.share_network_id }}
{% endif %}
{% trans "Mount snapshot support" %}
diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_create.html b/manila_ui/dashboards/project/shares/templates/shares/_extend.html similarity index 71% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_create.html rename to manila_ui/dashboards/project/shares/templates/shares/_extend.html index fefa3d39..8d87895c 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/_create.html +++ b/manila_ui/dashboards/project/shares/templates/shares/_extend.html @@ -2,6 +2,6 @@ {% load i18n %} {% block modal-body-right %}
- {% include "project/shares/shares/_limits.html" with usages=usages %} + {% include "project/shares/_extend_limits.html" with usages=usages %}
{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_extend_limits.html b/manila_ui/dashboards/project/shares/templates/shares/_extend_limits.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_extend_limits.html rename to manila_ui/dashboards/project/shares/templates/shares/_extend_limits.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_limits.html b/manila_ui/dashboards/project/shares/templates/shares/_limits.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_limits.html rename to manila_ui/dashboards/project/shares/templates/shares/_limits.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_manage_rules.html b/manila_ui/dashboards/project/shares/templates/shares/_manage_rules.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_manage_rules.html rename to manila_ui/dashboards/project/shares/templates/shares/_manage_rules.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_revert.html b/manila_ui/dashboards/project/shares/templates/shares/_revert.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_revert.html rename to manila_ui/dashboards/project/shares/templates/shares/_revert.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_rule_add.html b/manila_ui/dashboards/project/shares/templates/shares/_rule_add.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_rule_add.html rename to manila_ui/dashboards/project/shares/templates/shares/_rule_add.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_update.html b/manila_ui/dashboards/project/shares/templates/shares/_update.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_update.html rename to manila_ui/dashboards/project/shares/templates/shares/_update.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_update_metadata.html b/manila_ui/dashboards/project/shares/templates/shares/_update_metadata.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/_update_metadata.html rename to manila_ui/dashboards/project/shares/templates/shares/_update_metadata.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/create.html b/manila_ui/dashboards/project/shares/templates/shares/create.html similarity index 70% rename from manila_ui/dashboards/project/shares/templates/shares/shares/create.html rename to manila_ui/dashboards/project/shares/templates/shares/create.html index 41a37c26..780eb727 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/create.html +++ b/manila_ui/dashboards/project/shares/templates/shares/create.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Create Share" %}{% endblock %} {% block main %} - {% include 'project/shares/shares/_create.html' %} + {% include 'project/shares/_create.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/share_networks/detail.html b/manila_ui/dashboards/project/shares/templates/shares/detail.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/share_networks/detail.html rename to manila_ui/dashboards/project/shares/templates/shares/detail.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/extend.html b/manila_ui/dashboards/project/shares/templates/shares/extend.html similarity index 63% rename from manila_ui/dashboards/project/shares/templates/shares/shares/extend.html rename to manila_ui/dashboards/project/shares/templates/shares/extend.html index 03ae1203..9658518f 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/extend.html +++ b/manila_ui/dashboards/project/shares/templates/shares/extend.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Extend Share" %}{% endblock %} {% block main %} - {% include 'project/shares/shares/_extend.html' %} -{% endblock %} \ No newline at end of file + {% include 'project/shares/_extend.html' %} +{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/index.html b/manila_ui/dashboards/project/shares/templates/shares/index.html index 7ee65323..1f041e09 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/index.html +++ b/manila_ui/dashboards/project/shares/templates/shares/index.html @@ -5,7 +5,7 @@ {% block main %}
- {{ tab_group.render }} + {{ shares_table.render }}
{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/manage_rules.html b/manila_ui/dashboards/project/shares/templates/shares/manage_rules.html similarity index 100% rename from manila_ui/dashboards/project/shares/templates/shares/shares/manage_rules.html rename to manila_ui/dashboards/project/shares/templates/shares/manage_rules.html diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/revert.html b/manila_ui/dashboards/project/shares/templates/shares/revert.html similarity index 70% rename from manila_ui/dashboards/project/shares/templates/shares/shares/revert.html rename to manila_ui/dashboards/project/shares/templates/shares/revert.html index d5973eb2..a5cc1475 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/revert.html +++ b/manila_ui/dashboards/project/shares/templates/shares/revert.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Revert Share" %}{% endblock %} {% block main %} - {% include 'project/shares/shares/_revert.html' %} + {% include 'project/shares/_revert.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/rule_add.html b/manila_ui/dashboards/project/shares/templates/shares/rule_add.html similarity index 69% rename from manila_ui/dashboards/project/shares/templates/shares/shares/rule_add.html rename to manila_ui/dashboards/project/shares/templates/shares/rule_add.html index ef804953..e518c51b 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/rule_add.html +++ b/manila_ui/dashboards/project/shares/templates/shares/rule_add.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Add Rule" %}{% endblock %} {% block main %} - {% include 'project/shares/shares/_rule_add.html' %} + {% include 'project/shares/_rule_add.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_add_security_service.html b/manila_ui/dashboards/project/shares/templates/shares/shares/_add_security_service.html deleted file mode 100644 index a241a9c4..00000000 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/_add_security_service.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}{% endblock %} -{% block form_action %}{% url 'horizon:project:shares:add_security_service' share_network.id %}{% endblock %} - -{% block modal_id %}add_security_service_modal{% endblock %} -{% block modal-header %}{% trans "Add Security Service" %}{% endblock %} - - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description" %}:

-

{% blocktrans %} - The security service can be used by backend drivers to - configure clients, for more secure using of share. - {% endblocktrans %}

-
- - - - - - -
- -
    -
- -
    -
-
- - - - - - - - -
-
- {% include "horizon/common/_form_fields.html" %} -
-
- {{ step.get_help_text }} -
- - -{% endblock %} - -{% block modal-footer %} - - {% trans "Cancel" %} -{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/update.html b/manila_ui/dashboards/project/shares/templates/shares/update.html similarity index 70% rename from manila_ui/dashboards/project/shares/templates/shares/shares/update.html rename to manila_ui/dashboards/project/shares/templates/shares/update.html index ce313a8d..0ed205f1 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/update.html +++ b/manila_ui/dashboards/project/shares/templates/shares/update.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Edit Share" %}{% endblock %} {% block main %} - {% include 'project/shares/shares/_update.html' %} + {% include 'project/shares/_update.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/update_metadata.html b/manila_ui/dashboards/project/shares/templates/shares/update_metadata.html similarity index 68% rename from manila_ui/dashboards/project/shares/templates/shares/shares/update_metadata.html rename to manila_ui/dashboards/project/shares/templates/shares/update_metadata.html index 86fec56e..32567233 100644 --- a/manila_ui/dashboards/project/shares/templates/shares/shares/update_metadata.html +++ b/manila_ui/dashboards/project/shares/templates/shares/update_metadata.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Edit Share Metadata" %}{% endblock %} {% block main %} - {% include 'project/shares/shares/_update_metadata.html' %} + {% include 'project/shares/_update_metadata.html' %} {% endblock %} diff --git a/manila_ui/dashboards/project/shares/urls.py b/manila_ui/dashboards/project/shares/urls.py index ed8ee9a1..37675922 100644 --- a/manila_ui/dashboards/project/shares/urls.py +++ b/manila_ui/dashboards/project/shares/urls.py @@ -12,96 +12,68 @@ # License for the specific language governing permissions and limitations # under the License. -from django.conf.urls import url # noqa +from django.conf import urls from manila_ui.api import manila -from manila_ui.dashboards.project.shares.replicas\ - import views as replica_views -from manila_ui.dashboards.project.shares.security_services \ - import views as security_services_views -from manila_ui.dashboards.project.shares.share_networks \ - import views as share_networks_views -from manila_ui.dashboards.project.shares.shares \ - import views as shares_views -from manila_ui.dashboards.project.shares.snapshots\ - import views as snapshot_views -from manila_ui.dashboards.project.shares import views +from manila_ui.dashboards.project.shares.replicas import views as replica_views +from manila_ui.dashboards.project.shares import views as shares_views urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^\?tab=share_tabs__snapshots_tab$', - views.IndexView.as_view(), - name='snapshots_tab'), - url(r'^create/$', shares_views.CreateView.as_view(), name='create'), - url(r'^create_security_service$', - security_services_views.CreateView.as_view(), - name='create_security_service'), - url(r'^create_share_network$', - share_networks_views.Create.as_view(), - name='create_share_network'), - url(r'^share_networks/(?P[^/]+)/update$', - share_networks_views.Update.as_view(), - name='update_share_network'), - url(r'^share_networks/(?P[^/]+)$', - share_networks_views.Detail.as_view(), - name='share_network_detail'), - url(r'^security_services/(?P[^/]+)/update/$', - security_services_views.UpdateView.as_view(), - name='update_security_service'), - url(r'^security_services/(?P[^/]+)$', - security_services_views.Detail.as_view(), - name='security_service_detail'), - url(r'^snapshots/(?P[^/]+)$', - snapshot_views.SnapshotDetailView.as_view(), - name='snapshot-detail'), - url(r'^(?P[^/]+)/create_snapshot/$', - snapshot_views.CreateSnapshotView.as_view(), - name='create_snapshot'), - url(r'^(?P[^/]+)/edit_snapshot/$', - snapshot_views.UpdateView.as_view(), - name='edit_snapshot'), - url(r'^(?P[^/]+)/rules/$', + urls.url( + r'^$', + shares_views.SharesView.as_view(), + name='index'), + urls.url( + r'^create/$', + shares_views.CreateView.as_view(), + name='create'), + urls.url( + r'^(?P[^/]+)/rules/$', shares_views.ManageRulesView.as_view(), name='manage_rules'), - url(r'^(?P[^/]+)/rule_add/$', + urls.url( + r'^(?P[^/]+)/rule_add/$', shares_views.AddRuleView.as_view(), name='rule_add'), - url(r'^(?P[^/]+)/$', + urls.url( + r'^(?P[^/]+)/$', shares_views.DetailView.as_view(), name='detail'), - url(r'^(?P[^/]+)/update/$', + urls.url( + r'^(?P[^/]+)/update/$', shares_views.UpdateView.as_view(), name='update'), - url(r'^(?P[^/]+)/update_metadata/$', + urls.url( + r'^(?P[^/]+)/update_metadata/$', shares_views.UpdateMetadataView.as_view(), name='update_metadata'), - url(r'^(?P[^/]+)/extend/$', + urls.url( + r'^(?P[^/]+)/extend/$', shares_views.ExtendView.as_view(), name='extend'), - url(r'^(?P[^/]+)/revert/$', + urls.url( + r'^(?P[^/]+)/revert/$', shares_views.RevertView.as_view(), name='revert'), - url(r'^(?P[^/]+)/snapshot_rules/$', - snapshot_views.ManageRulesView.as_view(), - name='snapshot_manage_rules'), - url(r'^(?P[^/]+)/snapshot_rule_add/$', - snapshot_views.AddRuleView.as_view(), - name='snapshot_rule_add'), ] if manila.is_replication_enabled(): urlpatterns.extend([ - url(r'^(?P[^/]+)/create_replica/$', + urls.url( + r'^(?P[^/]+)/create_replica/$', replica_views.CreateReplicaView.as_view(), name='create_replica'), - url(r'^(?P[^/]+)/replicas/$', + urls.url( + r'^(?P[^/]+)/replicas/$', replica_views.ManageReplicasView.as_view(), name='manage_replicas'), - url(r'^replica/(?P[^/]+)$', + urls.url( + r'^replica/(?P[^/]+)$', replica_views.DetailReplicaView.as_view(), name='replica_detail'), - url(r'^replica/(?P[^/]+)/set_replica_as_active$', + urls.url( + r'^replica/(?P[^/]+)/set_replica_as_active$', replica_views.SetReplicaAsActiveView.as_view(), name='set_replica_as_active'), ]) diff --git a/manila_ui/dashboards/project/shares/views.py b/manila_ui/dashboards/project/shares/views.py index 39c30e25..0c55624c 100644 --- a/manila_ui/dashboards/project/shares/views.py +++ b/manila_ui/dashboards/project/shares/views.py @@ -12,29 +12,342 @@ # License for the specific language governing permissions and limitations # under the License. +from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse_lazy from django.utils.translation import ugettext_lazy as _ +from horizon import exceptions +from horizon import forms +from horizon import tables from horizon import tabs +from horizon.utils import memoized -from manila_ui.dashboards.project.shares.security_services \ - import tabs as security_services_tabs -from manila_ui.dashboards.project.shares.share_networks \ - import tabs as share_networks_tabs -from manila_ui.dashboards.project.shares.shares \ - import tabs as shares_tabs -from manila_ui.dashboards.project.shares.snapshots \ - import tabs as snapshots_tabs +from manila_ui.api import manila +from manila_ui.dashboards.project.shares import forms as share_form +from manila_ui.dashboards.project.shares import tables as shares_tables +from manila_ui.dashboards.project.shares import tabs as shares_tabs +from manila_ui.dashboards import utils as ui_utils +from openstack_dashboard.usage import quotas -class ShareTabs(tabs.TabGroup): - slug = "share_tabs" - tabs = (shares_tabs.SharesTab, - snapshots_tabs.SnapshotsTab, - share_networks_tabs.ShareNetworkTab, - security_services_tabs.SecurityServiceTab,) - sticky = True +class ShareTableMixIn(object): + def _get_shares(self, search_opts=None): + try: + return manila.share_list(self.request, search_opts=search_opts) + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve share list.')) + return [] + + def _set_id_if_nameless(self, shares): + for share in shares: + # It is possible to create a share with no name + if not share.name: + share.name = share.id -class IndexView(tabs.TabbedTableView): - tab_group_class = ShareTabs +class SharesView(tables.MultiTableView, ShareTableMixIn): + table_classes = ( + shares_tables.SharesTable, + ) template_name = "project/shares/index.html" page_title = _("Shares") + + @memoized.memoized_method + def get_shares_data(self): + share_nets_names = {} + share_nets = manila.share_network_list(self.request) + for share_net in share_nets: + share_nets_names[share_net.id] = share_net.name + try: + shares = manila.share_list(self.request) + for share in shares: + share.share_network = ( + share_nets_names.get(share.share_network_id) or + share.share_network_id) + share.metadata = ui_utils.metadata_to_str(share.metadata) + + snapshots = manila.share_snapshot_list(self.request, detailed=True) + share_ids_with_snapshots = [] + for snapshot in snapshots: + share_ids_with_snapshots.append(snapshot.to_dict()['share_id']) + for share in shares: + if share.to_dict()['id'] in share_ids_with_snapshots: + setattr(share, 'has_snapshot', True) + else: + setattr(share, 'has_snapshot', False) + except Exception: + exceptions.handle( + self.request, _('Unable to retrieve share list.')) + return [] + # Gather our tenants to correlate against IDs + return shares + + +class DetailView(tabs.TabView): + tab_group_class = shares_tabs.ShareDetailTabs + template_name = 'project/shares/detail.html' + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + share = self.get_data() + share_display_name = share.name or share.id + context["share"] = share + context["share_display_name"] = share_display_name + context["page_title"] = _("Share Details: " + "%(share_display_name)s") % { + 'share_display_name': share_display_name} + return context + + @memoized.memoized_method + def get_data(self): + try: + share_id = self.kwargs['share_id'] + share = manila.share_get(self.request, share_id) + share.rules = manila.share_rules_list(self.request, share_id) + share.export_locations = manila.share_export_location_list( + self.request, share_id) + export_locations = [ + exp['path'] for exp in share.export_locations] + share.el_size = ui_utils.calculate_longest_str_size( + export_locations) + except Exception: + redirect = reverse('horizon:project:shares:index') + exceptions.handle(self.request, + _('Unable to retrieve share details.'), + redirect=redirect) + return share + + def get_tabs(self, request, *args, **kwargs): + share = self.get_data() + return self.tab_group_class(request, share=share, **kwargs) + + +class CreateView(forms.ModalFormView): + form_class = share_form.CreateForm + form_id = "create_share" + template_name = 'project/shares/create.html' + modal_header = _("Create Share") + modal_id = "create_share_modal" + submit_label = _("Create") + submit_url = reverse_lazy("horizon:project:shares:create") + success_url = reverse_lazy("horizon:project:shares:index") + page_title = _('Create a Share') + + def get_context_data(self, **kwargs): + context = super(CreateView, self).get_context_data(**kwargs) + try: + context['usages'] = quotas.tenant_limit_usages(self.request) + except Exception: + exceptions.handle(self.request) + return context + + +class UpdateView(forms.ModalFormView): + form_class = share_form.UpdateForm + form_id = "update_share" + template_name = 'project/shares/update.html' + modal_header = _("Edit Share") + modal_id = "update_share_modal" + submit_label = _("Edit") + submit_url = "horizon:project:shares:update" + success_url = reverse_lazy("horizon:project:shares:index") + page_title = _('Edit Share') + + def get_object(self): + if not hasattr(self, "_object"): + vol_id = self.kwargs['share_id'] + try: + self._object = manila.share_get(self.request, vol_id) + except Exception: + msg = _('Unable to retrieve share.') + url = reverse('horizon:project:shares:index') + exceptions.handle(self.request, msg, redirect=url) + return self._object + + def get_context_data(self, **kwargs): + context = super(UpdateView, self).get_context_data(**kwargs) + return context + + def get_initial(self): + self.submit_url = reverse(self.submit_url, kwargs=self.kwargs) + share = self.get_object() + return {'share_id': self.kwargs["share_id"], + 'name': share.name, + 'description': share.description} + + +class UpdateMetadataView(forms.ModalFormView): + form_class = share_form.UpdateMetadataForm + form_id = "update_share_metadata" + template_name = 'project/shares/update_metadata.html' + modal_header = _("Edit Share Metadata") + modal_id = "update_share_metadata_modal" + submit_label = _("Save Changes") + submit_url = "horizon:project:shares:update_metadata" + success_url = reverse_lazy("horizon:project:shares:index") + page_title = _('Edit Share Metadata') + + def get_object(self): + if not hasattr(self, "_object"): + sh_id = self.kwargs['share_id'] + try: + self._object = manila.share_get(self.request, sh_id) + except Exception: + msg = _('Unable to retrieve share.') + url = reverse('horizon:project:shares:index') + exceptions.handle(self.request, msg, redirect=url) + return self._object + + def get_context_data(self, **kwargs): + context = super(UpdateMetadataView, self).get_context_data(**kwargs) + args = (self.get_object().id,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + share = self.get_object() + return {'share_id': self.kwargs["share_id"], + 'metadata': share.metadata} + + +class AddRuleView(forms.ModalFormView): + form_class = share_form.AddRule + form_id = "rule_add" + template_name = 'project/shares/rule_add.html' + modal_header = _("Add Rule") + modal_id = "rule_add_modal" + submit_label = _("Add") + submit_url = "horizon:project:shares:rule_add" + success_url = reverse_lazy("horizon:project:shares:index") + page_title = _('Add Rule') + + def get_object(self): + if not hasattr(self, "_object"): + vol_id = self.kwargs['share_id'] + try: + self._object = manila.share_get(self.request, vol_id) + except Exception: + msg = _('Unable to retrieve share.') + url = reverse('horizon:project:shares:index') + exceptions.handle(self.request, msg, redirect=url) + return self._object + + def get_context_data(self, **kwargs): + context = super(AddRuleView, self).get_context_data(**kwargs) + args = (self.get_object().id,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + share = self.get_object() + return {'share_id': self.kwargs["share_id"], + 'name': share.name, + 'description': share.description} + + def get_success_url(self): + return reverse("horizon:project:shares:manage_rules", + args=[self.kwargs['share_id']]) + + +class ManageRulesView(tables.DataTableView): + table_class = shares_tables.RulesTable + template_name = 'project/shares/manage_rules.html' + + def get_context_data(self, **kwargs): + context = super(ManageRulesView, self).get_context_data(**kwargs) + share = manila.share_get(self.request, self.kwargs['share_id']) + context['share_display_name'] = share.name or share.id + context["share"] = self.get_data() + context["page_title"] = _("Share Rules: " + "%(share_display_name)s") % { + 'share_display_name': context['share_display_name']} + return context + + @memoized.memoized_method + def get_data(self): + try: + share_id = self.kwargs['share_id'] + rules = manila.share_rules_list(self.request, share_id) + except Exception: + redirect = reverse('horizon:project:shares:index') + exceptions.handle(self.request, + _('Unable to retrieve share rules.'), + redirect=redirect) + return rules + + +class ExtendView(forms.ModalFormView): + form_class = share_form.ExtendForm + form_id = "extend_share" + template_name = 'project/shares/extend.html' + modal_header = _("Extend Share") + modal_id = "extend_share_modal" + submit_label = _("Extend") + submit_url = "horizon:project:shares:extend" + success_url = reverse_lazy("horizon:project:shares:index") + page_title = _('Extend Share') + + @memoized.memoized_method + def get_object(self): + try: + return manila.share_get(self.request, self.kwargs['share_id']) + except Exception: + exceptions.handle(self.request, _('Unable to retrieve share.')) + + def get_context_data(self, **kwargs): + context = super(ExtendView, self).get_context_data(**kwargs) + args = (self.get_object().id,) + context['submit_url'] = reverse(self.submit_url, args=args) + try: + context['usages'] = quotas.tenant_limit_usages(self.request) + context['usages']['totalShareGigabytesUsed'] -= int( + self.get_object().size) + except Exception: + exceptions.handle(self.request) + + return context + + def get_initial(self): + share = self.get_object() + if not share or isinstance(share, Exception): + raise exceptions.NotFound() + return { + 'share_id': self.kwargs["share_id"], + 'name': share.name or share.id, + 'orig_size': share.size, + 'new_size': int(share.size) + 1, + } + + +class RevertView(forms.ModalFormView): + form_class = share_form.RevertForm + form_id = "revert_share" + template_name = 'project/shares/revert.html' + modal_header = _("Revert Share to a Snapshot") + modal_id = "revert_share_modal" + submit_label = _("Revert share to a snapshot") + submit_url = "horizon:project:shares:revert" + success_url = reverse_lazy("horizon:project:shares:index") + page_title = _('Revert Share to a Snapshot') + + @memoized.memoized_method + def get_object(self): + try: + return manila.share_get(self.request, self.kwargs['share_id']) + except Exception: + exceptions.handle(self.request, _('Unable to retrieve share.')) + + def get_context_data(self, **kwargs): + context = super(self.__class__, self).get_context_data(**kwargs) + args = (self.get_object().id,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + share = self.get_object() + if not share or isinstance(share, Exception): + raise exceptions.NotFound() + return { + 'share_id': self.kwargs["share_id"], + 'name': share.name or share.id, + } 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 c839b00a..90a8b980 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 @@ -1,3 +1,17 @@ +# Copyright 2017 Mirantis Inc. +# +# 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. + # The slug of the panel group to be added to HORIZON_CONFIG. Required. PANEL_GROUP = 'share' # The display name of the PANEL_GROUP. Required. diff --git a/manila_ui/local/enabled/_90_manila_project_shares.py b/manila_ui/local/enabled/_80_manila_project_add_share_panel_group.py similarity index 70% rename from manila_ui/local/enabled/_90_manila_project_shares.py rename to manila_ui/local/enabled/_80_manila_project_add_share_panel_group.py index 99258b3b..2a5ab90e 100644 --- a/manila_ui/local/enabled/_90_manila_project_shares.py +++ b/manila_ui/local/enabled/_80_manila_project_add_share_panel_group.py @@ -1,4 +1,4 @@ -# Copyright 2016 Mirantis Inc. +# Copyright 2017 Mirantis Inc. # # 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 @@ -14,13 +14,14 @@ from manila_ui import exceptions -PANEL_DASHBOARD = 'project' -PANEL_GROUP = 'compute' -PANEL = 'shares' -ADD_PANEL = 'manila_ui.dashboards.project.shares.panel.Shares' -# ADD_INSTALLED_APPS enables using html templates from within the plugin -ADD_INSTALLED_APPS = ['manila_ui.dashboards.project'] +# The slug of the panel group to be added to HORIZON_CONFIG. Required. +PANEL_GROUP = 'share' +# The display name of the PANEL_GROUP. Required. +PANEL_GROUP_NAME = 'Share' +# The slug of the dashboard the PANEL_GROUP associated with. Required. +PANEL_GROUP_DASHBOARD = 'project' + ADD_EXCEPTIONS = { 'recoverable': exceptions.RECOVERABLE, diff --git a/manila_ui/local/enabled/_9010_manila_project_add_shares_panel_to_share_panel_group.py b/manila_ui/local/enabled/_9010_manila_project_add_shares_panel_to_share_panel_group.py new file mode 100644 index 00000000..d0e4647e --- /dev/null +++ b/manila_ui/local/enabled/_9010_manila_project_add_shares_panel_to_share_panel_group.py @@ -0,0 +1,18 @@ +# Copyright 2017 Mirantis Inc. +# +# 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. + +PANEL_DASHBOARD = 'project' +PANEL_GROUP = 'share' +PANEL = 'shares' +ADD_PANEL = 'manila_ui.dashboards.project.shares.panel.Shares' diff --git a/manila_ui/local/enabled/_9020_manila_project_add_share_snapshots_panel_to_share_panel_group.py b/manila_ui/local/enabled/_9020_manila_project_add_share_snapshots_panel_to_share_panel_group.py new file mode 100644 index 00000000..1c1636cf --- /dev/null +++ b/manila_ui/local/enabled/_9020_manila_project_add_share_snapshots_panel_to_share_panel_group.py @@ -0,0 +1,18 @@ +# Copyright 2017 Mirantis Inc. +# +# 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. + +PANEL_DASHBOARD = 'project' +PANEL_GROUP = 'share' +PANEL = 'share_snapshots' +ADD_PANEL = 'manila_ui.dashboards.project.share_snapshots.panel.ShareSnapshots' diff --git a/manila_ui/local/enabled/_9040_manila_project_add_share_networks_panel_to_share_panel_group.py b/manila_ui/local/enabled/_9040_manila_project_add_share_networks_panel_to_share_panel_group.py new file mode 100644 index 00000000..a03ed200 --- /dev/null +++ b/manila_ui/local/enabled/_9040_manila_project_add_share_networks_panel_to_share_panel_group.py @@ -0,0 +1,18 @@ +# Copyright 2017 Mirantis Inc. +# +# 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. + +PANEL_DASHBOARD = 'project' +PANEL_GROUP = 'share' +PANEL = 'share_networks' +ADD_PANEL = 'manila_ui.dashboards.project.share_networks.panel.ShareNetworks' diff --git a/manila_ui/local/enabled/_9050_manila_project_add_security_services_panel_to_share_panel_group.py b/manila_ui/local/enabled/_9050_manila_project_add_security_services_panel_to_share_panel_group.py new file mode 100644 index 00000000..f6c00ab3 --- /dev/null +++ b/manila_ui/local/enabled/_9050_manila_project_add_security_services_panel_to_share_panel_group.py @@ -0,0 +1,19 @@ +# Copyright 2017 Mirantis Inc. +# +# 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. + +PANEL_DASHBOARD = 'project' +PANEL_GROUP = 'share' +PANEL = 'security_services' +ADD_PANEL = ( + 'manila_ui.dashboards.project.security_services.panel.SecurityServices') diff --git a/manila_ui/tests/dashboards/admin/security_services/tests.py b/manila_ui/tests/dashboards/admin/security_services/tests.py index 464f6495..6635ceb6 100644 --- a/manila_ui/tests/dashboards/admin/security_services/tests.py +++ b/manila_ui/tests/dashboards/admin/security_services/tests.py @@ -20,7 +20,7 @@ from openstack_dashboard.api import keystone as api_keystone from manila_ui.api import manila as api_manila from manila_ui.dashboards.admin import utils -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test from manila_ui.tests.test_data import keystone_data diff --git a/manila_ui/tests/dashboards/admin/share_instances/tests.py b/manila_ui/tests/dashboards/admin/share_instances/tests.py index 26470811..f44afce7 100644 --- a/manila_ui/tests/dashboards/admin/share_instances/tests.py +++ b/manila_ui/tests/dashboards/admin/share_instances/tests.py @@ -19,7 +19,7 @@ import mock from openstack_dashboard.api import keystone as api_keystone from manila_ui.api import manila as api_manila -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test INDEX_URL = reverse('horizon:admin:share_instances:index') diff --git a/manila_ui/tests/dashboards/admin/share_networks/tests.py b/manila_ui/tests/dashboards/admin/share_networks/tests.py index e5b090b4..53445842 100644 --- a/manila_ui/tests/dashboards/admin/share_networks/tests.py +++ b/manila_ui/tests/dashboards/admin/share_networks/tests.py @@ -22,7 +22,7 @@ from openstack_dashboard.api import neutron as api_neutron from manila_ui.api import manila as api_manila from manila_ui.dashboards.admin import utils -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test from manila_ui.tests.test_data import keystone_data diff --git a/manila_ui/tests/dashboards/admin/share_servers/tests.py b/manila_ui/tests/dashboards/admin/share_servers/tests.py index 56ec6a24..3bab8571 100644 --- a/manila_ui/tests/dashboards/admin/share_servers/tests.py +++ b/manila_ui/tests/dashboards/admin/share_servers/tests.py @@ -19,7 +19,7 @@ import mock from openstack_dashboard.api import keystone as api_keystone from manila_ui.api import manila as api_manila -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test INDEX_URL = reverse('horizon:admin:share_servers:index') diff --git a/manila_ui/tests/dashboards/admin/share_snapshots/tests.py b/manila_ui/tests/dashboards/admin/share_snapshots/tests.py index 35394ef9..d4cb6c0b 100644 --- a/manila_ui/tests/dashboards/admin/share_snapshots/tests.py +++ b/manila_ui/tests/dashboards/admin/share_snapshots/tests.py @@ -20,7 +20,7 @@ from openstack_dashboard.api import keystone as api_keystone from manila_ui.api import manila as api_manila from manila_ui.dashboards.admin import utils -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test from manila_ui.tests.test_data import keystone_data diff --git a/manila_ui/tests/dashboards/admin/share_types/tests.py b/manila_ui/tests/dashboards/admin/share_types/tests.py index f995575b..8778efc0 100644 --- a/manila_ui/tests/dashboards/admin/share_types/tests.py +++ b/manila_ui/tests/dashboards/admin/share_types/tests.py @@ -20,7 +20,7 @@ from openstack_dashboard.api import neutron as api_neutron from manila_ui.api import manila as api_manila from manila_ui.dashboards.admin import utils -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test from manila_ui.tests.test_data import keystone_data diff --git a/manila_ui/tests/dashboards/admin/shares/replicas/tests.py b/manila_ui/tests/dashboards/admin/shares/replicas/tests.py index e694da28..eae1ee35 100644 --- a/manila_ui/tests/dashboards/admin/shares/replicas/tests.py +++ b/manila_ui/tests/dashboards/admin/shares/replicas/tests.py @@ -18,7 +18,7 @@ from django.core.urlresolvers import reverse import mock from manila_ui.api import manila as api_manila -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test from openstack_dashboard.api import neutron diff --git a/manila_ui/tests/dashboards/admin/shares/tests.py b/manila_ui/tests/dashboards/admin/shares/tests.py index 79386857..8a7dbcfe 100644 --- a/manila_ui/tests/dashboards/admin/shares/tests.py +++ b/manila_ui/tests/dashboards/admin/shares/tests.py @@ -22,7 +22,7 @@ from openstack_dashboard.usage import quotas from manila_ui.api import manila as api_manila from manila_ui.dashboards.admin import utils -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test from manila_ui.tests.test_data import keystone_data diff --git a/manila_ui/dashboards/project/shares/snapshots/__init__.py b/manila_ui/tests/dashboards/project/security_services/__init__.py similarity index 100% rename from manila_ui/dashboards/project/shares/snapshots/__init__.py rename to manila_ui/tests/dashboards/project/security_services/__init__.py diff --git a/manila_ui/tests/dashboards/project/shares/security_services/tests.py b/manila_ui/tests/dashboards/project/security_services/tests.py similarity index 82% rename from manila_ui/tests/dashboards/project/shares/security_services/tests.py rename to manila_ui/tests/dashboards/project/security_services/tests.py index 7eeec597..dc611dc0 100644 --- a/manila_ui/tests/dashboards/project/shares/security_services/tests.py +++ b/manila_ui/tests/dashboards/project/security_services/tests.py @@ -19,15 +19,13 @@ from django.core.urlresolvers import reverse from horizon import exceptions as horizon_exceptions import mock - -from manila_ui.api import manila as api_manila -from manila_ui.tests.dashboards.project.shares import test_data - -from manila_ui.tests import helpers as test - from openstack_dashboard import api -SHARE_INDEX_URL = reverse('horizon:project:shares:index') +from manila_ui.api import manila as api_manila +from manila_ui.tests.dashboards.project import test_data +from manila_ui.tests import helpers as test + +INDEX_URL = reverse('horizon:project:security_services:index') class SecurityServicesViewTests(test.TestCase): @@ -46,7 +44,8 @@ class SecurityServicesViewTests(test.TestCase): 'domain': 'TEST', 'server': 'testserver', } - url = reverse('horizon:project:shares:create_security_service') + url = reverse( + 'horizon:project:security_services:security_service_create') self.mock_object( api_manila, "security_service_create", mock.Mock(return_value=sec_service)) @@ -57,10 +56,9 @@ class SecurityServicesViewTests(test.TestCase): del formData['confirm_password'] api_manila.security_service_create.assert_called_with( mock.ANY, **formData) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) def test_delete_security_service(self): - url = reverse('horizon:project:shares:index') security_service = test_data.sec_service formData = { 'action': 'security_services__delete__%s' % security_service.id, @@ -70,20 +68,21 @@ class SecurityServicesViewTests(test.TestCase): api_manila, "security_service_list", mock.Mock(return_value=[security_service])) - res = self.client.post(url, formData) + res = self.client.post(INDEX_URL, formData) api_manila.security_service_list.assert_called_with(mock.ANY) api_manila.security_service_delete.assert_called_with( mock.ANY, security_service.id) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) def test_detail_view(self): sec_service = test_data.sec_service self.mock_object( api_manila, "security_service_get", mock.Mock(return_value=sec_service)) - url = reverse('horizon:project:shares:security_service_detail', - args=[sec_service.id]) + url = reverse( + 'horizon:project:security_services:security_service_detail', + args=[sec_service.id]) res = self.client.get(url) @@ -101,22 +100,24 @@ class SecurityServicesViewTests(test.TestCase): mock.ANY, sec_service.id) def test_detail_view_with_exception(self): - url = reverse('horizon:project:shares:security_service_detail', - args=[test_data.sec_service.id]) + url = reverse( + 'horizon:project:security_services:security_service_detail', + args=[test_data.sec_service.id]) self.mock_object( api_manila, "security_service_get", mock.Mock(side_effect=horizon_exceptions.NotFound(404))) res = self.client.get(url) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) api_manila.security_service_get.assert_called_once_with( mock.ANY, test_data.sec_service.id) def test_update_security_service_get(self): sec_service = test_data.sec_service - url = reverse('horizon:project:shares:update_security_service', - args=[sec_service.id]) + url = reverse( + 'horizon:project:security_services:security_service_update', + args=[sec_service.id]) self.mock_object( api_manila, "security_service_get", mock.Mock(return_value=sec_service)) @@ -127,14 +128,15 @@ class SecurityServicesViewTests(test.TestCase): self.assertNoMessages() self.assertTemplateUsed( - res, 'project/shares/security_services/update.html') + res, 'project/security_services/update.html') api_manila.security_service_get.assert_called_once_with( mock.ANY, sec_service.id) def test_update_security_service_post(self): sec_service = test_data.sec_service - url = reverse('horizon:project:shares:update_security_service', - args=[sec_service.id]) + url = reverse( + 'horizon:project:security_services:security_service_update', + args=[sec_service.id]) formData = { 'method': 'UpdateForm', 'name': sec_service.name, @@ -147,7 +149,7 @@ class SecurityServicesViewTests(test.TestCase): res = self.client.post(url, formData) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) api_manila.security_service_get.assert_called_once_with( mock.ANY, sec_service.id) api_manila.security_service_update.assert_called_once_with( diff --git a/manila_ui/tests/dashboards/project/shares/security_services/__init__.py b/manila_ui/tests/dashboards/project/share_networks/__init__.py similarity index 100% rename from manila_ui/tests/dashboards/project/shares/security_services/__init__.py rename to manila_ui/tests/dashboards/project/share_networks/__init__.py diff --git a/manila_ui/tests/dashboards/project/shares/share_networks/tests.py b/manila_ui/tests/dashboards/project/share_networks/tests.py similarity index 92% rename from manila_ui/tests/dashboards/project/shares/share_networks/tests.py rename to manila_ui/tests/dashboards/project/share_networks/tests.py index 2256bdaf..93c58d26 100644 --- a/manila_ui/tests/dashboards/project/shares/share_networks/tests.py +++ b/manila_ui/tests/dashboards/project/share_networks/tests.py @@ -14,26 +14,23 @@ from django.core.urlresolvers import reverse import mock - from neutronclient.client import exceptions from openstack_auth import policy +from openstack_dashboard import api from manila_ui.api import manila as api_manila from manila_ui.api import network as api_manila_network -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test -from openstack_dashboard import api - - -SHARE_INDEX_URL = reverse('horizon:project:shares:index') +INDEX_URL = reverse('horizon:project:share_networks:index') class ShareNetworksViewTests(test.TestCase): def test_create_share_network(self): share_net = test_data.active_share_network - url = reverse('horizon:project:shares:create_share_network') + url = reverse('horizon:project:share_networks:share_network_create') neutron_net_id = self.networks.first().id formData = { 'name': 'new_share_network', @@ -66,7 +63,6 @@ class ShareNetworksViewTests(test.TestCase): ], any_order=True) def test_delete_share_network(self): - url = reverse('horizon:project:shares:index') share_network = test_data.inactive_share_network formData = {'action': 'share_networks__delete__%s' % share_network.id} self.mock_object(api_manila, "share_network_delete") @@ -81,9 +77,9 @@ class ShareNetworksViewTests(test.TestCase): api.neutron, "subnet_list", mock.Mock(return_value=self.subnets.list())) - res = self.client.post(url, formData) + res = self.client.post(INDEX_URL, formData) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) api_manila.share_network_list.assert_called_once_with( mock.ANY, detailed=True) api_manila.share_network_delete.assert_called_once_with( @@ -107,7 +103,7 @@ class ShareNetworksViewTests(test.TestCase): api.neutron, "network_get", mock.Mock(return_value=network)) self.mock_object( api.neutron, "subnet_get", mock.Mock(return_value=subnet)) - url = reverse('horizon:project:shares:share_network_detail', + url = reverse('horizon:project:share_networks:share_network_detail', args=[share_net.id]) res = self.client.get(url) @@ -119,7 +115,7 @@ class ShareNetworksViewTests(test.TestCase): self.assertContains(res, "
%s
" % share_net.id, 1, 200) self.assertContains(res, "
%s
" % network.name_or_id, 1, 200) self.assertContains(res, "
%s
" % subnet.name_or_id, 1, 200) - self.assertContains(res, "%s" % (sec_service.id, sec_service.name), 1, 200) self.assertNoMessages() @@ -137,7 +133,7 @@ class ShareNetworksViewTests(test.TestCase): def test_detail_view_network_not_found(self): share_net = test_data.active_share_network sec_service = test_data.sec_service - url = reverse('horizon:project:shares:share_network_detail', + url = reverse('horizon:project:share_networks:share_network_detail', args=[share_net.id]) self.mock_object( api_manila, "share_server_list", mock.Mock(return_value=[])) @@ -164,7 +160,7 @@ class ShareNetworksViewTests(test.TestCase): self.assertNotContains(res, "
%s
" % share_net.neutron_net_id) self.assertNotContains(res, "
%s
" % share_net.neutron_subnet_id) - self.assertContains(res, "%s" % (sec_service.id, sec_service.name), 1, 200) self.assertNoMessages() @@ -186,7 +182,7 @@ class ShareNetworksViewTests(test.TestCase): 'name': share_net.name, 'description': share_net.description, } - url = reverse('horizon:project:shares:update_share_network', + url = reverse('horizon:project:share_networks:share_network_update', args=[share_net.id]) self.mock_object(api_manila, "share_network_update") self.mock_object( @@ -203,7 +199,7 @@ class ShareNetworksViewTests(test.TestCase): res = self.client.post(url, formData) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) api_manila.share_network_security_service_list.assert_called_once_with( mock.ANY, share_net.id) api_manila.security_service_list.assert_has_calls([ diff --git a/manila_ui/tests/dashboards/project/shares/share_networks/__init__.py b/manila_ui/tests/dashboards/project/share_snapshots/__init__.py similarity index 100% rename from manila_ui/tests/dashboards/project/shares/share_networks/__init__.py rename to manila_ui/tests/dashboards/project/share_snapshots/__init__.py diff --git a/manila_ui/tests/dashboards/project/shares/snapshots/test_tables.py b/manila_ui/tests/dashboards/project/share_snapshots/test_tables.py similarity index 94% rename from manila_ui/tests/dashboards/project/shares/snapshots/test_tables.py rename to manila_ui/tests/dashboards/project/share_snapshots/test_tables.py index 88c75959..a82ab47c 100644 --- a/manila_ui/tests/dashboards/project/shares/snapshots/test_tables.py +++ b/manila_ui/tests/dashboards/project/share_snapshots/test_tables.py @@ -17,7 +17,7 @@ import ddt from django.core.handlers import wsgi import mock -from manila_ui.dashboards.project.shares.snapshots import tables +from manila_ui.dashboards.project.share_snapshots import tables from manila_ui.tests import helpers as base @@ -28,7 +28,7 @@ class CreateSnapshotTests(base.APITestCase): super(self.__class__, self).setUp() FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'} self.request = wsgi.WSGIRequest(FAKE_ENVIRON) - self.create_snapshot = tables.CreateSnapshot() + self.create_snapshot = tables.CreateShareSnapshot() def _get_fake_share(self, **kwargs): if 'status' not in kwargs.keys(): diff --git a/manila_ui/tests/dashboards/project/shares/snapshots/tests.py b/manila_ui/tests/dashboards/project/share_snapshots/tests.py similarity index 81% rename from manila_ui/tests/dashboards/project/shares/snapshots/tests.py rename to manila_ui/tests/dashboards/project/share_snapshots/tests.py index 226e413b..41cbefe5 100644 --- a/manila_ui/tests/dashboards/project/shares/snapshots/tests.py +++ b/manila_ui/tests/dashboards/project/share_snapshots/tests.py @@ -15,16 +15,14 @@ import ddt from django.core.urlresolvers import reverse import mock - -from manila_ui.api import manila as api_manila -from manila_ui.tests.dashboards.project.shares import test_data -from manila_ui.tests import helpers as test - from openstack_dashboard.api import neutron from openstack_dashboard.usage import quotas -SHARE_INDEX_URL = reverse('horizon:project:shares:index') -SHARE_SNAPSHOTS_TAB_URL = reverse('horizon:project:shares:snapshots_tab') +from manila_ui.api import manila as api_manila +from manila_ui.tests.dashboards.project import test_data +from manila_ui.tests import helpers as test + +INDEX_URL = reverse('horizon:project:share_snapshots:index') @ddt.ddt @@ -36,7 +34,7 @@ class SnapshotSnapshotViewTests(test.TestCase): 'maxTotalShareGigabytes': 250, 'totalShareGigabytesUsed': 20, } - url = reverse('horizon:project:shares:create_snapshot', + url = reverse('horizon:project:share_snapshots:share_snapshot_create', args=[share.id]) self.mock_object( quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) @@ -46,13 +44,12 @@ class SnapshotSnapshotViewTests(test.TestCase): res = self.client.get(url) self.assertNoMessages() - self.assertTemplateUsed( - res, 'project/shares/snapshots/create_snapshot.html') + self.assertTemplateUsed(res, 'project/share_snapshots/create.html') def test_create_snapshot_post(self): share = test_data.share snapshot = test_data.snapshot - url = reverse('horizon:project:shares:create_snapshot', + url = reverse('horizon:project:share_snapshots:share_snapshot_create', args=[share.id]) formData = { 'name': 'new_snapshot', @@ -70,32 +67,31 @@ class SnapshotSnapshotViewTests(test.TestCase): api_manila.share_snapshot_create.assert_called_once_with( mock.ANY, share.id, formData['name'], formData['description']) - self.assertRedirectsNoFollow(res, SHARE_SNAPSHOTS_TAB_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) def test_delete_snapshot(self): share = test_data.share snapshot = test_data.snapshot - formData = {'action': 'snapshots__delete__%s' % snapshot.id} + formData = {'action': 'share_snapshots__delete__%s' % snapshot.id} self.mock_object(api_manila, "share_snapshot_delete") self.mock_object( api_manila, "share_snapshot_list", mock.Mock(return_value=[snapshot])) self.mock_object( api_manila, "share_list", mock.Mock(return_value=[share])) - url = reverse('horizon:project:shares:index') - res = self.client.post(url, formData) + res = self.client.post(INDEX_URL, formData) - api_manila.share_snapshot_delete.assert_called_once_with( - mock.ANY, test_data.snapshot.id) + self.assertRedirectsNoFollow(res, INDEX_URL) api_manila.share_snapshot_list.assert_called_once_with(mock.ANY) api_manila.share_list.assert_called_once_with(mock.ANY) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + api_manila.share_snapshot_delete.assert_called_once_with( + mock.ANY, test_data.snapshot.id) def test_detail_view(self): snapshot = test_data.snapshot share = test_data.share - url = reverse('horizon:project:shares:snapshot-detail', + url = reverse('horizon:project:share_snapshots:share_snapshot_detail', args=[snapshot.id]) self.mock_object( api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot)) @@ -110,7 +106,7 @@ class SnapshotSnapshotViewTests(test.TestCase): self.assertContains(res, "
%s
" % snapshot.name, 1, 200) self.assertContains(res, "
%s
" % snapshot.id, 1, 200) self.assertContains(res, - "
%s
" % + "
%s
" % (snapshot.share_id, share.name), 1, 200) self.assertContains(res, "
%s GiB
" % snapshot.size, 1, 200) self.assertNoMessages() @@ -123,7 +119,7 @@ class SnapshotSnapshotViewTests(test.TestCase): share = test_data.share_mount_snapshot rules = [test_data.ip_rule, test_data.user_rule, test_data.cephx_rule] export_locations = test_data.user_snapshot_export_locations - url = reverse('horizon:project:shares:snapshot-detail', + url = reverse('horizon:project:share_snapshots:share_snapshot_detail', args=[snapshot.id]) self.mock_object( api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot)) @@ -144,7 +140,7 @@ class SnapshotSnapshotViewTests(test.TestCase): self.assertContains(res, "
%s
" % snapshot.name, 1, 200) self.assertContains(res, "
%s
" % snapshot.id, 1, 200) self.assertContains(res, - "
%s
" % + "
%s
" % (snapshot.share_id, share.name), 1, 200) self.assertContains(res, "
%s GiB
" % snapshot.size, 1, 200) for el in export_locations: @@ -167,7 +163,7 @@ class SnapshotSnapshotViewTests(test.TestCase): def test_update_snapshot_get(self): snapshot = test_data.snapshot - url = reverse('horizon:project:shares:edit_snapshot', + url = reverse('horizon:project:share_snapshots:share_snapshot_edit', args=[snapshot.id]) self.mock_object( api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot)) @@ -179,11 +175,11 @@ class SnapshotSnapshotViewTests(test.TestCase): api_manila.share_snapshot_get.assert_called_once_with( mock.ANY, snapshot.id) self.assertNoMessages() - self.assertTemplateUsed(res, 'project/shares/snapshots/update.html') + self.assertTemplateUsed(res, 'project/share_snapshots/update.html') def test_update_snapshot_post(self): snapshot = test_data.snapshot - url = reverse('horizon:project:shares:edit_snapshot', + url = reverse('horizon:project:share_snapshots:share_snapshot_edit', args=[snapshot.id]) formData = { 'method': 'UpdateForm', @@ -196,7 +192,7 @@ class SnapshotSnapshotViewTests(test.TestCase): res = self.client.post(url, formData) - self.assertRedirectsNoFollow(res, SHARE_SNAPSHOTS_TAB_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) api_manila.share_snapshot_get.assert_called_once_with( mock.ANY, snapshot.id) api_manila.share_snapshot_update.assert_called_once_with( @@ -205,49 +201,50 @@ class SnapshotSnapshotViewTests(test.TestCase): def test_list_rules(self): snapshot = test_data.snapshot rules = [test_data.ip_rule, test_data.user_rule, test_data.cephx_rule] - self.mock_object( api_manila, "share_snapshot_get", mock.Mock( return_value=snapshot)) self.mock_object( api_manila, "share_snapshot_rules_list", mock.Mock( return_value=rules)) - url = reverse('horizon:project:shares:snapshot_manage_rules', - args=[snapshot.id]) + url = reverse( + 'horizon:project:share_snapshots:share_snapshot_manage_rules', + args=[snapshot.id]) res = self.client.get(url) self.assertEqual(res.status_code, 200) - self.assertTemplateUsed(res, - 'project/shares/snapshots/manage_rules.html') + self.assertTemplateUsed( + res, + 'project/share_snapshots/manage_rules.html') api_manila.share_snapshot_rules_list.assert_called_once_with( mock.ANY, snapshot.id) def test_list_rules_exception(self): snapshot = test_data.snapshot - self.mock_object( api_manila, "share_snapshot_get", mock.Mock( return_value=snapshot)) self.mock_object( api_manila, "share_snapshot_rules_list", mock.Mock(side_effect=Exception('fake'))) - url = reverse('horizon:project:shares:snapshot_manage_rules', - args=[snapshot.id]) + url = reverse( + 'horizon:project:share_snapshots:share_snapshot_manage_rules', + args=[snapshot.id]) res = self.client.get(url) self.assertEqual(res.status_code, 302) self.assertTemplateNotUsed( - res, 'project/shares/snapshots/manage_rules.html') + res, 'project/share_snapshots/manage_rules.html') api_manila.share_snapshot_rules_list.assert_called_once_with( mock.ANY, snapshot.id) def test_create_rule_get(self): snapshot = test_data.snapshot - url = reverse('horizon:project:shares:snapshot_rule_add', - args=[snapshot.id]) - + url = reverse( + 'horizon:project:share_snapshots:share_snapshot_rule_add', + args=[snapshot.id]) self.mock_object( api_manila, "share_snapshot_get", mock.Mock( return_value=snapshot)) @@ -257,13 +254,13 @@ class SnapshotSnapshotViewTests(test.TestCase): res = self.client.get(url) self.assertNoMessages() - self.assertTemplateUsed(res, 'project/shares/snapshots/rule_add.html') + self.assertTemplateUsed(res, 'project/share_snapshots/rule_add.html') def test_create_rule_get_exception(self): snapshot = test_data.snapshot - url = reverse('horizon:project:shares:snapshot_rule_add', - args=[snapshot.id]) - + url = reverse( + 'horizon:project:share_snapshots:share_snapshot_rule_add', + args=[snapshot.id]) self.mock_object( api_manila, "share_snapshot_get", mock.Mock( side_effect=Exception('fake'))) @@ -272,20 +269,19 @@ class SnapshotSnapshotViewTests(test.TestCase): self.assertEqual(res.status_code, 302) self.assertTemplateNotUsed( - res, 'project/shares/snapshots/rule_add.html') + res, 'project/share_snapshots/rule_add.html') @ddt.data(None, Exception('fake')) def test_create_rule_post(self, exc): snapshot = test_data.snapshot - self.mock_object( - api_manila, "share_snapshot_get", mock.Mock( - return_value=snapshot)) - url = reverse('horizon:project:shares:snapshot_rule_add', - args=[snapshot.id]) - self.mock_object(api_manila, "share_snapshot_allow", - mock.Mock(side_effect=exc)) - + api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot)) + url = reverse( + 'horizon:project:share_snapshots:share_snapshot_rule_add', + args=[snapshot.id]) + self.mock_object( + api_manila, "share_snapshot_allow", + mock.Mock(side_effect=exc)) formData = { 'access_type': 'user', 'method': u'CreateForm', @@ -300,8 +296,9 @@ class SnapshotSnapshotViewTests(test.TestCase): access_to=formData['access_to']) self.assertRedirectsNoFollow( res, - reverse('horizon:project:shares:snapshot_manage_rules', - args=[snapshot.id]) + reverse( + 'horizon:project:share_snapshots:share_snapshot_manage_rules', + args=[snapshot.id]) ) @ddt.data(None, Exception('fake')) @@ -319,7 +316,7 @@ class SnapshotSnapshotViewTests(test.TestCase): api_manila, "share_snapshot_rules_list", mock.Mock( return_value=[rule])) url = reverse( - 'horizon:project:shares:snapshot_manage_rules', + 'horizon:project:share_snapshots:share_snapshot_manage_rules', args=[snapshot.id]) res = self.client.post(url, formData) diff --git a/manila_ui/tests/dashboards/project/shares/replicas/tests.py b/manila_ui/tests/dashboards/project/shares/replicas/tests.py index a0a7df51..5f0ea2c4 100644 --- a/manila_ui/tests/dashboards/project/shares/replicas/tests.py +++ b/manila_ui/tests/dashboards/project/shares/replicas/tests.py @@ -16,15 +16,14 @@ import copy import ddt from django.core.urlresolvers import reverse import mock +from openstack_dashboard.api import neutron from manila_ui.api import manila as api_manila from manila_ui.dashboards.project.shares.replicas import tables as r_tables -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test -from openstack_dashboard.api import neutron - -SHARE_INDEX_URL = reverse('horizon:project:shares:index') +INDEX_URL = reverse('horizon:project:shares:index') class FakeAZ(object): @@ -153,7 +152,7 @@ class ReplicasTests(test.TestCase): res = self.client.get(url) self.assertEqual(302, res.status_code) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) self.assertTemplateNotUsed(res, "project/shares/replicas/detail.html") api_manila.share_replica_get.assert_called_once_with( mock.ANY, self.share_replica.id) @@ -187,7 +186,7 @@ class ReplicasTests(test.TestCase): res = self.client.get(url) self.assertEqual(302, res.status_code) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) self.assertTemplateNotUsed( res, "project/shares/replicas/manage_replicas.html") api_manila.share_replica_list.assert_called_with( diff --git a/manila_ui/tests/dashboards/project/shares/shares/__init__.py b/manila_ui/tests/dashboards/project/shares/shares/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/manila_ui/tests/dashboards/project/shares/shares/tests.py b/manila_ui/tests/dashboards/project/shares/shares/tests.py deleted file mode 100644 index bf987714..00000000 --- a/manila_ui/tests/dashboards/project/shares/shares/tests.py +++ /dev/null @@ -1,709 +0,0 @@ -# Copyright (c) 2014 NetApp, Inc. -# -# 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. - -import ddt -from django.core.handlers import wsgi -from django.core.urlresolvers import reverse -import mock -import six - -from horizon import messages as horizon_messages -from manila_ui.api import manila as api_manila -from manila_ui.dashboards.project.shares.shares import forms -from manila_ui.dashboards import utils -from manila_ui.tests.dashboards.project.shares import test_data -from manila_ui.tests import helpers as test - -from openstack_dashboard.api import base -from openstack_dashboard.api import neutron -from openstack_dashboard.usage import quotas - -SHARE_INDEX_URL = reverse('horizon:project:shares:index') - - -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.ddt -class ShareViewTests(test.APITestCase): - - class FakeAZ(object): - def __init__(self, name): - self.name = name - - def setUp(self): - super(ShareViewTests, self).setUp() - self.fake_share_type = mock.Mock() - self.fake_share_type.name = 'fake' - self.fake_share_type.id = 'fake_id' - self.fake_share_type.get_keys = mock.Mock( - return_value={'driver_handles_share_servers': 'True'}) - self.share = test_data.share - self.mock_object( - api_manila, "share_get", mock.Mock(return_value=self.share)) - self.mock_object( - neutron, "is_service_enabled", mock.Mock(return_value=[True])) - self.mock_object(horizon_messages, "success") - FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'} - self.request = wsgi.WSGIRequest(FAKE_ENVIRON) - - @mock.patch.object(api_manila, 'availability_zone_list') - def test_create_share(self, az_list): - url = reverse('horizon:project:shares:create') - share = test_data.share - share_net = test_data.active_share_network - share_nets = [share_net] - formData = { - 'name': u'new_share', - 'description': u'This is test share', - 'method': u'CreateForm', - 'share_network': share_net.id, - 'size': 1, - 'share_proto': u'NFS', - 'share_type': 'fake', - 'share-network-choices-fake': share_net.id, - 'availability_zone': 'fake_az', - } - - az_list.return_value = [self.FakeAZ('fake_az'), ] - self.mock_object( - api_manila, "share_create", mock.Mock(return_value=share)) - self.mock_object( - api_manila, "share_snapshot_list", mock.Mock(return_value=[])) - self.mock_object( - api_manila, "share_network_list", - mock.Mock(return_value=share_nets)) - self.mock_object( - api_manila, "share_type_list", - mock.Mock(return_value=[self.fake_share_type, ])) - - self.client.post(url, formData) - - api_manila.share_create.assert_called_once_with( - mock.ANY, size=formData['size'], name=formData['name'], - description=formData['description'], proto=formData['share_proto'], - snapshot_id=None, is_public=False, share_network=share_net.id, - metadata={}, share_type=formData['share_type'], - availability_zone=formData['availability_zone']) - api_manila.share_snapshot_list.assert_called_once_with(mock.ANY) - api_manila.share_network_list.assert_called_once_with(mock.ANY) - api_manila.share_type_list.assert_called_once_with(mock.ANY) - - @mock.patch.object(api_manila, 'availability_zone_list') - def test_create_share_from_snapshot(self, mock_az_list): - share = test_data.share - share_net = test_data.active_share_network - share_nets = [share_net] - snapshot = test_data.snapshot - url = reverse('horizon:project:shares:create') - formData = { - 'name': u'new_share', - 'description': u'This is test share from snapshot', - 'method': u'CreateForm', - 'share_network': share_net.id, - 'size': snapshot.size, - 'share_proto': 'NFS', - 'share_type': 'fake', - 'share_source_type': 'snapshot', - 'snapshot': snapshot.id, - 'share-network-choices-fake': share_net.id, - 'availability_zone': 'fake_az', - } - mock_az_list.return_value = [self.FakeAZ('fake_az'), ] - self.mock_object( - api_manila, "share_create", mock.Mock(return_value=share)) - self.mock_object( - api_manila, "share_snapshot_list", - mock.Mock(return_value=[snapshot])) - self.mock_object( - api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot)) - self.mock_object( - api_manila, "share_network_list", - mock.Mock(return_value=share_nets)) - self.mock_object( - api_manila, "share_type_list", - mock.Mock(return_value=[self.fake_share_type, ])) - - res = self.client.post(url, formData) - - mock_az_list.assert_called_once_with(mock.ANY) - api_manila.share_snapshot_list.assert_not_called() - api_manila.share_snapshot_get.assert_called_once_with( - mock.ANY, snapshot.id) - api_manila.share_network_list.assert_called_once_with(mock.ANY) - api_manila.share_type_list.assert_called_once_with(mock.ANY) - api_manila.share_create.assert_called_with( - mock.ANY, size=formData['size'], name=formData['name'], - description=formData['description'], proto=formData['share_proto'], - snapshot_id=snapshot.id, is_public=False, - share_network=share_net.id, metadata={}, - share_type=formData['share_type'], - availability_zone=formData['availability_zone']) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) - - def test_delete_share(self): - formData = {'action': 'shares__delete__%s' % self.share.id} - self.mock_object( - api_manila, "share_snapshot_list", mock.Mock(return_value=[])) - self.mock_object( - api_manila, "share_network_list", mock.Mock(return_value=[])) - self.mock_object(api_manila, "share_delete") - self.mock_object( - api_manila, "share_list", mock.Mock(return_value=[self.share])) - url = reverse('horizon:project:shares:index') - - res = self.client.post(url, formData) - - api_manila.share_network_list.assert_called_once_with(mock.ANY) - api_manila.share_snapshot_list.assert_called_once_with( - mock.ANY, detailed=True) - api_manila.share_list.assert_called_with(mock.ANY) - api_manila.share_delete.assert_called_with( - mock.ANY, self.share.id) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) - - def test_detail_view(self): - share_net = test_data.active_share_network - rules = [test_data.ip_rule, test_data.user_rule, test_data.cephx_rule] - export_locations = test_data.export_locations - url = reverse('horizon:project:shares:detail', args=[self.share.id]) - self.mock_object( - api_manila, "share_network_get", mock.Mock(return_value=share_net)) - self.mock_object( - api_manila, "share_rules_list", mock.Mock(return_value=rules)) - self.mock_object( - api_manila, "share_export_location_list", - mock.Mock(return_value=export_locations)) - - res = self.client.get(url) - - self.assertContains( - res, "

Share Details: %s

" % self.share.name, 1, 200) - self.assertContains(res, "
%s
" % self.share.name, 1, 200) - self.assertContains(res, "
%s
" % self.share.id, 1, 200) - self.assertContains(res, "
%s GiB
" % self.share.size, 1, 200) - self.assertContains( - res, "
%s
" % self.share.share_proto, 1, 200) - self.assertContains( - res, "
%s
" % self.share.availability_zone, 1, 200) - for el in export_locations: - self.assertContains(res, "value=\"%s\"" % el.path, 1, 200) - self.assertContains( - res, "
Preferred: %s
" % el.preferred, 1, 200) - self.assertContains( - res, "
Is admin only: %s
" % el.is_admin_only, - 1, 200) - self.assertContains( - res, ("
Share Replica ID: %s
" % - export_locations[0].share_instance_id), - 2, 200) - for rule in rules: - self.assertContains(res, "
%s
" % rule.access_type, 1, 200) - self.assertContains( - res, "
Access to: %s
" % rule.access_to, - 1, 200) - if 'cephx' == rule.access_type: - self.assertContains( - res, "
Access Key: %s
" % rule.access_key, - 1, 200) - self.assertContains( - res, "
Access Key:
", - len(rules) - sum(r.access_type == 'cephx' for r in rules), 200) - self.assertContains( - res, "
Access Level: rw
", len(rules), 200) - self.assertContains( - res, "
Status: active
", len(rules), 200) - self.assertNoMessages() - api_manila.share_rules_list.assert_called_once_with( - mock.ANY, self.share.id) - api_manila.share_export_location_list.assert_called_once_with( - mock.ANY, self.share.id) - - def test_update_share_get(self): - share = test_data.share - url = reverse('horizon:project:shares:update', args=[share.id]) - self.mock_object( - neutron, "is_service_enabled", mock.Mock(return_value=[True])) - - res = self.client.get(url) - - api_manila.share_get.assert_called_once_with(mock.ANY, share.id) - self.assertNoMessages() - self.assertTemplateUsed(res, 'project/shares/shares/update.html') - - def test_update_share_post(self): - self.mock_object(api_manila, "share_update") - formData = { - 'method': 'UpdateForm', - 'name': self.share.name, - 'description': self.share.description, - 'is_public': False, - } - url = reverse('horizon:project:shares:update', args=[self.share.id]) - - res = self.client.post(url, formData) - - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) - api_manila.share_update.assert_called_once_with( - mock.ANY, self.share, formData['name'], formData['description'], - is_public=six.text_type(formData['is_public'])) - api_manila.share_get.assert_has_calls( - [mock.call(mock.ANY, self.share.id) for i in (1, 2)]) - - def test_list_rules(self): - rules = [test_data.ip_rule, test_data.user_rule, test_data.cephx_rule] - self.mock_object( - api_manila, "share_rules_list", mock.Mock(return_value=rules)) - url = reverse( - 'horizon:project:shares:manage_rules', args=[self.share.id]) - - res = self.client.get(url) - - self.assertEqual(res.status_code, 200) - self.assertTemplateUsed(res, 'project/shares/shares/manage_rules.html') - api_manila.share_rules_list.assert_called_once_with( - mock.ANY, self.share.id) - - def test_create_rule_get(self): - url = reverse('horizon:project:shares:rule_add', args=[self.share.id]) - self.mock_object( - neutron, "is_service_enabled", mock.Mock(return_value=[True])) - - res = self.client.get(url) - - self.assertNoMessages() - self.assertTemplateUsed(res, 'project/shares/shares/rule_add.html') - - def test_create_rule_post(self): - url = reverse('horizon:project:shares:rule_add', args=[self.share.id]) - self.mock_object(api_manila, "share_allow") - formData = { - 'access_type': 'user', - 'method': u'CreateForm', - 'access_to': 'someuser', - 'access_level': 'rw', - } - - res = self.client.post(url, formData) - - api_manila.share_allow.assert_called_once_with( - mock.ANY, self.share.id, access_type=formData['access_type'], - access_to=formData['access_to'], - access_level=formData['access_level']) - self.assertRedirectsNoFollow( - res, - reverse('horizon:project:shares:manage_rules', - args=[self.share.id]) - ) - - def test_delete_rule(self): - rule = test_data.ip_rule - formData = {'action': 'rules__delete__%s' % rule.id} - self.mock_object(api_manila, "share_deny") - self.mock_object( - api_manila, "share_rules_list", mock.Mock(return_value=[rule])) - url = reverse( - 'horizon:project:shares:manage_rules', args=[self.share.id]) - - self.client.post(url, formData) - - api_manila.share_deny.assert_called_with( - mock.ANY, self.share.id, rule.id) - api_manila.share_rules_list.assert_called_with(mock.ANY, self.share.id) - - 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( - quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) - self.mock_object( - neutron, "is_service_enabled", mock.Mock(return_value=[True])) - - res = self.client.get(url) - - api_manila.share_get.assert_called_once_with(mock.ANY, share.id) - self.assertNoMessages() - self.assertTemplateUsed(res, 'project/shares/shares/extend.html') - - 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( - quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) - - response = self.client.get(url) - - self.assertEqual(200, response.status_code) - self.assertTemplateUsed(response, 'project/shares/shares/extend.html') - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - self.assertFalse(api_manila.share_extend.called) - quotas.tenant_limit_usages.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( - quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) - self.mock_object( - api_manila, "share_get", - mock.Mock(return_value=Exception('Fake share NotFound exception'))) - - response = self.client.get(url) - - self.assertEqual(404, response.status_code) - self.assertTemplateNotUsed( - response, 'project/shares/shares/extend.html') - self.assertFalse(api_manila.share_extend.called) - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - self.assertFalse(quotas.tenant_limit_usages.called) - - @ddt.data(6, 54, 55) - def test_extend_share_post_successfully(self, new_size): - self.share.size = 5 - form_data = {'new_size': new_size} - 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( - quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) - - response = self.client.post(url, form_data) - - self.assertEqual(302, response.status_code) - self.assertTemplateNotUsed( - response, 'project/shares/shares/extend.html') - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - api_manila.share_extend.assert_called_once_with( - mock.ANY, self.share.id, form_data['new_size']) - quotas.tenant_limit_usages.assert_called_once_with(mock.ANY) - self.assertRedirectsNoFollow(response, SHARE_INDEX_URL) - - @ddt.data(0, 5, 56) - def test_extend_share_post_with_invalid_value(self, new_size): - self.share.size = 5 - form_data = {'new_size': new_size} - 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( - quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) - - response = self.client.post(url, form_data) - - self.assertEqual(200, response.status_code) - self.assertTemplateUsed(response, 'project/shares/shares/extend.html') - self.assertFalse(api_manila.share_extend.called) - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - quotas.tenant_limit_usages.assert_called_with(mock.ANY) - - 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( - quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) - - response = self.client.post(url, form_data) - - self.assertEqual(302, response.status_code) - self.assertTemplateNotUsed( - response, 'project/shares/shares/extend.html') - api_manila.share_extend.assert_called_once_with( - mock.ANY, self.share.id, form_data['new_size']) - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - quotas.tenant_limit_usages.assert_called_once_with(mock.ANY) - self.assertRedirectsNoFollow(response, SHARE_INDEX_URL) - - def test_revert_to_snapshot_get_success(self): - snapshots = [ - type('FakeSnapshot', (object, ), - {'name': s_n, 'id': s_id, 'created_at': c_at}) - for s_n, s_id, c_at in ( - ('foo_name', 'foo_id', '2017-04-20T12:31:14.000000'), - ('bar_name', 'bar_id', '2017-04-20T12:31:16.000000')) - ] - url = reverse('horizon:project:shares:revert', args=[self.share.id]) - self.mock_object(api_manila, "share_revert") - self.mock_object( - api_manila, "share_snapshot_list", - mock.Mock(return_value=snapshots)) - - res = self.client.get(url) - - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - api_manila.share_snapshot_list.assert_called_once_with( - mock.ANY, search_opts={'share_id': self.share.id}) - api_manila.share_revert.assert_not_called() - self.assertNoMessages() - self.assertTemplateUsed(res, 'project/shares/shares/revert.html') - - def test_revert_to_snapshot_post_success(self): - snapshots = [ - type('FakeSnapshot', (object, ), - {'name': s_n, 'id': s_id, 'created_at': c_at}) - for s_n, s_id, c_at in ( - ('foo_name', 'foo_id', '2017-04-20T12:31:14.000000'), - ('bar_name', 'bar_id', '2017-04-20T12:31:16.000000'), - ('quuz_name', 'quuz_id', '2017-04-20T12:31:13.000000')) - ] - url = reverse('horizon:project:shares:revert', args=[self.share.id]) - self.mock_object(api_manila, "share_revert") - self.mock_object( - api_manila, "share_snapshot_list", - mock.Mock(return_value=snapshots)) - data = {'snapshot': snapshots[1].id} - - res = self.client.post(url, data) - - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - api_manila.share_snapshot_list.assert_called_once_with( - mock.ANY, search_opts={'share_id': self.share.id}) - api_manila.share_revert.assert_called_once_with( - mock.ANY, self.share.id, data['snapshot']) - self.assertNoMessages() - self.assertTemplateNotUsed(res, 'project/shares/shares/revert.html') - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) - - def test_revert_to_snapshot_share_not_found(self): - url = reverse("horizon:project:shares:revert", args=[self.share.id]) - self.mock_object(api_manila, "share_revert") - api_manila.share_get.side_effect = Exception( - 'Fake share NotFound exception') - self.mock_object( - api_manila, "share_snapshot_list", mock.Mock(return_value=[])) - - res = self.client.get(url) - - self.assertEqual(404, res.status_code) - self.assertTemplateNotUsed( - res, 'project/shares/shares/revert.html') - api_manila.share_revert.assert_not_called() - api_manila.share_snapshot_list.assert_not_called() - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - - def test_revert_to_snapshot_failed(self): - snapshots = [ - type('FakeSnapshot', (object, ), - {'name': s_n, 'id': s_id, 'created_at': c_at}) - for s_n, s_id, c_at in ( - ('foo_name', 'foo_id', '2017-04-20T12:31:14.000000'), - ('bar_name', 'bar_id', '2017-04-20T12:31:16.000000'), - ('quuz_name', 'quuz_id', '2017-04-20T12:31:13.000000')) - ] - url = reverse('horizon:project:shares:revert', args=[self.share.id]) - self.mock_object( - api_manila, "share_revert", - mock.Mock(side_effect=Exception('Fake reverting error'))) - self.mock_object( - api_manila, "share_snapshot_list", - mock.Mock(return_value=snapshots)) - data = {'snapshot': snapshots[1].id} - - res = self.client.post(url, data) - - self.assertEqual(302, res.status_code) - api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) - api_manila.share_snapshot_list.assert_called_once_with( - mock.ANY, search_opts={'share_id': self.share.id}) - api_manila.share_revert.assert_called_once_with( - mock.ANY, self.share.id, data['snapshot']) - self.assertTemplateNotUsed(res, 'project/shares/shares/revert.html') - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) - - def test_update_share_metadata_get(self): - share = test_data.share_with_metadata - url = reverse( - 'horizon:project:shares:update_metadata', args=[share.id]) - self.mock_object( - api_manila, "share_get", mock.Mock(return_value=share)) - self.mock_object( - neutron, "is_service_enabled", mock.Mock(return_value=[True])) - - res = self.client.get(url) - - api_manila.share_get.assert_called_once_with(mock.ANY, share.id) - self.assertNoMessages() - self.assertTemplateUsed( - res, 'project/shares/shares/update_metadata.html') - - def test_update_share_metadata_post(self): - share = test_data.share_with_metadata - data = { - 'metadata': 'aaa=ccc', - } - form_data = { - 'metadata': {'aaa': 'ccc'}, - } - url = reverse( - 'horizon:project:shares:update_metadata', args=[share.id]) - self.mock_object( - api_manila, "share_get", mock.Mock(return_value=share)) - self.mock_object(api_manila, "share_set_metadata") - self.mock_object( - neutron, "is_service_enabled", mock.Mock(return_value=[True])) - - res = self.client.post(url, data) - - api_manila.share_set_metadata.assert_called_once_with( - mock.ANY, share, form_data['metadata']) - self.assertRedirectsNoFollow(res, SHARE_INDEX_URL) - - @ddt.data((True, True), (True, False), (False, False)) - @ddt.unpack - def test_enable_public_share_creation(self, - enable_public_shares, - is_public): - def _get_form(**kwargs): - return forms.CreateForm(self.request, **kwargs) - - self.mock_object( - api_manila, "share_create", mock.Mock(return_value=self.share)) - self.mock_object( - api_manila, "share_snapshot_list", mock.Mock(return_value=[])) - self.mock_object( - api_manila, "share_network_list", - mock.Mock(return_value=[test_data.active_share_network])) - self.mock_object( - api_manila, "share_type_list", - mock.Mock(return_value=[self.fake_share_type, ])) - self.mock_object( - api_manila, "availability_zone_list", - mock.Mock(return_value=[self.FakeAZ('fake_az'), ])) - - data = { - 'name': u'new_share', - 'description': u'This is test share', - 'method': u'CreateForm', - 'share_network': test_data.active_share_network.id, - 'size': 1, - 'share_proto': u'NFS', - 'share_type': 'fake', - 'share-network-choices-fake': test_data.active_share_network.id, - 'availability_zone': 'fake_az', - 'metadata': 'key=value', - 'snapshot_id': None, - } - if enable_public_shares: - data.update({'is_public': is_public}) - - with self.settings(OPENSTACK_MANILA_FEATURES={ - 'enable_public_shares': enable_public_shares}): - form = _get_form() - result = form.handle(self.request, data) - self.assertTrue(result) - self.assertEqual( - enable_public_shares, - form.enable_public_shares) - if enable_public_shares: - self.assertIn("is_public", form.fields) - self.assertTrue(form.fields["is_public"]) - else: - self.assertNotIn("is_public", form.fields) - api_manila.share_create.assert_called_once_with( - self.request, - availability_zone=data['availability_zone'], - description=data['description'], - is_public=is_public, - metadata=utils.parse_str_meta(data['metadata'])[0], - name=data['name'], - proto=data['share_proto'], - share_network=test_data.active_share_network.id, - share_type=data['share_type'], - size=data['size'], - snapshot_id=data['snapshot_id'], - ) - horizon_messages.success.assert_called_once_with( - self.request, mock.ANY) - - @ddt.data((True, True), (True, False), (False, False)) - @ddt.unpack - def test_enable_public_share_update(self, - enable_public_shares, - is_public): - def _get_form(initial): - kwargs = { - 'prefix': None, - 'initial': initial, - } - return forms.UpdateForm(self.request, **kwargs) - - initial = {'share_id': 'fake_share_id'} - - self.mock_object( - api_manila, "share_update", mock.Mock(return_value=self.share)) - - data = { - 'name': u'old_share', - 'description': u'This is test share', - } - if enable_public_shares: - data.update({'is_public': is_public}) - - with self.settings(OPENSTACK_MANILA_FEATURES={ - 'enable_public_shares': enable_public_shares}): - form = _get_form(initial) - result = form.handle(self.request, data) - self.assertTrue(result) - self.assertEqual( - enable_public_shares, - form.enable_public_shares) - if enable_public_shares: - self.assertIn("is_public", form.fields) - self.assertTrue(form.fields["is_public"]) - else: - self.assertNotIn("is_public", form.fields) - api_manila.share_update.assert_called_once_with( - self.request, - self.share, - data['name'], - data['description'], - is_public=is_public, - ) - horizon_messages.success.assert_called_once_with( - self.request, mock.ANY) diff --git a/manila_ui/tests/dashboards/project/shares/snapshots/__init__.py b/manila_ui/tests/dashboards/project/shares/snapshots/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/manila_ui/tests/dashboards/project/shares/tests.py b/manila_ui/tests/dashboards/project/shares/tests.py index 7fc3a831..99bf3648 100644 --- a/manila_ui/tests/dashboards/project/shares/tests.py +++ b/manila_ui/tests/dashboards/project/shares/tests.py @@ -13,52 +13,61 @@ # under the License. import ddt +from django.core.handlers import wsgi from django.core.urlresolvers import reverse -from django.utils import translation +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 -from manila_ui.dashboards.project import shares -from manila_ui.tests.dashboards.project.shares import test_data +from manila_ui.dashboards.project.shares import forms +from manila_ui.dashboards import utils +from manila_ui.tests.dashboards.project import test_data from manila_ui.tests import helpers as test -from openstack_dashboard.api import neutron as api_neutron -from openstack_dashboard.usage import quotas - INDEX_URL = reverse('horizon:project:shares:index') -class SharesTests(test.TestCase): +@ddt.ddt +class ShareViewTests(test.APITestCase): - def test_index_with_all_tabs(self): + class FakeAZ(object): + def __init__(self, name): + self.name = name + + def setUp(self): + super(ShareViewTests, self).setUp() + self.fake_share_type = mock.Mock() + self.fake_share_type.name = 'fake' + self.fake_share_type.id = 'fake_id' + self.fake_share_type.get_keys = mock.Mock( + return_value={'driver_handles_share_servers': 'True'}) + self.share = test_data.share + self.mock_object( + api_manila, "share_get", mock.Mock(return_value=self.share)) + self.mock_object( + neutron, "is_service_enabled", mock.Mock(return_value=[True])) + self.mock_object(horizon_messages, "success") + FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'} + self.request = wsgi.WSGIRequest(FAKE_ENVIRON) + + def test_index(self): snaps = [test_data.snapshot, test_data.snapshot_mount_support] shares = [test_data.share, test_data.nameless_share, test_data.other_share] share_networks = [test_data.inactive_share_network, test_data.active_share_network] - security_services = [test_data.sec_service] - snap_shares = [test_data.share, test_data.share_mount_snapshot] - self.mock_object( api_manila, "share_list", mock.Mock(return_value=shares)) self.mock_object( api_manila, "share_snapshot_list", mock.Mock(return_value=snaps)) - self.mock_object( - api_manila, "share_get", mock.Mock(return_value=snap_shares[0])) - self.mock_object( - api_manila, "share_get", mock.Mock(return_value=snap_shares[1])) self.mock_object( api_manila, "share_network_list", mock.Mock(return_value=share_networks)) self.mock_object( - api_manila, "security_service_list", - mock.Mock(return_value=security_services)) - self.mock_object( - api_neutron, "is_service_enabled", mock.Mock(return_value=[True])) - self.mock_object( - api_neutron, "network_list", mock.Mock(return_value=[])) - self.mock_object( - api_neutron, "subnet_list", mock.Mock(return_value=[])) + neutron, "is_service_enabled", mock.Mock(return_value=[True])) self.mock_object( quotas, "tenant_limit_usages", mock.Mock(return_value=test_data.quota_usage)) @@ -70,145 +79,647 @@ class SharesTests(test.TestCase): self.assertEqual(res.status_code, 200) self.assertTemplateUsed(res, 'project/shares/index.html') - api_neutron.network_list.assert_called_once_with(mock.ANY) - api_neutron.subnet_list.assert_called_once_with(mock.ANY) - api_manila.security_service_list.assert_called_once_with(mock.ANY) - api_manila.share_snapshot_list.assert_called_with(mock.ANY) - api_manila.share_get.assert_has_calls([ - mock.call(mock.ANY, snaps[0].share_id), - mock.call(mock.ANY, snaps[1].share_id) - ]) + api_manila.share_snapshot_list.assert_called_with( + mock.ANY, detailed=True) api_manila.share_list.assert_called_with(mock.ANY) - api_manila.share_network_list.assert_has_calls([ - mock.call(mock.ANY), - mock.call(mock.ANY, detailed=True), - ], any_order=True) + api_manila.share_network_list.assert_called_with(mock.ANY) - -class PieChartsTests(test.TestCase): - - def test_get_context_data(self): - limits = { - "totalSharesUsed": 1, - "totalShareGigabytesUsed": 2, - "totalShareNetworksUsed": 3, - "totalShareSnapshotsUsed": 4, - "totalSnapshotGigabytesUsed": 5, - "maxTotalShares": 6, - "maxTotalShareGigabytes": 7, - "maxTotalShareNetworks": 8, - "maxTotalShareSnapshots": 9, - "maxTotalSnapshotGigabytes": 10, - } - existing_chart_name = "Foo" - existing_chart = { - "name": translation.ugettext_lazy(existing_chart_name), - "used": 11, - "max": 13, - "text": "fake_text", + @mock.patch.object(api_manila, 'availability_zone_list') + def test_create_share(self, az_list): + url = reverse('horizon:project:shares:create') + share = test_data.share + share_net = test_data.active_share_network + share_nets = [share_net] + formData = { + 'name': u'new_share', + 'description': u'This is test share', + 'method': u'CreateForm', + 'share_network': share_net.id, + 'size': 1, + 'share_proto': u'NFS', + 'share_type': 'fake', + 'share-network-choices-fake': share_net.id, + 'availability_zone': 'fake_az', } - class ParentViewInstance(mock.MagicMock): - def get_context_data(self, **kwargs): - return {"charts": [existing_chart]} + az_list.return_value = [self.FakeAZ('fake_az'), ] + self.mock_object( + api_manila, "share_create", mock.Mock(return_value=share)) + self.mock_object( + api_manila, "share_snapshot_list", mock.Mock(return_value=[])) + self.mock_object( + api_manila, "share_network_list", + mock.Mock(return_value=share_nets)) + self.mock_object( + api_manila, "share_type_list", + mock.Mock(return_value=[self.fake_share_type, ])) - class ViewInstance(ParentViewInstance): - usage = type("FakeUsage", (object, ), {"limits": limits}) + self.client.post(url, formData) - view_instance = ViewInstance() + api_manila.share_create.assert_called_once_with( + mock.ANY, size=formData['size'], name=formData['name'], + description=formData['description'], proto=formData['share_proto'], + snapshot_id=None, is_public=False, share_network=share_net.id, + metadata={}, share_type=formData['share_type'], + availability_zone=formData['availability_zone']) + api_manila.share_snapshot_list.assert_called_once_with(mock.ANY) + api_manila.share_network_list.assert_called_once_with(mock.ANY) + api_manila.share_type_list.assert_called_once_with(mock.ANY) - result = shares.get_context_data( - view_instance, fook="foov", bark="barv") - - charts = result.get("charts", []) - self.assertEqual(6, len(charts)) - expected_charts = { - existing_chart_name: { - "name": existing_chart_name, "used": existing_chart["used"], - "max": existing_chart["max"], "text": existing_chart["text"]}, - "Shares": {"name": "Shares", "used": 1, "max": 6, "text": False}, - "Share Storage": { - "name": "Share Storage", 'used': 2, "max": 7, "text": False}, - "Share Networks": { - "name": "Share Networks", "used": 3, "max": 8, "text": False}, - "Share Snapshots": { - "name": "Share Snapshots", "used": 4, "max": 9, "text": False}, - "Share Snapshots Storage": { - "name": "Share Snapshots Storage", "used": 5, "max": 10, - "text": False}, + @mock.patch.object(api_manila, 'availability_zone_list') + def test_create_share_from_snapshot(self, mock_az_list): + share = test_data.share + share_net = test_data.active_share_network + share_nets = [share_net] + snapshot = test_data.snapshot + url = reverse('horizon:project:shares:create') + formData = { + 'name': u'new_share', + 'description': u'This is test share from snapshot', + 'method': u'CreateForm', + 'share_network': share_net.id, + 'size': snapshot.size, + 'share_proto': 'NFS', + 'share_type': 'fake', + 'share_source_type': 'snapshot', + 'snapshot': snapshot.id, + 'share-network-choices-fake': share_net.id, + 'availability_zone': 'fake_az', } - for chart in charts: - name = chart["name"].title() - self.assertEqual( - {"name": name, "used": chart["used"], "max": chart["max"], - "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): + mock_az_list.return_value = [self.FakeAZ('fake_az'), ] 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') - ] + api_manila, "share_create", mock.Mock(return_value=share)) self.mock_object( - api_manila, method_name, mock.Mock(return_value=fake_quotas)) + api_manila, "share_snapshot_list", + mock.Mock(return_value=[snapshot])) self.mock_object( - shares, '_get_manila_disabled_quotas', - mock.Mock(return_value=[])) + api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot)) + self.mock_object( + api_manila, "share_network_list", + mock.Mock(return_value=share_nets)) + self.mock_object( + api_manila, "share_type_list", + mock.Mock(return_value=[self.fake_share_type, ])) - result = shares._get_manila_quota_data( - self.request, method_name) + res = self.client.post(url, formData) - 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) + mock_az_list.assert_called_once_with(mock.ANY) + api_manila.share_snapshot_list.assert_not_called() + api_manila.share_snapshot_get.assert_called_once_with( + mock.ANY, snapshot.id) + api_manila.share_network_list.assert_called_once_with(mock.ANY) + api_manila.share_type_list.assert_called_once_with(mock.ANY) + api_manila.share_create.assert_called_with( + mock.ANY, size=formData['size'], name=formData['name'], + description=formData['description'], proto=formData['share_proto'], + snapshot_id=snapshot.id, is_public=False, + share_network=share_net.id, metadata={}, + share_type=formData['share_type'], + availability_zone=formData['availability_zone']) + self.assertRedirectsNoFollow(res, INDEX_URL) - def test_manila_quota_fields(self): - expected_fields = ( - "shares", - "share_gigabytes", - "share_snapshots", - "share_snapshot_gigabytes", - "share_networks", + def test_delete_share(self): + formData = {'action': 'shares__delete__%s' % self.share.id} + self.mock_object( + api_manila, "share_snapshot_list", mock.Mock(return_value=[])) + self.mock_object( + api_manila, "share_network_list", mock.Mock(return_value=[])) + self.mock_object(api_manila, "share_delete") + self.mock_object( + api_manila, "share_list", mock.Mock(return_value=[self.share])) + + res = self.client.post(INDEX_URL, formData) + + api_manila.share_network_list.assert_called_once_with(mock.ANY) + api_manila.share_snapshot_list.assert_called_once_with( + mock.ANY, detailed=True) + api_manila.share_list.assert_called_with(mock.ANY) + api_manila.share_delete.assert_called_with( + mock.ANY, self.share.id) + self.assertRedirectsNoFollow(res, INDEX_URL) + + def test_detail_view(self): + share_net = test_data.active_share_network + rules = [test_data.ip_rule, test_data.user_rule, test_data.cephx_rule] + export_locations = test_data.export_locations + url = reverse('horizon:project:shares:detail', args=[self.share.id]) + self.mock_object( + api_manila, "share_network_get", mock.Mock(return_value=share_net)) + self.mock_object( + api_manila, "share_rules_list", mock.Mock(return_value=rules)) + self.mock_object( + api_manila, "share_export_location_list", + mock.Mock(return_value=export_locations)) + + res = self.client.get(url) + + self.assertContains( + res, "

Share Details: %s

" % self.share.name, 1, 200) + self.assertContains(res, "
%s
" % self.share.name, 1, 200) + self.assertContains(res, "
%s
" % self.share.id, 1, 200) + self.assertContains(res, "
%s GiB
" % self.share.size, 1, 200) + self.assertContains( + res, "
%s
" % self.share.share_proto, 1, 200) + self.assertContains( + res, "
%s
" % self.share.availability_zone, 1, 200) + for el in export_locations: + self.assertContains(res, "value=\"%s\"" % el.path, 1, 200) + self.assertContains( + res, "
Preferred: %s
" % el.preferred, 1, 200) + self.assertContains( + res, "
Is admin only: %s
" % el.is_admin_only, + 1, 200) + self.assertContains( + res, ("
Share Replica ID: %s
" % + export_locations[0].share_instance_id), + 2, 200) + for rule in rules: + self.assertContains(res, "
%s
" % rule.access_type, 1, 200) + self.assertContains( + res, "
Access to: %s
" % rule.access_to, + 1, 200) + if 'cephx' == rule.access_type: + self.assertContains( + res, "
Access Key: %s
" % rule.access_key, + 1, 200) + self.assertContains( + res, "
Access Key:
", + len(rules) - sum(r.access_type == 'cephx' for r in rules), 200) + self.assertContains( + res, "
Access Level: rw
", len(rules), 200) + self.assertContains( + res, "
Status: active
", len(rules), 200) + self.assertNoMessages() + api_manila.share_rules_list.assert_called_once_with( + mock.ANY, self.share.id) + api_manila.share_export_location_list.assert_called_once_with( + mock.ANY, self.share.id) + + def test_update_share_get(self): + share = test_data.share + url = reverse('horizon:project:shares:update', args=[share.id]) + self.mock_object( + neutron, "is_service_enabled", mock.Mock(return_value=[True])) + + res = self.client.get(url) + + api_manila.share_get.assert_called_once_with(mock.ANY, share.id) + self.assertNoMessages() + self.assertTemplateUsed(res, 'project/shares/update.html') + + def test_update_share_post(self): + self.mock_object(api_manila, "share_update") + formData = { + 'method': 'UpdateForm', + 'name': self.share.name, + 'description': self.share.description, + 'is_public': False, + } + url = reverse('horizon:project:shares:update', args=[self.share.id]) + + res = self.client.post(url, formData) + + self.assertRedirectsNoFollow(res, INDEX_URL) + api_manila.share_update.assert_called_once_with( + mock.ANY, self.share, formData['name'], formData['description'], + is_public=six.text_type(formData['is_public'])) + api_manila.share_get.assert_has_calls( + [mock.call(mock.ANY, self.share.id) for i in (1, 2)]) + + def test_list_rules(self): + rules = [test_data.ip_rule, test_data.user_rule, test_data.cephx_rule] + self.mock_object( + api_manila, "share_rules_list", mock.Mock(return_value=rules)) + url = reverse( + 'horizon:project:shares:manage_rules', args=[self.share.id]) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + self.assertTemplateUsed(res, 'project/shares/manage_rules.html') + api_manila.share_rules_list.assert_called_once_with( + mock.ANY, self.share.id) + + def test_create_rule_get(self): + url = reverse('horizon:project:shares:rule_add', args=[self.share.id]) + self.mock_object( + neutron, "is_service_enabled", mock.Mock(return_value=[True])) + + res = self.client.get(url) + + self.assertNoMessages() + self.assertTemplateUsed(res, 'project/shares/rule_add.html') + + def test_create_rule_post(self): + url = reverse('horizon:project:shares:rule_add', args=[self.share.id]) + self.mock_object(api_manila, "share_allow") + formData = { + 'access_type': 'user', + 'method': u'CreateForm', + 'access_to': 'someuser', + 'access_level': 'rw', + } + + res = self.client.post(url, formData) + + api_manila.share_allow.assert_called_once_with( + mock.ANY, self.share.id, access_type=formData['access_type'], + access_to=formData['access_to'], + access_level=formData['access_level']) + self.assertRedirectsNoFollow( + res, + reverse('horizon:project:shares:manage_rules', + args=[self.share.id]) ) - for ef in expected_fields: - self.assertIn(ef, shares.quotas.QUOTA_FIELDS) + + def test_delete_rule(self): + rule = test_data.ip_rule + formData = {'action': 'rules__delete__%s' % rule.id} + self.mock_object(api_manila, "share_deny") + self.mock_object( + api_manila, "share_rules_list", mock.Mock(return_value=[rule])) + url = reverse( + 'horizon:project:shares:manage_rules', args=[self.share.id]) + + self.client.post(url, formData) + + api_manila.share_deny.assert_called_with( + mock.ANY, self.share.id, rule.id) + api_manila.share_rules_list.assert_called_with(mock.ANY, self.share.id) + + 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( + quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) + self.mock_object( + neutron, "is_service_enabled", mock.Mock(return_value=[True])) + + res = self.client.get(url) + + api_manila.share_get.assert_called_once_with(mock.ANY, share.id) + self.assertNoMessages() + self.assertTemplateUsed(res, 'project/shares/extend.html') + + 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( + quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) + + response = self.client.get(url) + + self.assertEqual(200, response.status_code) + self.assertTemplateUsed(response, 'project/shares/extend.html') + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + self.assertFalse(api_manila.share_extend.called) + quotas.tenant_limit_usages.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( + quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) + self.mock_object( + api_manila, "share_get", + mock.Mock(return_value=Exception('Fake share NotFound exception'))) + + response = self.client.get(url) + + self.assertEqual(404, response.status_code) + self.assertTemplateNotUsed( + response, 'project/shares/shares/extend.html') + self.assertFalse(api_manila.share_extend.called) + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + self.assertFalse(quotas.tenant_limit_usages.called) + + @ddt.data(6, 54, 55) + def test_extend_share_post_successfully(self, new_size): + self.share.size = 5 + form_data = {'new_size': new_size} + 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( + quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) + + response = self.client.post(url, form_data) + + self.assertEqual(302, response.status_code) + self.assertTemplateNotUsed( + response, 'project/shares/extend.html') + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + api_manila.share_extend.assert_called_once_with( + mock.ANY, self.share.id, form_data['new_size']) + quotas.tenant_limit_usages.assert_called_once_with(mock.ANY) + self.assertRedirectsNoFollow(response, INDEX_URL) + + @ddt.data(0, 5, 56) + def test_extend_share_post_with_invalid_value(self, new_size): + self.share.size = 5 + form_data = {'new_size': new_size} + 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( + quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) + + response = self.client.post(url, form_data) + + self.assertEqual(200, response.status_code) + self.assertTemplateUsed(response, 'project/shares/extend.html') + self.assertFalse(api_manila.share_extend.called) + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + quotas.tenant_limit_usages.assert_called_with(mock.ANY) + + 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( + quotas, "tenant_limit_usages", mock.Mock(return_value=usage_limit)) + + response = self.client.post(url, form_data) + + self.assertEqual(302, response.status_code) + self.assertTemplateNotUsed( + response, 'project/shares/extend.html') + api_manila.share_extend.assert_called_once_with( + mock.ANY, self.share.id, form_data['new_size']) + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + quotas.tenant_limit_usages.assert_called_once_with(mock.ANY) + self.assertRedirectsNoFollow(response, INDEX_URL) + + def test_revert_to_snapshot_get_success(self): + snapshots = [ + type('FakeSnapshot', (object, ), + {'name': s_n, 'id': s_id, 'created_at': c_at}) + for s_n, s_id, c_at in ( + ('foo_name', 'foo_id', '2017-04-20T12:31:14.000000'), + ('bar_name', 'bar_id', '2017-04-20T12:31:16.000000')) + ] + url = reverse('horizon:project:shares:revert', args=[self.share.id]) + self.mock_object(api_manila, "share_revert") + self.mock_object( + api_manila, "share_snapshot_list", + mock.Mock(return_value=snapshots)) + + res = self.client.get(url) + + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + api_manila.share_snapshot_list.assert_called_once_with( + mock.ANY, search_opts={'share_id': self.share.id}) + api_manila.share_revert.assert_not_called() + self.assertNoMessages() + self.assertTemplateUsed(res, 'project/shares/revert.html') + + def test_revert_to_snapshot_post_success(self): + snapshots = [ + type('FakeSnapshot', (object, ), + {'name': s_n, 'id': s_id, 'created_at': c_at}) + for s_n, s_id, c_at in ( + ('foo_name', 'foo_id', '2017-04-20T12:31:14.000000'), + ('bar_name', 'bar_id', '2017-04-20T12:31:16.000000'), + ('quuz_name', 'quuz_id', '2017-04-20T12:31:13.000000')) + ] + url = reverse('horizon:project:shares:revert', args=[self.share.id]) + self.mock_object(api_manila, "share_revert") + self.mock_object( + api_manila, "share_snapshot_list", + mock.Mock(return_value=snapshots)) + data = {'snapshot': snapshots[1].id} + + res = self.client.post(url, data) + + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + api_manila.share_snapshot_list.assert_called_once_with( + mock.ANY, search_opts={'share_id': self.share.id}) + api_manila.share_revert.assert_called_once_with( + mock.ANY, self.share.id, data['snapshot']) + self.assertNoMessages() + self.assertTemplateNotUsed(res, 'project/shares/revert.html') + self.assertRedirectsNoFollow(res, INDEX_URL) + + def test_revert_to_snapshot_share_not_found(self): + url = reverse("horizon:project:shares:revert", args=[self.share.id]) + self.mock_object(api_manila, "share_revert") + api_manila.share_get.side_effect = Exception( + 'Fake share NotFound exception') + self.mock_object( + api_manila, "share_snapshot_list", mock.Mock(return_value=[])) + + res = self.client.get(url) + + self.assertEqual(404, res.status_code) + self.assertTemplateNotUsed( + res, 'project/shares/revert.html') + api_manila.share_revert.assert_not_called() + api_manila.share_snapshot_list.assert_not_called() + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + + def test_revert_to_snapshot_failed(self): + snapshots = [ + type('FakeSnapshot', (object, ), + {'name': s_n, 'id': s_id, 'created_at': c_at}) + for s_n, s_id, c_at in ( + ('foo_name', 'foo_id', '2017-04-20T12:31:14.000000'), + ('bar_name', 'bar_id', '2017-04-20T12:31:16.000000'), + ('quuz_name', 'quuz_id', '2017-04-20T12:31:13.000000')) + ] + url = reverse('horizon:project:shares:revert', args=[self.share.id]) + self.mock_object( + api_manila, "share_revert", + mock.Mock(side_effect=Exception('Fake reverting error'))) + self.mock_object( + api_manila, "share_snapshot_list", + mock.Mock(return_value=snapshots)) + data = {'snapshot': snapshots[1].id} + + res = self.client.post(url, data) + + self.assertEqual(302, res.status_code) + api_manila.share_get.assert_called_once_with(mock.ANY, self.share.id) + api_manila.share_snapshot_list.assert_called_once_with( + mock.ANY, search_opts={'share_id': self.share.id}) + api_manila.share_revert.assert_called_once_with( + mock.ANY, self.share.id, data['snapshot']) + self.assertTemplateNotUsed(res, 'project/shares/revert.html') + self.assertRedirectsNoFollow(res, INDEX_URL) + + def test_update_share_metadata_get(self): + share = test_data.share_with_metadata + url = reverse( + 'horizon:project:shares:update_metadata', args=[share.id]) + self.mock_object( + api_manila, "share_get", mock.Mock(return_value=share)) + self.mock_object( + neutron, "is_service_enabled", mock.Mock(return_value=[True])) + + res = self.client.get(url) + + api_manila.share_get.assert_called_once_with(mock.ANY, share.id) + self.assertNoMessages() + self.assertTemplateUsed( + res, 'project/shares/update_metadata.html') + + def test_update_share_metadata_post(self): + share = test_data.share_with_metadata + data = { + 'metadata': 'aaa=ccc', + } + form_data = { + 'metadata': {'aaa': 'ccc'}, + } + url = reverse( + 'horizon:project:shares:update_metadata', args=[share.id]) + self.mock_object( + api_manila, "share_get", mock.Mock(return_value=share)) + self.mock_object(api_manila, "share_set_metadata") + self.mock_object( + neutron, "is_service_enabled", mock.Mock(return_value=[True])) + + res = self.client.post(url, data) + + api_manila.share_set_metadata.assert_called_once_with( + mock.ANY, share, form_data['metadata']) + self.assertRedirectsNoFollow(res, INDEX_URL) + + @ddt.data((True, True), (True, False), (False, False)) + @ddt.unpack + def test_enable_public_share_creation(self, + enable_public_shares, + is_public): + def _get_form(**kwargs): + return forms.CreateForm(self.request, **kwargs) + + self.mock_object( + api_manila, "share_create", mock.Mock(return_value=self.share)) + self.mock_object( + api_manila, "share_snapshot_list", mock.Mock(return_value=[])) + self.mock_object( + api_manila, "share_network_list", + mock.Mock(return_value=[test_data.active_share_network])) + self.mock_object( + api_manila, "share_type_list", + mock.Mock(return_value=[self.fake_share_type, ])) + self.mock_object( + api_manila, "availability_zone_list", + mock.Mock(return_value=[self.FakeAZ('fake_az'), ])) + + data = { + 'name': u'new_share', + 'description': u'This is test share', + 'method': u'CreateForm', + 'share_network': test_data.active_share_network.id, + 'size': 1, + 'share_proto': u'NFS', + 'share_type': 'fake', + 'share-network-choices-fake': test_data.active_share_network.id, + 'availability_zone': 'fake_az', + 'metadata': 'key=value', + 'snapshot_id': None, + } + if enable_public_shares: + data.update({'is_public': is_public}) + + with self.settings(OPENSTACK_MANILA_FEATURES={ + 'enable_public_shares': enable_public_shares}): + form = _get_form() + result = form.handle(self.request, data) + self.assertTrue(result) + self.assertEqual( + enable_public_shares, + form.enable_public_shares) + if enable_public_shares: + self.assertIn("is_public", form.fields) + self.assertTrue(form.fields["is_public"]) + else: + self.assertNotIn("is_public", form.fields) + api_manila.share_create.assert_called_once_with( + self.request, + availability_zone=data['availability_zone'], + description=data['description'], + is_public=is_public, + metadata=utils.parse_str_meta(data['metadata'])[0], + name=data['name'], + proto=data['share_proto'], + share_network=test_data.active_share_network.id, + share_type=data['share_type'], + size=data['size'], + snapshot_id=data['snapshot_id'], + ) + horizon_messages.success.assert_called_once_with( + self.request, mock.ANY) + + @ddt.data((True, True), (True, False), (False, False)) + @ddt.unpack + def test_enable_public_share_update(self, + enable_public_shares, + is_public): + def _get_form(initial): + kwargs = { + 'prefix': None, + 'initial': initial, + } + return forms.UpdateForm(self.request, **kwargs) + + initial = {'share_id': 'fake_share_id'} + + self.mock_object( + api_manila, "share_update", mock.Mock(return_value=self.share)) + + data = { + 'name': u'old_share', + 'description': u'This is test share', + } + if enable_public_shares: + data.update({'is_public': is_public}) + + with self.settings(OPENSTACK_MANILA_FEATURES={ + 'enable_public_shares': enable_public_shares}): + form = _get_form(initial) + result = form.handle(self.request, data) + self.assertTrue(result) + self.assertEqual( + enable_public_shares, + form.enable_public_shares) + if enable_public_shares: + self.assertIn("is_public", form.fields) + self.assertTrue(form.fields["is_public"]) + else: + self.assertNotIn("is_public", form.fields) + api_manila.share_update.assert_called_once_with( + self.request, + self.share, + data['name'], + data['description'], + is_public=is_public, + ) + horizon_messages.success.assert_called_once_with( + self.request, mock.ANY) diff --git a/manila_ui/tests/dashboards/project/shares/test_data.py b/manila_ui/tests/dashboards/project/test_data.py similarity index 100% rename from manila_ui/tests/dashboards/project/shares/test_data.py rename to manila_ui/tests/dashboards/project/test_data.py diff --git a/manila_ui/tests/dashboards/project/tests.py b/manila_ui/tests/dashboards/project/tests.py new file mode 100644 index 00000000..626333d8 --- /dev/null +++ b/manila_ui/tests/dashboards/project/tests.py @@ -0,0 +1,164 @@ +# Copyright (c) 2014 NetApp, Inc. +# +# 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. + +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 + +INDEX_URL = reverse('horizon:project:shares:index') + + +class PieChartsTests(test.TestCase): + + def test_get_context_data(self): + limits = { + "totalSharesUsed": 1, + "totalShareGigabytesUsed": 2, + "totalShareNetworksUsed": 3, + "totalShareSnapshotsUsed": 4, + "totalSnapshotGigabytesUsed": 5, + "maxTotalShares": 6, + "maxTotalShareGigabytes": 7, + "maxTotalShareNetworks": 8, + "maxTotalShareSnapshots": 9, + "maxTotalSnapshotGigabytes": 10, + } + existing_chart_name = "Foo" + existing_chart = { + "name": translation.ugettext_lazy(existing_chart_name), + "used": 11, + "max": 13, + "text": "fake_text", + } + + class ParentViewInstance(mock.MagicMock): + def get_context_data(self, **kwargs): + return {"charts": [existing_chart]} + + class ViewInstance(ParentViewInstance): + usage = type("FakeUsage", (object, ), {"limits": limits}) + + view_instance = ViewInstance() + + result = shares.get_context_data( + view_instance, fook="foov", bark="barv") + + charts = result.get("charts", []) + self.assertEqual(6, len(charts)) + expected_charts = { + existing_chart_name: { + "name": existing_chart_name, "used": existing_chart["used"], + "max": existing_chart["max"], "text": existing_chart["text"]}, + "Shares": {"name": "Shares", "used": 1, "max": 6, "text": False}, + "Share Storage": { + "name": "Share Storage", 'used': 2, "max": 7, "text": False}, + "Share Networks": { + "name": "Share Networks", "used": 3, "max": 8, "text": False}, + "Share Snapshots": { + "name": "Share Snapshots", "used": 4, "max": 9, "text": False}, + "Share Snapshots Storage": { + "name": "Share Snapshots Storage", "used": 5, "max": 10, + "text": False}, + } + for chart in charts: + name = chart["name"].title() + self.assertEqual( + {"name": name, "used": chart["used"], "max": chart["max"], + "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) diff --git a/releasenotes/notes/add-share-panel-group-to-project-dashboard-722ab48392588728.yaml b/releasenotes/notes/add-share-panel-group-to-project-dashboard-722ab48392588728.yaml new file mode 100644 index 00000000..86ebb004 --- /dev/null +++ b/releasenotes/notes/add-share-panel-group-to-project-dashboard-722ab48392588728.yaml @@ -0,0 +1,12 @@ +--- +features: + - Project dashboard now has manila-specific panel group called 'share'. + All 'tabs' we had before are panels in this group now. Each panel + is loaded in separate page. It allows us to avoid making redundant + API calls that we did loading all tabs at once. +upgrade: + - URLs for resources in project dashboard were changed. + One part of changes is removal of intermediate "shares" part. Example - + was - "/project/shares/share_networks/" + became - "/project/share_networks/" + Other part is rename of resource actions to be more alike.