Merge "Show volume snapshots in admin volume detail page"

This commit is contained in:
Zuul 2017-12-19 03:50:16 +00:00 committed by Gerrit Code Review
commit 9d159da4af
7 changed files with 78 additions and 28 deletions

View File

@ -78,3 +78,8 @@ class VolumeSnapshotsTable(volumes_tables.VolumesTableBase):
status_columns = ("status",)
columns = ('tenant', 'host', 'name', 'description', 'size', 'status',
'volume_name',)
class VolumeDetailsSnapshotsTable(VolumeSnapshotsTable):
class Meta(VolumeSnapshotsTable.Meta):
columns = ('name', 'description', 'size', 'status', 'volume_name',)

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from openstack_dashboard.dashboards.admin.snapshots import tables
from openstack_dashboard.dashboards.project.volumes import tabs as project_tabs
@ -27,8 +28,8 @@ class OverviewTab(project_tabs.OverviewTab):
class SnapshotTab(project_tabs.SnapshotTab):
pass
table_classes = (tables.VolumeDetailsSnapshotsTable,)
class VolumeDetailTabs(project_tabs.VolumeDetailTabs):
tabs = (OverviewTab, project_tabs.SnapshotTab)
tabs = (OverviewTab, SnapshotTab)

View File

@ -30,6 +30,7 @@ from openstack_dashboard.test import helpers as test
from openstack_dashboard.dashboards.admin.snapshots import forms
DETAIL_URL = ('horizon:admin:volumes:detail')
INDEX_URL = reverse('horizon:admin:volumes:index')
@ -385,3 +386,52 @@ class VolumeTests(test.BaseAdminViewTests):
mock_get.assert_called_once_with(test.IsHttpRequest(), volume.id)
self.assertNotContains(res, status_option)
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}]
volume_limits = self.cinder_limits['absolute']
with mock.patch.object(api.nova, 'server_get',
return_value=server) as mock_server_get, \
mock.patch.object(
cinder, 'tenant_absolute_limits',
return_value=volume_limits) as mock_limits, \
mock.patch.object(
cinder, 'volume_get',
return_value=volume) as mock_volume_get, \
mock.patch.object(
cinder, 'volume_snapshot_list',
return_value=this_volume_snapshots) \
as mock_snapshot_list, \
mock.patch.object(
cinder, 'message_list',
return_value=[]) as mock_message_list:
url = (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()
mock_server_get.assert_called_once_with(test.IsHttpRequest(),
server.id)
mock_volume_get.assert_called_once_with(test.IsHttpRequest(),
volume.id)
mock_snapshot_list.assert_called_once_with(
test.IsHttpRequest(),
search_opts={'volume_id': volume.id, 'all_tenants': True})
mock_limits.assert_called_once()
mock_message_list.assert_called_once_with(
test.IsHttpRequest(),
{
'resource_uuid': volume.id,
'resource_type': 'volume'
})

View File

@ -118,6 +118,11 @@ class DetailView(volumes_views.DetailView):
context["actions"] = table.render_row_actions(context["volume"])
return context
def get_search_opts(self, volume):
search_opts = super(DetailView, self).get_search_opts(volume)
search_opts['all_tenants'] = True
return search_opts
def get_redirect_url(self):
return reverse('horizon:admin:volumes:index')

View File

@ -14,10 +14,8 @@
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
@ -42,26 +40,12 @@ class SnapshotTab(tabs.TableTab):
name = _("Snapshots")
slug = "snapshots_tab"
template_name = "horizon/common/_detail_table.html"
dashboard = 'project'
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})
except Exception:
snapshots = []
exceptions.handle(self.request,
_("Unable to retrieve volume snapshots for "
"volume %s.") % volume_id)
try:
volume = cinder.volume_get(self.request, volume_id)
except Exception:
volume = None
exceptions.handle(self.request,
_("Unable to retrieve volume details for "
"volume %s.") % volume_id)
snapshots = self.tab_group.kwargs['snapshots']
volume = self.tab_group.kwargs['volume']
if volume is not None:
for snapshot in snapshots:

View File

@ -1423,8 +1423,8 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
len(this_volume_snapshots))
self.assertNoMessages()
mock_get.assert_called_with(test.IsHttpRequest(), volume.id)
mock_snapshot_list.assert_called_with(
mock_get.assert_called_once_with(test.IsHttpRequest(), volume.id)
mock_snapshot_list.assert_called_once_with(
test.IsHttpRequest(), search_opts={'volume_id': volume.id})
mock_limits.assert_called_once()
mock_message.assert_called_once_with(

View File

@ -147,7 +147,7 @@ class DetailView(tabs.TabbedTableView):
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
volume = self.get_data()
volume, snapshots = self.get_data()
table = volume_tables.VolumesTable(self.request)
context["volume"] = volume
context["url"] = self.get_redirect_url()
@ -156,13 +156,17 @@ class DetailView(tabs.TabbedTableView):
volume.status_label = filters.get_display_label(choices, volume.status)
return context
def get_search_opts(self, volume):
return {'volume_id': volume.id}
@memoized.memoized_method
def get_data(self):
try:
volume_id = self.kwargs['volume_id']
volume = cinder.volume_get(self.request, volume_id)
search_opts = self.get_search_opts(volume)
snapshots = cinder.volume_snapshot_list(
self.request, search_opts={'volume_id': volume.id})
self.request, search_opts=search_opts)
if snapshots:
setattr(volume, 'has_snapshot', True)
for att in volume.attachments:
@ -185,14 +189,15 @@ class DetailView(tabs.TabbedTableView):
_('Unable to retrieve volume messages.'),
ignore=True,
)
return volume
return volume, snapshots
def get_redirect_url(self):
return reverse('horizon:project:volumes:index')
def get_tabs(self, request, *args, **kwargs):
volume = self.get_data()
return self.tab_group_class(request, volume=volume, **kwargs)
volume, snapshots = self.get_data()
return self.tab_group_class(
request, volume=volume, snapshots=snapshots, **kwargs)
class CreateView(forms.ModalFormView):