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.