Show generic group info in volume and volume snapshot pages
blueprint cinder-generic-volume-groups Co-Authored-By: Ivan Kolodyazhny <e0ne@e0ne.info> Change-Id: I96515087a3e3a5328cceaff4e0e9a811601c7ba0
This commit is contained in:
parent
32d463a298
commit
ef4d8d69c9
|
@ -100,7 +100,7 @@ class Volume(BaseCinderAPIResourceWrapper):
|
|||
class VolumeSnapshot(BaseCinderAPIResourceWrapper):
|
||||
|
||||
_attrs = ['id', 'name', 'description', 'size', 'status',
|
||||
'created_at', 'volume_id',
|
||||
'created_at', 'volume_id', 'group_snapshot_id',
|
||||
'os-extended-snapshot-attributes:project_id',
|
||||
'metadata']
|
||||
|
||||
|
@ -344,7 +344,8 @@ def volume_list_paged(request, search_opts=None, marker=None, paginate=False,
|
|||
|
||||
@profiler.trace
|
||||
def volume_get(request, volume_id):
|
||||
volume_data = cinderclient(request).volumes.get(volume_id)
|
||||
client = _cinderclient_with_generic_groups(request)
|
||||
volume_data = client.volumes.get(volume_id)
|
||||
|
||||
for attachment in volume_data.attachments:
|
||||
if "server_id" in attachment:
|
||||
|
@ -455,7 +456,8 @@ def volume_migrate(request, volume_id, host, force_host_copy=False,
|
|||
|
||||
@profiler.trace
|
||||
def volume_snapshot_get(request, snapshot_id):
|
||||
snapshot = cinderclient(request).volume_snapshots.get(snapshot_id)
|
||||
client = _cinderclient_with_generic_groups(request)
|
||||
snapshot = client.volume_snapshots.get(snapshot_id)
|
||||
return VolumeSnapshot(snapshot)
|
||||
|
||||
|
||||
|
@ -473,7 +475,7 @@ def volume_snapshot_list_paged(request, search_opts=None, marker=None,
|
|||
has_more_data = False
|
||||
has_prev_data = False
|
||||
snapshots = []
|
||||
c_client = cinderclient(request)
|
||||
c_client = _cinderclient_with_generic_groups(request)
|
||||
if c_client is None:
|
||||
return snapshots, has_more_data, has_more_data
|
||||
|
||||
|
|
|
@ -96,6 +96,13 @@ class DeleteVolumeSnapshot(policy.PolicyTargetMixin, tables.DeleteAction):
|
|||
def delete(self, request, obj_id):
|
||||
api.cinder.volume_snapshot_delete(request, obj_id)
|
||||
|
||||
def allowed(self, request, datum=None):
|
||||
if datum:
|
||||
# Can't delete snapshot if part of group snapshot
|
||||
if datum.group_snapshot:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class EditVolumeSnapshot(policy.PolicyTargetMixin, tables.LinkAction):
|
||||
name = "edit"
|
||||
|
@ -159,6 +166,11 @@ class UpdateRow(tables.Row):
|
|||
def get_data(self, request, snapshot_id):
|
||||
snapshot = cinder.volume_snapshot_get(request, snapshot_id)
|
||||
snapshot._volume = cinder.volume_get(request, snapshot.volume_id)
|
||||
if getattr(snapshot, 'group_snapshot_id', None):
|
||||
snapshot.group_snapshot = cinder.group_snapshot_get(
|
||||
request, snapshot.group_snapshot_id)
|
||||
else:
|
||||
snapshot.group_snapshot = None
|
||||
return snapshot
|
||||
|
||||
|
||||
|
@ -174,6 +186,17 @@ class SnapshotVolumeNameColumn(tables.WrappingColumn):
|
|||
return reverse(self.link, args=(volume_id,))
|
||||
|
||||
|
||||
class GroupSnapshotNameColumn(tables.WrappingColumn):
|
||||
def get_raw_data(self, snapshot):
|
||||
group_snapshot = snapshot.group_snapshot
|
||||
return group_snapshot.name_or_id if group_snapshot else _("-")
|
||||
|
||||
def get_link_url(self, snapshot):
|
||||
group_snapshot = snapshot.group_snapshot
|
||||
if group_snapshot:
|
||||
return reverse(self.link, args=(group_snapshot.id,))
|
||||
|
||||
|
||||
class VolumeSnapshotsFilterAction(tables.FilterAction):
|
||||
|
||||
def filter(self, table, snapshots, filter_string):
|
||||
|
@ -184,6 +207,10 @@ class VolumeSnapshotsFilterAction(tables.FilterAction):
|
|||
|
||||
|
||||
class VolumeDetailsSnapshotsTable(volume_tables.VolumesTableBase):
|
||||
group_snapshot = GroupSnapshotNameColumn(
|
||||
"name",
|
||||
verbose_name=_("Group Snapshot"),
|
||||
link="horizon:project:vg_snapshots:detail")
|
||||
name = tables.WrappingColumn(
|
||||
"name",
|
||||
verbose_name=_("Name"),
|
||||
|
|
|
@ -36,7 +36,8 @@ class OverviewTab(tabs.Tab):
|
|||
_('Unable to retrieve snapshot details.'),
|
||||
redirect=redirect)
|
||||
return {"snapshot": snapshot,
|
||||
"volume": volume}
|
||||
"volume": volume,
|
||||
"group_snapshot": snapshot.group_snapshot}
|
||||
|
||||
def get_redirect_url(self):
|
||||
return reverse('horizon:project:snapshots:index')
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
{% endif %}
|
||||
</a>
|
||||
</dd>
|
||||
<dt>{% trans "Group Snapshot" %}</dt>
|
||||
{% if group_snapshot %}
|
||||
<dd><a href="{% url 'horizon:project:vg_snapshots:detail' snapshot.group_snapshot_id %}">{{ group_snapshot.name_or_id }}</a></dd>
|
||||
{% else %}
|
||||
<dd>{% trans "-" %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
|
||||
<h4>{% trans "Specs" %}</h4>
|
||||
|
|
|
@ -34,15 +34,18 @@ INDEX_URL = reverse('horizon:project:snapshots:index')
|
|||
|
||||
class VolumeSnapshotsViewTests(test.TestCase):
|
||||
@test.create_mocks({api.cinder: ('volume_snapshot_list_paged',
|
||||
'volume_list'),
|
||||
'volume_list',
|
||||
'group_snapshot_list'),
|
||||
api.base: ('is_service_enabled',)})
|
||||
def _test_snapshots_index_paginated(self, marker, sort_dir, snapshots, url,
|
||||
has_more, has_prev):
|
||||
has_more, has_prev, with_groups=False):
|
||||
self.mock_is_service_enabled.return_value = True
|
||||
self.mock_volume_snapshot_list_paged.return_value = [snapshots,
|
||||
has_more,
|
||||
has_prev]
|
||||
self.mock_volume_list.return_value = self.cinder_volumes.list()
|
||||
self.mock_group_snapshot_list.return_value = \
|
||||
self.cinder_volume_snapshots_with_groups.list()
|
||||
|
||||
res = self.client.get(urlunquote(url))
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
@ -56,17 +59,21 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
paginate=True)
|
||||
self.mock_volume_list.assert_called_once_with(test.IsHttpRequest())
|
||||
|
||||
if with_groups:
|
||||
self.mock_group_snapshot_list.assert_called_once_with(
|
||||
test.IsHttpRequest())
|
||||
|
||||
return res
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=1)
|
||||
def test_snapshots_index_paginated(self):
|
||||
mox_snapshots = self.cinder_volume_snapshots.list()
|
||||
mock_snapshots = self.cinder_volume_snapshots.list()
|
||||
size = settings.API_RESULT_PAGE_SIZE
|
||||
base_url = INDEX_URL
|
||||
next = snapshot_tables.VolumeSnapshotsTable._meta.pagination_param
|
||||
|
||||
# get first page
|
||||
expected_snapshots = mox_snapshots[:size]
|
||||
expected_snapshots = mock_snapshots[:size]
|
||||
res = self._test_snapshots_index_paginated(
|
||||
marker=None, sort_dir="desc", snapshots=expected_snapshots,
|
||||
url=base_url, has_more=True, has_prev=False)
|
||||
|
@ -74,7 +81,7 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
self.assertItemsEqual(snapshots, expected_snapshots)
|
||||
|
||||
# get second page
|
||||
expected_snapshots = mox_snapshots[size:2 * size]
|
||||
expected_snapshots = mock_snapshots[size:2 * size]
|
||||
marker = expected_snapshots[0].id
|
||||
|
||||
url = base_url + "?%s=%s" % (next, marker)
|
||||
|
@ -85,7 +92,7 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
self.assertItemsEqual(snapshots, expected_snapshots)
|
||||
|
||||
# get last page
|
||||
expected_snapshots = mox_snapshots[-size:]
|
||||
expected_snapshots = mock_snapshots[-size:]
|
||||
marker = expected_snapshots[0].id
|
||||
url = base_url + "?%s=%s" % (next, marker)
|
||||
res = self._test_snapshots_index_paginated(
|
||||
|
@ -94,15 +101,29 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
snapshots = res.context['volume_snapshots_table'].data
|
||||
self.assertItemsEqual(snapshots, expected_snapshots)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=1)
|
||||
def test_snapshots_index_with_group(self):
|
||||
mock_snapshots = self.cinder_volume_snapshots_with_groups.list()
|
||||
size = settings.API_RESULT_PAGE_SIZE
|
||||
base_url = INDEX_URL
|
||||
|
||||
# get first page
|
||||
expected_snapshots = mock_snapshots[:size]
|
||||
res = self._test_snapshots_index_paginated(
|
||||
marker=None, sort_dir="desc", snapshots=expected_snapshots,
|
||||
url=base_url, has_more=False, has_prev=False, with_groups=True)
|
||||
snapshots = res.context['volume_snapshots_table'].data
|
||||
self.assertItemsEqual(snapshots, mock_snapshots)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=1)
|
||||
def test_snapshots_index_paginated_prev_page(self):
|
||||
mox_snapshots = self.cinder_volume_snapshots.list()
|
||||
mock_snapshots = self.cinder_volume_snapshots.list()
|
||||
size = settings.API_RESULT_PAGE_SIZE
|
||||
base_url = INDEX_URL
|
||||
prev = snapshot_tables.VolumeSnapshotsTable._meta.prev_pagination_param
|
||||
|
||||
# prev from some page
|
||||
expected_snapshots = mox_snapshots[size:2 * size]
|
||||
expected_snapshots = mock_snapshots[size:2 * size]
|
||||
marker = expected_snapshots[0].id
|
||||
url = base_url + "?%s=%s" % (prev, marker)
|
||||
res = self._test_snapshots_index_paginated(
|
||||
|
@ -112,7 +133,7 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
self.assertItemsEqual(snapshots, expected_snapshots)
|
||||
|
||||
# back to first page
|
||||
expected_snapshots = mox_snapshots[:size]
|
||||
expected_snapshots = mock_snapshots[:size]
|
||||
marker = expected_snapshots[0].id
|
||||
url = base_url + "?%s=%s" % (prev, marker)
|
||||
res = self._test_snapshots_index_paginated(
|
||||
|
|
|
@ -38,6 +38,7 @@ class SnapshotsView(tables.PagedTableMixin, tables.DataTableView):
|
|||
def get_data(self):
|
||||
snapshots = []
|
||||
volumes = {}
|
||||
needs_gs = False
|
||||
if cinder.is_volume_service_enabled(self.request):
|
||||
try:
|
||||
marker, sort_dir = self._get_marker()
|
||||
|
@ -45,15 +46,36 @@ class SnapshotsView(tables.PagedTableMixin, tables.DataTableView):
|
|||
cinder.volume_snapshot_list_paged(
|
||||
self.request, paginate=True, marker=marker,
|
||||
sort_dir=sort_dir)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve volume snapshots."))
|
||||
try:
|
||||
volumes = cinder.volume_list(self.request)
|
||||
volumes = dict((v.id, v) for v in volumes)
|
||||
except Exception:
|
||||
exceptions.handle(self.request, _("Unable to retrieve "
|
||||
"volume snapshots."))
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve volumes."))
|
||||
needs_gs = any(getattr(snapshot, 'group_snapshot_id', None)
|
||||
for snapshot in snapshots)
|
||||
if needs_gs:
|
||||
try:
|
||||
group_snapshots = cinder.group_snapshot_list(self.request)
|
||||
group_snapshots = dict((gs.id, gs) for gs
|
||||
in group_snapshots)
|
||||
except Exception:
|
||||
group_snapshots = {}
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve group snapshots."))
|
||||
|
||||
for snapshot in snapshots:
|
||||
volume = volumes.get(snapshot.volume_id)
|
||||
setattr(snapshot, '_volume', volume)
|
||||
if needs_gs:
|
||||
group_snapshot = group_snapshots.get(
|
||||
snapshot.group_snapshot_id)
|
||||
snapshot.group_snapshot = group_snapshot
|
||||
else:
|
||||
snapshot.group_snapshot = None
|
||||
|
||||
return snapshots
|
||||
|
||||
|
@ -127,6 +149,11 @@ class DetailView(tabs.TabView):
|
|||
snapshot_id)
|
||||
snapshot._volume = cinder.volume_get(self.request,
|
||||
snapshot.volume_id)
|
||||
if getattr(snapshot, 'group_snapshot_id', None):
|
||||
snapshot.group_snapshot = cinder.group_snapshot_get(
|
||||
self.request, snapshot.group_snapshot_id)
|
||||
else:
|
||||
snapshot.group_snapshot = None
|
||||
except Exception:
|
||||
redirect = self.get_redirect_url()
|
||||
exceptions.handle(self.request,
|
||||
|
|
|
@ -61,21 +61,21 @@ class UpdateRow(tables.Row):
|
|||
vg_snapshot = cinder.group_snapshot_get(request, vg_snapshot_id)
|
||||
if getattr(vg_snapshot, 'group_id', None):
|
||||
try:
|
||||
vg_snapshot._group = cinder.group_get(request,
|
||||
vg_snapshot.group_id)
|
||||
vg_snapshot.group = cinder.group_get(request,
|
||||
vg_snapshot.group_id)
|
||||
except Exception:
|
||||
exceptions.handle(request, _("Unable to retrieve group"))
|
||||
vg_snapshot._group = None
|
||||
vg_snapshot.group = None
|
||||
return vg_snapshot
|
||||
|
||||
|
||||
class GroupNameColumn(tables.WrappingColumn):
|
||||
def get_raw_data(self, snapshot):
|
||||
group = snapshot._group
|
||||
group = snapshot.group
|
||||
return group.name_or_id if group else _("-")
|
||||
|
||||
def get_link_url(self, snapshot):
|
||||
group = snapshot._group
|
||||
group = snapshot.group
|
||||
if group:
|
||||
return reverse(self.link, args=(group.id,))
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ class IndexView(tables.DataTableView):
|
|||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve volume groups."))
|
||||
for gs in vg_snapshots:
|
||||
gs._group = groups.get(gs.group_id)
|
||||
gs.group = groups.get(gs.group_id)
|
||||
return vg_snapshots
|
||||
|
||||
|
||||
|
|
|
@ -119,7 +119,9 @@ class DeleteVolume(VolumePolicyTargetMixin, tables.DeleteAction):
|
|||
# Can't delete volume if part of consistency group
|
||||
if getattr(volume, 'consistencygroup_id', None):
|
||||
return False
|
||||
|
||||
# Can't delete volume if part of volume group
|
||||
if volume.group:
|
||||
return False
|
||||
return (volume.status in DELETABLE_STATES and
|
||||
not getattr(volume, 'has_snapshot', False))
|
||||
return True
|
||||
|
@ -339,6 +341,14 @@ class UpdateRow(tables.Row):
|
|||
|
||||
def get_data(self, request, volume_id):
|
||||
volume = cinder.volume_get(request, volume_id)
|
||||
if volume and getattr(volume, 'group_id', None):
|
||||
try:
|
||||
volume.group = cinder.group_get(request, volume.group_id)
|
||||
except Exception:
|
||||
exceptions.handle(request, _("Unable to retrieve group."))
|
||||
volume.group = None
|
||||
else:
|
||||
volume.group = None
|
||||
return volume
|
||||
|
||||
|
||||
|
@ -393,6 +403,17 @@ class AttachmentColumn(tables.WrappingColumn):
|
|||
return safestring.mark_safe(", ".join(attachments))
|
||||
|
||||
|
||||
class GroupNameColumn(tables.WrappingColumn):
|
||||
def get_raw_data(self, volume):
|
||||
group = volume.group
|
||||
return group.name_or_id if group else _("-")
|
||||
|
||||
def get_link_url(self, volume):
|
||||
group = volume.group
|
||||
if group:
|
||||
return reverse(self.link, args=(group.id,))
|
||||
|
||||
|
||||
def get_volume_type(volume):
|
||||
return volume.volume_type if volume.volume_type != "None" else None
|
||||
|
||||
|
@ -500,6 +521,10 @@ class VolumesTable(VolumesTableBase):
|
|||
name = tables.WrappingColumn("name",
|
||||
verbose_name=_("Name"),
|
||||
link="horizon:project:volumes:detail")
|
||||
group = GroupNameColumn(
|
||||
"name",
|
||||
verbose_name=_("Group"),
|
||||
link="horizon:project:volume_groups:detail")
|
||||
volume_type = tables.Column(get_volume_type,
|
||||
verbose_name=_("Type"))
|
||||
attachments = AttachmentColumn("attachments",
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
|
||||
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
|
||||
|
||||
|
||||
|
@ -25,8 +27,10 @@ class OverviewTab(tabs.Tab):
|
|||
template_name = ("project/volumes/_detail_overview.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
volume = self.tab_group.kwargs['volume']
|
||||
return {
|
||||
'volume': self.tab_group.kwargs['volume'],
|
||||
'volume': volume,
|
||||
'group': volume.group,
|
||||
'detail_url': {
|
||||
'instance': 'horizon:project:instances:detail',
|
||||
'image': 'horizon:project:images:images:detail',
|
||||
|
@ -47,9 +51,28 @@ class SnapshotTab(tabs.TableTab):
|
|||
snapshots = self.tab_group.kwargs['snapshots']
|
||||
volume = self.tab_group.kwargs['volume']
|
||||
|
||||
if volume is not None:
|
||||
for snapshot in snapshots:
|
||||
snapshot._volume = volume
|
||||
if volume is None:
|
||||
return snapshots
|
||||
|
||||
needs_gs = any(getattr(snapshot, 'group_snapshot_id', None)
|
||||
for snapshot in snapshots)
|
||||
if needs_gs:
|
||||
try:
|
||||
group_snapshots_list = cinder.group_snapshot_list(self.request)
|
||||
group_snapshots = dict((gs.id, gs) for gs
|
||||
in group_snapshots_list)
|
||||
except Exception:
|
||||
group_snapshots = {}
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve group snapshots."))
|
||||
|
||||
for snapshot in snapshots:
|
||||
snapshot._volume = volume
|
||||
if needs_gs:
|
||||
gs_id = snapshot.group_snapshot_id
|
||||
snapshot.group_snapshot = group_snapshots.get(gs_id)
|
||||
else:
|
||||
snapshot.group_snapshot = None
|
||||
|
||||
return snapshots
|
||||
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
{% endif %}
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ volume.status_label|capfirst }}</dd>
|
||||
<dt>{% trans "Group" %}</dt>
|
||||
{% if group %}
|
||||
<dd><a href="{% url 'horizon:project:volume_groups:detail' volume.group_id %}">{{ group.name_or_id }}</a></dd>
|
||||
{% else %}
|
||||
<dd>{% trans "-" %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
|
||||
<h4>{% trans "Specs" %}</h4>
|
||||
|
|
|
@ -44,9 +44,10 @@ class VolumeIndexViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
|||
'volume_backup_supported',
|
||||
'volume_snapshot_list',
|
||||
'volume_list_paged',
|
||||
'tenant_absolute_limits'],
|
||||
'tenant_absolute_limits',
|
||||
'group_list'],
|
||||
})
|
||||
def _test_index(self, with_attachments):
|
||||
def _test_index(self, with_attachments=False, with_groups=False):
|
||||
vol_snaps = self.cinder_volume_snapshots.list()
|
||||
volumes = self.cinder_volumes.list()
|
||||
if with_attachments:
|
||||
|
@ -56,6 +57,10 @@ class VolumeIndexViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
|||
volume.attachments = []
|
||||
|
||||
self.mock_volume_backup_supported.return_value = False
|
||||
if with_groups:
|
||||
self.mock_group_list.return_value = self.cinder_groups.list()
|
||||
volumes = self.cinder_group_volumes.list()
|
||||
|
||||
self.mock_volume_list_paged.return_value = [volumes, False, False]
|
||||
if with_attachments:
|
||||
self.mock_server_get.return_value = server
|
||||
|
@ -73,6 +78,9 @@ class VolumeIndexViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
|||
search_opts=None)
|
||||
self.mock_volume_snapshot_list.assert_called_once()
|
||||
|
||||
if with_groups:
|
||||
self.mock_group_list.assert_called_once_with(test.IsHttpRequest())
|
||||
|
||||
self.mock_volume_backup_supported.assert_called_with(
|
||||
test.IsHttpRequest())
|
||||
self.mock_volume_list_paged.assert_called_once_with(
|
||||
|
@ -89,6 +97,9 @@ class VolumeIndexViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
|||
def test_index_no_volume_attachments(self):
|
||||
self._test_index(False)
|
||||
|
||||
def test_index_with_volume_groups(self):
|
||||
self._test_index(with_groups=True)
|
||||
|
||||
@test.create_mocks({
|
||||
api.nova: ['server_get', 'server_list'],
|
||||
cinder: ['tenant_absolute_limits',
|
||||
|
|
|
@ -109,6 +109,24 @@ class VolumeTableMixIn(object):
|
|||
attached_instance_ids.append(server_id)
|
||||
return attached_instance_ids
|
||||
|
||||
def _get_groups(self, volumes):
|
||||
needs_group = False
|
||||
if volumes and hasattr(volumes[0], 'group_id'):
|
||||
needs_group = True
|
||||
if needs_group:
|
||||
try:
|
||||
groups_list = cinder.group_list(self.request)
|
||||
groups = dict((g.id, g) for g in groups_list)
|
||||
except Exception:
|
||||
groups = {}
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve volume groups"))
|
||||
for volume in volumes:
|
||||
if needs_group:
|
||||
volume.group = groups.get(volume.group_id)
|
||||
else:
|
||||
volume.group = None
|
||||
|
||||
# set attachment string and if volume has snapshots
|
||||
def _set_volume_attributes(self,
|
||||
volumes,
|
||||
|
@ -137,6 +155,7 @@ class VolumesView(tables.PagedTableMixin, VolumeTableMixIn,
|
|||
volume_ids_with_snapshots = self._get_volumes_ids_with_snapshots()
|
||||
self._set_volume_attributes(
|
||||
volumes, instances, volume_ids_with_snapshots)
|
||||
self._get_groups(volumes)
|
||||
return volumes
|
||||
|
||||
|
||||
|
@ -172,6 +191,10 @@ class DetailView(tabs.TabbedTableView):
|
|||
for att in volume.attachments:
|
||||
att['instance'] = nova.server_get(self.request,
|
||||
att['server_id'])
|
||||
if getattr(volume, 'group_id', None):
|
||||
volume.group = cinder.group_get(self.request, volume.group_id)
|
||||
else:
|
||||
volume.group = None
|
||||
except Exception:
|
||||
redirect = self.get_redirect_url()
|
||||
exceptions.handle(self.request,
|
||||
|
|
|
@ -62,6 +62,7 @@ def data(TEST):
|
|||
TEST.cinder_group_types = utils.TestDataContainer()
|
||||
TEST.cinder_group_snapshots = utils.TestDataContainer()
|
||||
TEST.cinder_group_volumes = utils.TestDataContainer()
|
||||
TEST.cinder_volume_snapshots_with_groups = utils.TestDataContainer()
|
||||
|
||||
# Services
|
||||
service_1 = services.Service(services.ServiceManager(None), {
|
||||
|
@ -566,3 +567,17 @@ def data(TEST):
|
|||
'attachments': []})
|
||||
TEST.cinder_group_volumes.add(group_volume_1)
|
||||
TEST.cinder_group_volumes.add(group_volume_2)
|
||||
|
||||
snapshot5 = vol_snaps.Snapshot(
|
||||
vol_snaps.SnapshotManager(None),
|
||||
{'id': 'cd6be1eb-82ca-4587-8036-13c37c00c2b1',
|
||||
'name': '',
|
||||
'description': 'v2 volume snapshot with metadata description',
|
||||
'size': 80,
|
||||
'status': 'available',
|
||||
'volume_id': '7e4efa56-9ca1-45ff-b83c-2efb2383930d',
|
||||
'metadata': {'snapshot_meta_key': 'snapshot_meta_value'},
|
||||
'group_snapshot_id': group_snapshot_1.id})
|
||||
|
||||
TEST.cinder_volume_snapshots_with_groups.add(
|
||||
api.cinder.VolumeSnapshot(snapshot5))
|
||||
|
|
|
@ -296,11 +296,15 @@ class CinderApiTests(test.APIMockTestCase):
|
|||
self.assertTrue(more_data)
|
||||
self.assertFalse(prev_data)
|
||||
|
||||
@mock.patch.object(api.cinder, 'cinderclient')
|
||||
def test_volume_snapshot_list(self, mock_cinderclient):
|
||||
@test.create_mocks({
|
||||
api.cinder: [
|
||||
('_cinderclient_with_generic_groups', 'cinderclient_groups'),
|
||||
]
|
||||
})
|
||||
def test_volume_snapshot_list(self):
|
||||
search_opts = {'all_tenants': 1}
|
||||
volume_snapshots = self.cinder_volume_snapshots.list()
|
||||
cinderclient = mock_cinderclient.return_value
|
||||
cinderclient = self.mock_cinderclient_groups.return_value
|
||||
|
||||
snapshots_mock = cinderclient.volume_snapshots.list
|
||||
snapshots_mock.return_value = volume_snapshots
|
||||
|
@ -308,9 +312,12 @@ class CinderApiTests(test.APIMockTestCase):
|
|||
api.cinder.volume_snapshot_list(self.request, search_opts=search_opts)
|
||||
snapshots_mock.assert_called_once_with(search_opts=search_opts)
|
||||
|
||||
@mock.patch.object(api.cinder, 'cinderclient')
|
||||
def test_volume_snapshot_list_no_volume_configured(self,
|
||||
mock_cinderclient):
|
||||
@test.create_mocks({
|
||||
api.cinder: [
|
||||
('_cinderclient_with_generic_groups', 'cinderclient_groups'),
|
||||
]
|
||||
})
|
||||
def test_volume_snapshot_list_no_volume_configured(self):
|
||||
# remove volume from service catalog
|
||||
catalog = self.service_catalog
|
||||
for service in catalog:
|
||||
|
@ -319,7 +326,7 @@ class CinderApiTests(test.APIMockTestCase):
|
|||
search_opts = {'all_tenants': 1}
|
||||
volume_snapshots = self.cinder_volume_snapshots.list()
|
||||
|
||||
cinderclient = mock_cinderclient.return_value
|
||||
cinderclient = self.mock_cinderclient_groups.return_value
|
||||
|
||||
snapshots_mock = cinderclient.volume_snapshots.list
|
||||
snapshots_mock.return_value = volume_snapshots
|
||||
|
|
Loading…
Reference in New Issue