diff --git a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/__init__.py b/openstack_dashboard/dashboards/project/cg_snapshots/__init__.py similarity index 100% rename from openstack_dashboard/dashboards/project/volumes/cg_snapshots/__init__.py rename to openstack_dashboard/dashboards/project/cg_snapshots/__init__.py diff --git a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/forms.py b/openstack_dashboard/dashboards/project/cg_snapshots/forms.py similarity index 97% rename from openstack_dashboard/dashboards/project/volumes/cg_snapshots/forms.py rename to openstack_dashboard/dashboards/project/cg_snapshots/forms.py index 1134fc471c..338108702e 100644 --- a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/forms.py +++ b/openstack_dashboard/dashboards/project/cg_snapshots/forms.py @@ -68,7 +68,7 @@ class CreateCGroupForm(forms.SelfHandlingForm): messages.info(request, message) return cgroup except Exception: - redirect = reverse("horizon:project:volumes:index") + redirect = reverse("horizon:project:cg_snapshots:index") msg = _('Unable to create consistency ' 'group "%s" from snapshot.') % data['name'] exceptions.handle(request, diff --git a/openstack_dashboard/dashboards/project/cg_snapshots/panel.py b/openstack_dashboard/dashboards/project/cg_snapshots/panel.py new file mode 100644 index 0000000000..69319a5930 --- /dev/null +++ b/openstack_dashboard/dashboards/project/cg_snapshots/panel.py @@ -0,0 +1,26 @@ +# Copyright 2017 Rackspace, 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 + + +class CGSnapshots(horizon.Panel): + name = _("Consistency Group Snapshots") + slug = 'cg_snapshots' + permissions = ( + ('openstack.services.volume', 'openstack.services.volumev2'), + ) + policy_rules = (("volume", "consistencygroup:get_all_cgsnapshots"),) diff --git a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/tables.py b/openstack_dashboard/dashboards/project/cg_snapshots/tables.py similarity index 94% rename from openstack_dashboard/dashboards/project/volumes/cg_snapshots/tables.py rename to openstack_dashboard/dashboards/project/cg_snapshots/tables.py index 45ee8fdd27..5af5dc90c1 100644 --- a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/tables.py +++ b/openstack_dashboard/dashboards/project/cg_snapshots/tables.py @@ -23,7 +23,7 @@ from openstack_dashboard import policy class CreateVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction): name = "create_cgroup" verbose_name = _("Create Consistency Group") - url = "horizon:project:volumes:cg_snapshots:create_cgroup" + url = "horizon:project:cg_snapshots:create_cgroup" classes = ("ajax-modal",) policy_rules = (("volume", "consistencygroup:create"),) @@ -90,8 +90,7 @@ class CGSnapshotsTable(tables.DataTable): name = tables.Column("name", verbose_name=_("Name"), - link="horizon:project:volumes:" - "cg_snapshots:cg_snapshot_detail") + link="horizon:project:cg_snapshots:detail") description = tables.Column("description", verbose_name=_("Description"), truncate=40) @@ -113,4 +112,6 @@ class CGSnapshotsTable(tables.DataTable): DeleteVolumeCGSnapshot,) row_class = UpdateRow status_columns = ("status",) - permissions = ['openstack.services.volume'] + permissions = [ + ('openstack.services.volume', 'openstack.services.volumev2') + ] diff --git a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/tabs.py b/openstack_dashboard/dashboards/project/cg_snapshots/tabs.py similarity index 88% rename from openstack_dashboard/dashboards/project/volumes/cg_snapshots/tabs.py rename to openstack_dashboard/dashboards/project/cg_snapshots/tabs.py index b0ba1cb051..f1fc5231f7 100644 --- a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/tabs.py +++ b/openstack_dashboard/dashboards/project/cg_snapshots/tabs.py @@ -19,14 +19,14 @@ from horizon import tabs class OverviewTab(tabs.Tab): name = _("Overview") slug = "overview" - template_name = ("project/volumes/cg_snapshots/_detail_overview.html") + template_name = "project/cg_snapshots/_detail_overview.html" def get_context_data(self, request): cg_snapshot = self.tab_group.kwargs['cg_snapshot'] return {"cg_snapshot": cg_snapshot} def get_redirect_url(self): - return reverse('horizon:project:volumes:cg_snapshots:index') + return reverse('horizon:project:cg_snapshots:index') class CGSnapshotsDetailTabs(tabs.TabGroup): diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/_create.html b/openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/_create.html similarity index 100% rename from openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/_create.html rename to openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/_create.html diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/_detail_overview.html b/openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/_detail_overview.html similarity index 100% rename from openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/_detail_overview.html rename to openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/_detail_overview.html diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/_update.html b/openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/_update.html similarity index 100% rename from openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/_update.html rename to openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/_update.html diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/create.html b/openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/create.html similarity index 100% rename from openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/create.html rename to openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/create.html diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/update.html b/openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/update.html similarity index 100% rename from openstack_dashboard/dashboards/project/volumes/templates/volumes/cg_snapshots/update.html rename to openstack_dashboard/dashboards/project/cg_snapshots/templates/cg_snapshots/update.html diff --git a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/tests.py b/openstack_dashboard/dashboards/project/cg_snapshots/tests.py similarity index 87% rename from openstack_dashboard/dashboards/project/volumes/cg_snapshots/tests.py rename to openstack_dashboard/dashboards/project/cg_snapshots/tests.py index 858b526cb4..7ac5e3bb9a 100644 --- a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/tests.py +++ b/openstack_dashboard/dashboards/project/cg_snapshots/tests.py @@ -12,16 +12,13 @@ from django.core.urlresolvers import reverse from django import http -from django.utils.http import urlunquote from mox3.mox import IsA # noqa from openstack_dashboard.api import cinder from openstack_dashboard.test import helpers as test -VOLUME_INDEX_URL = reverse('horizon:project:volumes:index') -VOLUME_CG_SNAPSHOTS_TAB_URL = urlunquote(reverse( - 'horizon:project:volumes:cg_snapshots_tab')) +INDEX_URL = reverse('horizon:project:cg_snapshots:index') class CGroupSnapshotTests(test.TestCase): @@ -44,11 +41,11 @@ class CGroupSnapshotTests(test.TestCase): .AndReturn(cgroup) self.mox.ReplayAll() - url = reverse('horizon:project:volumes:cg_snapshots:create_cgroup', + url = reverse('horizon:project:cg_snapshots:create_cgroup', args=[cg_snapshot.id]) res = self.client.post(url, formData) self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) @test.create_stubs({cinder: ('volume_cg_snapshot_get', 'volume_cgroup_create_from_source',)}) @@ -69,7 +66,7 @@ class CGroupSnapshotTests(test.TestCase): .AndRaise(self.exceptions.cinder) self.mox.ReplayAll() - url = reverse('horizon:project:volumes:cg_snapshots:create_cgroup', + url = reverse('horizon:project:cg_snapshots:create_cgroup', args=[cg_snapshot.id]) res = self.client.post(url, formData) self.assertNoFormErrors(res) @@ -78,7 +75,7 @@ class CGroupSnapshotTests(test.TestCase): self.assertIn('Unable to create consistency group "%s" from snapshot.' % new_cg_name, res.cookies.output().replace('\\', '')) - self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) @test.create_stubs({cinder: ('volume_cg_snapshot_list', 'volume_cg_snapshot_delete',)}) @@ -93,8 +90,7 @@ class CGroupSnapshotTests(test.TestCase): form_data = {'action': 'volume_cg_snapshots__delete_cg_snapshot__%s' % cg_snapshot.id} - res = self.client.post(VOLUME_CG_SNAPSHOTS_TAB_URL, form_data, - follow=True) + res = self.client.post(INDEX_URL, form_data, follow=True) self.assertEqual(res.status_code, 200) self.assertIn("Scheduled deletion of Snapshot: %s" % cg_snapshot.name, [m.message for m in res.context['messages']]) @@ -114,8 +110,7 @@ class CGroupSnapshotTests(test.TestCase): form_data = {'action': 'volume_cg_snapshots__delete_cg_snapshot__%s' % cg_snapshot.id} - res = self.client.post(VOLUME_CG_SNAPSHOTS_TAB_URL, form_data, - follow=True) + res = self.client.post(INDEX_URL, form_data, follow=True) self.assertEqual(res.status_code, 200) self.assertIn("Unable to delete snapshot: %s" % cg_snapshot.name, [m.message for m in res.context['messages']]) @@ -143,7 +138,7 @@ class CGroupSnapshotTests(test.TestCase): self.mox.ReplayAll() url = reverse( - 'horizon:project:volumes:cg_snapshots:cg_snapshot_detail', + 'horizon:project:cg_snapshots:cg_snapshot_detail', args=[cg_snapshot.id]) res = self.client.get(url) self.assertNoFormErrors(res) @@ -159,8 +154,8 @@ class CGroupSnapshotTests(test.TestCase): self.mox.ReplayAll() url = reverse( - 'horizon:project:volumes:cg_snapshots:cg_snapshot_detail', + 'horizon:project:cg_snapshots:cg_snapshot_detail', args=[cg_snapshot.id]) res = self.client.get(url) self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL) + self.assertRedirectsNoFollow(res, INDEX_URL) diff --git a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/urls.py b/openstack_dashboard/dashboards/project/cg_snapshots/urls.py similarity index 86% rename from openstack_dashboard/dashboards/project/volumes/cg_snapshots/urls.py rename to openstack_dashboard/dashboards/project/cg_snapshots/urls.py index e9840522e4..2e517a575e 100644 --- a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/urls.py +++ b/openstack_dashboard/dashboards/project/cg_snapshots/urls.py @@ -12,9 +12,10 @@ from django.conf.urls import url -from openstack_dashboard.dashboards.project.volumes.cg_snapshots import views +from openstack_dashboard.dashboards.project.cg_snapshots import views urlpatterns = [ + url(r'^$', views.CGSnapshotsView.as_view(), name='index'), url(r'^(?P[^/]+)/cg_snapshot_detail/$', views.DetailView.as_view(), name='cg_snapshot_detail'), diff --git a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/views.py b/openstack_dashboard/dashboards/project/cg_snapshots/views.py similarity index 82% rename from openstack_dashboard/dashboards/project/volumes/cg_snapshots/views.py rename to openstack_dashboard/dashboards/project/cg_snapshots/views.py index 3bfc6fc33d..ef21157cf6 100644 --- a/openstack_dashboard/dashboards/project/volumes/cg_snapshots/views.py +++ b/openstack_dashboard/dashboards/project/cg_snapshots/views.py @@ -16,6 +16,7 @@ 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 @@ -23,17 +24,32 @@ from openstack_dashboard import api from openstack_dashboard.api import cinder from openstack_dashboard.usage import quotas -from openstack_dashboard.dashboards.project.volumes \ - .cg_snapshots import forms as cg_snapshot_forms -from openstack_dashboard.dashboards.project.volumes \ - .cg_snapshots import tables as cg_snapshot_tables -from openstack_dashboard.dashboards.project.volumes \ - .cg_snapshots import tabs as cg_snapshot_tabs +from openstack_dashboard.dashboards.project.cg_snapshots \ + import forms as cg_snapshot_forms +from openstack_dashboard.dashboards.project.cg_snapshots \ + import tables as cg_snapshot_tables +from openstack_dashboard.dashboards.project.cg_snapshots \ + import tabs as cg_snapshot_tabs CGROUP_INFO_FIELDS = ("name", "description") -INDEX_URL = "horizon:project:volumes:index" +INDEX_URL = "horizon:project:cg_snapshots:index" + + +class CGSnapshotsView(tables.DataTableView): + table_class = cg_snapshot_tables.CGSnapshotsTable + page_title = _("Consistency Group Snapshots") + + def get_data(self): + try: + cg_snapshots = api.cinder.volume_cg_snapshot_list(self.request) + except Exception: + cg_snapshots = [] + exceptions.handle(self.request, _("Unable to retrieve " + "volume consistency group " + "snapshots.")) + return cg_snapshots class DetailView(tabs.TabView): @@ -84,7 +100,7 @@ class DetailView(tabs.TabView): @staticmethod def get_redirect_url(): - return reverse('horizon:project:volumes:index') + return reverse(INDEX_URL) def get_tabs(self, request, *args, **kwargs): cg_snapshot = self.get_data() @@ -93,8 +109,8 @@ class DetailView(tabs.TabView): class CreateCGroupView(forms.ModalFormView): form_class = cg_snapshot_forms.CreateCGroupForm - template_name = 'project/volumes/cg_snapshots/create.html' - submit_url = "horizon:project:volumes:cg_snapshots:create_cgroup" + template_name = 'project/cg_snapshots/create.html' + submit_url = "horizon:project:cg_snapshots:create_cgroup" success_url = reverse_lazy('horizon:project:cgroups:index') page_title = _("Create Volume Consistency Group") diff --git a/openstack_dashboard/dashboards/project/cgroups/tests.py b/openstack_dashboard/dashboards/project/cgroups/tests.py index 150e92a129..6e551c5f94 100644 --- a/openstack_dashboard/dashboards/project/cgroups/tests.py +++ b/openstack_dashboard/dashboards/project/cgroups/tests.py @@ -20,8 +20,8 @@ from openstack_dashboard.test import helpers as test INDEX_URL = reverse('horizon:project:cgroups:index') -VOLUME_CGROUPS_SNAP_TAB_URL = urlunquote(reverse( - 'horizon:project:volumes:cg_snapshots_tab')) +VOLUME_CGROUPS_SNAP_INDEX_URL = urlunquote(reverse( + 'horizon:project:cg_snapshots:index')) class ConsistencyGroupTests(test.TestCase): @@ -296,7 +296,7 @@ class ConsistencyGroupTests(test.TestCase): args=[cgroup.id]) res = self.client.post(url, formData) self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, VOLUME_CGROUPS_SNAP_TAB_URL) + self.assertRedirectsNoFollow(res, VOLUME_CGROUPS_SNAP_INDEX_URL) @test.create_stubs({cinder: ('volume_cgroup_get', 'volume_cgroup_create_from_source',)}) diff --git a/openstack_dashboard/dashboards/project/cgroups/views.py b/openstack_dashboard/dashboards/project/cgroups/views.py index 4df3853364..954b5e4a1b 100644 --- a/openstack_dashboard/dashboards/project/cgroups/views.py +++ b/openstack_dashboard/dashboards/project/cgroups/views.py @@ -190,7 +190,7 @@ class CreateSnapshotView(forms.ModalFormView): template_name = 'project/cgroups/create_snapshot.html' submit_label = _("Create Snapshot") submit_url = "horizon:project:cgroups:create_snapshot" - success_url = reverse_lazy('horizon:project:volumes:cg_snapshots_tab') + success_url = reverse_lazy('horizon:project:cg_snapshots:index') def get_context_data(self, **kwargs): context = super(CreateSnapshotView, self).get_context_data(**kwargs) diff --git a/openstack_dashboard/dashboards/project/volumes/tabs.py b/openstack_dashboard/dashboards/project/volumes/tabs.py index 2253d249e4..4196f23991 100644 --- a/openstack_dashboard/dashboards/project/volumes/tabs.py +++ b/openstack_dashboard/dashboards/project/volumes/tabs.py @@ -21,10 +21,7 @@ from horizon.tables import PagedTableMixin from horizon import tabs from openstack_dashboard import api -from openstack_dashboard import policy -from openstack_dashboard.dashboards.project.volumes.cg_snapshots \ - import tables as cg_snapshots_tables from openstack_dashboard.dashboards.project.volumes.volumes \ import tables as volume_tables @@ -122,32 +119,7 @@ class VolumeTab(PagedTableMixin, tabs.TableTab, VolumeTableMixIn): return volumes -class CGSnapshotsTab(tabs.TableTab): - table_classes = (cg_snapshots_tables.CGSnapshotsTable,) - name = _("Consistency Group Snapshots") - slug = "cg_snapshots_tab" - template_name = ("horizon/common/_detail_table.html") - preload = False - - def allowed(self, request): - return policy.check( - (("volume", "consistencygroup:get_all_cgsnapshots"),), - request - ) - - def get_volume_cg_snapshots_data(self): - try: - cg_snapshots = api.cinder.volume_cg_snapshot_list( - self.request) - except Exception: - cg_snapshots = [] - exceptions.handle(self.request, _("Unable to retrieve " - "volume consistency group " - "snapshots.")) - return cg_snapshots - - class VolumeAndSnapshotTabs(tabs.TabGroup): slug = "volumes_and_snapshots" - tabs = (VolumeTab, CGSnapshotsTab) + tabs = (VolumeTab, ) sticky = True diff --git a/openstack_dashboard/dashboards/project/volumes/urls.py b/openstack_dashboard/dashboards/project/volumes/urls.py index 5001fed215..ef6a3f9e23 100644 --- a/openstack_dashboard/dashboards/project/volumes/urls.py +++ b/openstack_dashboard/dashboards/project/volumes/urls.py @@ -15,8 +15,6 @@ from django.conf.urls import include from django.conf.urls import url -from openstack_dashboard.dashboards.project.volumes.cg_snapshots \ - import urls as cg_snapshots_urls from openstack_dashboard.dashboards.project.volumes import views from openstack_dashboard.dashboards.project.volumes.volumes \ import urls as volume_urls @@ -25,12 +23,7 @@ urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^\?tab=volumes_and_snapshots__volumes_tab$', views.IndexView.as_view(), name='volumes_tab'), - url(r'^\?tab=volumes_and_snapshots__cg_snapshots_tab$', - views.IndexView.as_view(), name='cg_snapshots_tab'), url(r'', include( volume_urls, namespace='volumes')), - url(r'cg_snapshots/', include( - cg_snapshots_urls, - namespace='cg_snapshots')), ] diff --git a/openstack_dashboard/enabled/_1350_project_cg_snapshots_panel.py b/openstack_dashboard/enabled/_1350_project_cg_snapshots_panel.py new file mode 100644 index 0000000000..1709ef49fb --- /dev/null +++ b/openstack_dashboard/enabled/_1350_project_cg_snapshots_panel.py @@ -0,0 +1,10 @@ +# The slug of the panel to be added to HORIZON_CONFIG. Required. +PANEL = 'cg_snapshots' +# The slug of the dashboard the PANEL associated with. Required. +PANEL_DASHBOARD = 'project' +# The slug of the panel group the PANEL is associated with. +PANEL_GROUP = 'volumes' + +# Python panel class of the PANEL to be added. +ADD_PANEL = \ + 'openstack_dashboard.dashboards.project.cg_snapshots.panel.CGSnapshots'