Move Consistency Group Snapshots out of Volumes panel

Change-Id: I2c02ff63c4e98040b3e46ded5331e706033dc746
Implements: blueprint reorganise-volumes
This commit is contained in:
Richard Jones 2017-02-06 16:26:23 +11:00
parent f85e0ffa91
commit 0b340eccc0
18 changed files with 87 additions and 73 deletions

View File

@ -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,

View File

@ -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"),)

View File

@ -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')
]

View File

@ -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):

View File

@ -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)

View File

@ -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_id>[^/]+)/cg_snapshot_detail/$',
views.DetailView.as_view(),
name='cg_snapshot_detail'),

View File

@ -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")

View File

@ -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',)})

View File

@ -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)

View File

@ -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

View File

@ -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')),
]

View File

@ -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'