Merge "Add the Snapshots tab on the Volume Details page"

This commit is contained in:
Jenkins 2017-07-27 14:08:37 +00:00 committed by Gerrit Code Review
commit cc1196588d
7 changed files with 110 additions and 10 deletions

View File

@ -110,6 +110,11 @@ class EditVolumeSnapshot(policy.PolicyTargetMixin, tables.LinkAction):
def allowed(self, request, snapshot=None):
return snapshot.status == "available"
def get_link_url(self, datum):
params = urlencode({"success_url": self.table.get_full_url()})
snapshot_id = self.table.get_object_id(datum)
return "?".join([reverse(self.url, args=(snapshot_id,)), params])
class CreateVolumeFromSnapshot(tables.LinkAction):
name = "create_from_snapshot"
@ -178,15 +183,11 @@ class VolumeSnapshotsFilterAction(tables.FilterAction):
if query in snapshot.name.lower()]
class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
class VolumeDetailsSnapshotsTable(volume_tables.VolumesTableBase):
name = tables.WrappingColumn(
"name",
verbose_name=_("Name"),
link="horizon:project:snapshots:detail")
volume_name = SnapshotVolumeNameColumn(
"name",
verbose_name=_("Volume Name"),
link="horizon:project:volumes:detail")
class Meta(object):
name = "volume_snapshots"
@ -209,3 +210,13 @@ class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
permissions = [
('openstack.services.volume', 'openstack.services.volumev2'),
]
class VolumeSnapshotsTable(VolumeDetailsSnapshotsTable):
volume_name = SnapshotVolumeNameColumn(
"name",
verbose_name=_("Volume Name"),
link="horizon:project:volumes:detail")
class Meta(VolumeDetailsSnapshotsTable.Meta):
pass

View File

@ -12,6 +12,7 @@
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.http import urlencode
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
@ -81,8 +82,11 @@ class UpdateView(forms.ModalFormView):
def get_context_data(self, **kwargs):
context = super(UpdateView, self).get_context_data(**kwargs)
context['snapshot'] = self.get_object()
success_url = self.request.GET.get('success_url', "")
args = (self.kwargs['snapshot_id'],)
context['submit_url'] = reverse(self.submit_url, args=args)
params = urlencode({"success_url": success_url})
context['submit_url'] = "?".join([reverse(self.submit_url, args=args),
params])
return context
def get_initial(self):
@ -91,6 +95,12 @@ class UpdateView(forms.ModalFormView):
'name': snapshot.name,
'description': snapshot.description}
def get_success_url(self):
success_url = self.request.GET.get(
"success_url",
reverse_lazy("horizon:project:snapshots:index"))
return success_url
class DetailView(tabs.TabView):
tab_group_class = vol_snapshot_tabs.SnapshotDetailTabs

View File

@ -34,7 +34,6 @@ from openstack_dashboard import api
from openstack_dashboard.api import cinder
from openstack_dashboard import policy
DELETABLE_STATES = ("available", "error", "error_extending")

View File

@ -14,8 +14,12 @@
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import tabs
from openstack_dashboard.api import cinder
from openstack_dashboard.dashboards.project.snapshots import tables
class OverviewTab(tabs.Tab):
name = _("Overview")
@ -26,6 +30,31 @@ class OverviewTab(tabs.Tab):
return {"volume": self.tab_group.kwargs['volume']}
class VolumeDetailTabs(tabs.TabGroup):
class SnapshotTab(tabs.TableTab):
table_classes = (tables.VolumeDetailsSnapshotsTable,)
name = _("Snapshots")
slug = "snapshots_tab"
template_name = "horizon/common/_detail_table.html"
preload = False
def get_volume_snapshots_data(self):
volume_id = self.tab_group.kwargs['volume_id']
try:
snapshots = cinder.volume_snapshot_list(
self.request, search_opts={'volume_id': volume_id})
volume = cinder.volume_get(self.request, volume_id)
except Exception:
snapshots = []
exceptions.handle(self.request,
_("Unable to retrieve volume snapshots for "
"volume %s.") % volume_id)
for snapshot in snapshots:
snapshot._volume = volume
return snapshots
class VolumeDetailTabs(tabs.DetailTabsGroup):
slug = "volume_details"
tabs = (OverviewTab,)
tabs = (OverviewTab, SnapshotTab)

View File

@ -34,6 +34,7 @@ from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
DETAIL_URL = ('horizon:project:volumes:detail')
INDEX_URL = reverse('horizon:project:volumes:index')
SEARCH_OPTS = dict(status=api.cinder.VOLUME_STATE_AVAILABLE)
@ -1490,6 +1491,53 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.assertEqual(res.status_code, 200)
self.assertEqual(volume.name, volume.id)
@test.create_stubs({cinder: ('tenant_absolute_limits',
'volume_get',
'volume_snapshot_list',
'message_list'),
api.nova: ('server_get',)})
def test_detail_view_snapshot_tab(self):
volume = self.cinder_volumes.first()
server = self.servers.first()
snapshots = self.cinder_volume_snapshots.list()
this_volume_snapshots = [snapshot for snapshot in snapshots
if snapshot.volume_id == volume.id]
volume.attachments = [{"server_id": server.id}]
# Expected api calls for the Overview tab.
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
cinder.volume_snapshot_list(IsA(http.HttpRequest),
search_opts={'volume_id': volume.id})\
.AndReturn(snapshots)
api.nova.server_get(IsA(http.HttpRequest), server.id).AndReturn(server)
cinder.tenant_absolute_limits(IsA(http.HttpRequest))\
.AndReturn(self.cinder_limits['absolute'])
cinder.message_list(
IsA(http.HttpRequest),
{
'resource_uuid': volume.id,
'resource_type': 'volume'
}
).AndReturn([])
# Expected api calls for the Snapshots tab.
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
cinder.volume_snapshot_list(IsA(http.HttpRequest),
search_opts={'volume_id': volume.id})\
.AndReturn(this_volume_snapshots)
self.mox.ReplayAll()
url = '?'.join([reverse(DETAIL_URL, args=[volume.id]),
'='.join(['tab', 'volume_details__snapshots_tab'])])
res = self.client.get(url)
self.assertTemplateUsed(res, 'horizon/common/_detail.html')
self.assertEqual(res.context['volume'].id, volume.id)
self.assertEqual(len(res.context['table'].data),
len(this_volume_snapshots))
self.assertNoMessages()
@test.create_stubs({cinder: ('volume_get',)})
def test_detail_view_with_exception(self):
volume = self.cinder_volumes.first()

View File

@ -45,6 +45,9 @@ urlpatterns = [
url(r'^(?P<volume_id>[^/]+)/$',
views.DetailView.as_view(),
name='detail'),
url(r'^(?P<volume_id>[^/]+)/\?tab=volume_details__snapshots_tab$',
views.DetailView.as_view(),
name='snapshots_tab'),
url(r'^(?P<volume_id>[^/]+)/upload_to_image/$',
views.UploadToImageView.as_view(),
name='upload_to_image'),

View File

@ -140,7 +140,7 @@ class VolumesView(tables.PagedTableMixin, VolumeTableMixIn,
return volumes
class DetailView(tabs.TabView):
class DetailView(tabs.TabbedTableView):
tab_group_class = project_tabs.VolumeDetailTabs
template_name = 'horizon/common/_detail.html'
page_title = "{{ volume.name|default:volume.id }}"