Merge "Add Group and Group Snapshot colunm"
This commit is contained in:
commit
4c82dda11c
|
@ -63,6 +63,10 @@ class VolumeSnapshotsTable(volumes_tables.VolumesTableBase):
|
||||||
link="horizon:admin:volumes:detail")
|
link="horizon:admin:volumes:detail")
|
||||||
host = tables.Column("host_name", verbose_name=_("Host"))
|
host = tables.Column("host_name", verbose_name=_("Host"))
|
||||||
tenant = tables.Column("tenant_name", verbose_name=_("Project"))
|
tenant = tables.Column("tenant_name", verbose_name=_("Project"))
|
||||||
|
group_snapshot = snapshots_tables.GroupSnapshotNameColumn(
|
||||||
|
"name",
|
||||||
|
verbose_name=_("Group Snapshot"),
|
||||||
|
link="horizon:admin:vg_snapshots:detail")
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = "volume_snapshots"
|
name = "volume_snapshots"
|
||||||
|
@ -77,7 +81,7 @@ class VolumeSnapshotsTable(volumes_tables.VolumesTableBase):
|
||||||
row_class = UpdateRow
|
row_class = UpdateRow
|
||||||
status_columns = ("status",)
|
status_columns = ("status",)
|
||||||
columns = ('tenant', 'host', 'name', 'description', 'size', 'status',
|
columns = ('tenant', 'host', 'name', 'description', 'size', 'status',
|
||||||
'volume_name',)
|
'group_snapshot', 'volume_name',)
|
||||||
|
|
||||||
|
|
||||||
class VolumeDetailsSnapshotsTable(VolumeSnapshotsTable):
|
class VolumeDetailsSnapshotsTable(VolumeSnapshotsTable):
|
||||||
|
|
|
@ -37,6 +37,7 @@ class SnapshotsView(tables.PagedTableMixin, tables.DataTableView):
|
||||||
page_title = _("Volume Snapshots")
|
page_title = _("Volume Snapshots")
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
|
needs_gs = False
|
||||||
if cinder.is_volume_service_enabled(self.request):
|
if cinder.is_volume_service_enabled(self.request):
|
||||||
try:
|
try:
|
||||||
marker, sort_dir = self._get_marker()
|
marker, sort_dir = self._get_marker()
|
||||||
|
@ -54,6 +55,18 @@ class SnapshotsView(tables.PagedTableMixin, tables.DataTableView):
|
||||||
exceptions.handle(self.request, _("Unable to retrieve "
|
exceptions.handle(self.request, _("Unable to retrieve "
|
||||||
"volume snapshots."))
|
"volume snapshots."))
|
||||||
|
|
||||||
|
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, search_opts={'all_tenants': True})
|
||||||
|
group_snapshots = dict((gs.id, gs) for gs
|
||||||
|
in group_snapshots)
|
||||||
|
except Exception:
|
||||||
|
group_snapshots = {}
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_("Unable to retrieve group snapshots."))
|
||||||
# Gather our tenants to correlate against volume IDs
|
# Gather our tenants to correlate against volume IDs
|
||||||
try:
|
try:
|
||||||
tenants, has_more = keystone.tenant_list(self.request)
|
tenants, has_more = keystone.tenant_list(self.request)
|
||||||
|
@ -66,6 +79,12 @@ class SnapshotsView(tables.PagedTableMixin, tables.DataTableView):
|
||||||
tenant_dict = dict((t.id, t) for t in tenants)
|
tenant_dict = dict((t.id, t) for t in tenants)
|
||||||
for snapshot in snapshots:
|
for snapshot in snapshots:
|
||||||
volume = volumes.get(snapshot.volume_id)
|
volume = volumes.get(snapshot.volume_id)
|
||||||
|
if needs_gs:
|
||||||
|
group_snapshot = group_snapshots.get(
|
||||||
|
snapshot.group_snapshot_id)
|
||||||
|
snapshot.group_snapshot = group_snapshot
|
||||||
|
else:
|
||||||
|
snapshot.group_snapshot = None
|
||||||
tenant_id = snapshot.project_id
|
tenant_id = snapshot.project_id
|
||||||
tenant = tenant_dict.get(tenant_id, None)
|
tenant = tenant_dict.get(tenant_id, None)
|
||||||
snapshot._volume = volume
|
snapshot._volume = volume
|
||||||
|
|
|
@ -105,6 +105,10 @@ class VolumesTable(volumes_tables.VolumesTable):
|
||||||
host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host"))
|
host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host"))
|
||||||
tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', None),
|
tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', None),
|
||||||
verbose_name=_("Project"))
|
verbose_name=_("Project"))
|
||||||
|
group = volumes_tables.GroupNameColumn(
|
||||||
|
"name",
|
||||||
|
verbose_name=_("Group"),
|
||||||
|
link="horizon:admin:volume_groups:detail")
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = "volumes"
|
name = "volumes"
|
||||||
|
@ -119,5 +123,5 @@ class VolumesTable(volumes_tables.VolumesTable):
|
||||||
UnmanageVolumeAction,
|
UnmanageVolumeAction,
|
||||||
MigrateVolume,
|
MigrateVolume,
|
||||||
volumes_tables.UpdateMetadata)
|
volumes_tables.UpdateMetadata)
|
||||||
columns = ('tenant', 'host', 'name', 'size', 'status', 'volume_type',
|
columns = ('tenant', 'host', 'name', 'size', 'status', 'group',
|
||||||
'attachments', 'bootable', 'encryption',)
|
'volume_type', 'attachments', 'bootable', 'encryption',)
|
||||||
|
|
|
@ -15,10 +15,13 @@ from openstack_dashboard.dashboards.project.volumes import tabs as project_tabs
|
||||||
|
|
||||||
|
|
||||||
class OverviewTab(project_tabs.OverviewTab):
|
class OverviewTab(project_tabs.OverviewTab):
|
||||||
|
template_name = ("admin/volumes/_detail_overview.html")
|
||||||
|
|
||||||
def get_context_data(self, request):
|
def get_context_data(self, request):
|
||||||
|
volume = self.tab_group.kwargs['volume']
|
||||||
return {
|
return {
|
||||||
'volume': self.tab_group.kwargs['volume'],
|
'volume': volume,
|
||||||
|
'group': volume.group,
|
||||||
'detail_url': {
|
'detail_url': {
|
||||||
'instance': 'horizon:admin:instances:detail',
|
'instance': 'horizon:admin:instances:detail',
|
||||||
'image': 'horizon:admin:images:detail',
|
'image': 'horizon:admin:images:detail',
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
{% load i18n sizeformat parse_date %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd data-display="{{ volume.name|default:volume.id }}" class="word-wrap">{{ volume.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ volume.id }}</dd>
|
||||||
|
{% if volume.description %}
|
||||||
|
<dt>{% trans "Description" %}</dt>
|
||||||
|
<dd>{{ volume.description }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Project ID" %}</dt>
|
||||||
|
<dd>{{ volume.tenant_id|default:_("-") }}</dd>
|
||||||
|
<dt>{% trans "Status" %}</dt>
|
||||||
|
<dd>{{ volume.status_label|capfirst }}</dd>
|
||||||
|
<dt>{% trans "Group" %}</dt>
|
||||||
|
{% if group %}
|
||||||
|
<dd><a href="{% url 'horizon:admin:volume_groups:detail' volume.group_id %}">{{ group.name_or_id }}</a></dd>
|
||||||
|
{% else %}
|
||||||
|
<dd>{% trans "-" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h4>{% trans "Specs" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Size" %}</dt>
|
||||||
|
<dd>{{ volume.size }} {% trans "GiB" %}</dd>
|
||||||
|
{% if volume.volume_type %}
|
||||||
|
<dt>{% trans "Type" %}</dt>
|
||||||
|
<dd>{{ volume.volume_type }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if volume.availabilty_zone %}
|
||||||
|
<dt>{% trans "Availability zone" %}</dt>
|
||||||
|
<dd>{{ volume.availability_zone }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Bootable" %}</dt>
|
||||||
|
<dd>{{ volume.is_bootable|yesno|capfirst }}</dd>
|
||||||
|
<dt>{% trans "Encrypted" %}</dt>
|
||||||
|
{% if volume.encrypted %}
|
||||||
|
<dd><a href="{% url detail_url.encryption volume.id %}">{% trans "Yes" %}</a></dd>
|
||||||
|
{% else %}
|
||||||
|
<dd>{% trans "No" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Created" context "Created time" %}</dt>
|
||||||
|
<dd>{{ volume.created_at|parse_date }}</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h4>{% trans "Attachments" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
{% for attachment in volume.attachments %}
|
||||||
|
<dt>{% trans "Attached To" %}</dt>
|
||||||
|
<dd class="word-wrap">
|
||||||
|
{% url detail_url.instance attachment.server_id as instance_url %}
|
||||||
|
{% blocktrans trimmed with instance_name=attachment.instance.name device=attachment.device %}
|
||||||
|
<a href="{{ instance_url }}">{{ instance_name }}</a> on {{ device }}
|
||||||
|
{% endblocktrans %}
|
||||||
|
</dd>
|
||||||
|
{% empty %}
|
||||||
|
<dt>{% trans "Attached To" %}</dt>
|
||||||
|
<dd><em>{% trans "Not attached" %}</em></dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
{% if volume.volume_image_metadata %}
|
||||||
|
<h4>{% trans "Volume Source" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Image" %}</dt>
|
||||||
|
<dd class="word-wrap">
|
||||||
|
{% url detail_url.image volume.volume_image_metadata.image_id as image_url %}
|
||||||
|
<a href="{{ image_url }}">{{ volume.volume_image_metadata.image_name }}</a>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h4>{% trans "Metadata" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
{% if volume.metadata.items %}
|
||||||
|
{% for key, value in volume.metadata.items %}
|
||||||
|
<dt>{{ key }}</dt>
|
||||||
|
<dd>{{ value }}</dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<dd>{% trans "None" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
{% if volume.transfer %}
|
||||||
|
<h4>{% trans "Volume Transfer" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ volume.transfer.id }}</dd>
|
||||||
|
</dl>
|
||||||
|
<dl>
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd class="word-wrap">{{ volume.transfer.name }}</dd>
|
||||||
|
</dl>
|
||||||
|
<dl>
|
||||||
|
<dt>{% trans "Created" context "Created time" %}</dt>
|
||||||
|
<dd>{{ volume.transfer.created_at|parse_date }}</dd>
|
||||||
|
</dl>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if volume.messages %}
|
||||||
|
<h4>{% trans "Messages" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<div>
|
||||||
|
{% for m in volume.messages %}
|
||||||
|
<div class="alert
|
||||||
|
{% if m.message_level == 'ERROR' %}alert-danger
|
||||||
|
{% elif m.message_level == 'WARNING' %}alert-warning
|
||||||
|
{% elif m.message_level == 'INFO' %}alert-info
|
||||||
|
{% else %}alert-success
|
||||||
|
{% endif %}
|
||||||
|
">
|
||||||
|
{{ m.user_message }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
|
@ -100,6 +100,8 @@ class VolumesView(tables.PagedTableMixin, volumes_views.VolumeTableMixIn,
|
||||||
|
|
||||||
def _task_get_volumes():
|
def _task_get_volumes():
|
||||||
volumes.extend(self._get_volumes(search_opts=filters))
|
volumes.extend(self._get_volumes(search_opts=filters))
|
||||||
|
# update group name for volumes
|
||||||
|
self._get_groups(volumes, search_opts={'all_tenants': True})
|
||||||
attached_instance_ids.extend(
|
attached_instance_ids.extend(
|
||||||
self._get_attached_instance_ids(volumes))
|
self._get_attached_instance_ids(volumes))
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,8 @@ class VolumeIndexViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
|
||||||
self.mock_volume_snapshot_list.assert_called_once()
|
self.mock_volume_snapshot_list.assert_called_once()
|
||||||
|
|
||||||
if with_groups:
|
if with_groups:
|
||||||
self.mock_group_list.assert_called_once_with(test.IsHttpRequest())
|
self.mock_group_list.assert_called_once_with(test.IsHttpRequest(),
|
||||||
|
search_opts=None)
|
||||||
|
|
||||||
self.mock_volume_backup_supported.assert_called_with(
|
self.mock_volume_backup_supported.assert_called_with(
|
||||||
test.IsHttpRequest())
|
test.IsHttpRequest())
|
||||||
|
|
|
@ -104,13 +104,14 @@ class VolumeTableMixIn(object):
|
||||||
attached_instance_ids.append(server_id)
|
attached_instance_ids.append(server_id)
|
||||||
return attached_instance_ids
|
return attached_instance_ids
|
||||||
|
|
||||||
def _get_groups(self, volumes):
|
def _get_groups(self, volumes, search_opts=None):
|
||||||
needs_group = False
|
needs_group = False
|
||||||
if volumes and hasattr(volumes[0], 'group_id'):
|
if volumes and hasattr(volumes[0], 'group_id'):
|
||||||
needs_group = True
|
needs_group = True
|
||||||
if needs_group:
|
if needs_group:
|
||||||
try:
|
try:
|
||||||
groups_list = cinder.group_list(self.request)
|
groups_list = cinder.group_list(self.request,
|
||||||
|
search_opts=search_opts)
|
||||||
groups = dict((g.id, g) for g in groups_list)
|
groups = dict((g.id, g) for g in groups_list)
|
||||||
except Exception:
|
except Exception:
|
||||||
groups = {}
|
groups = {}
|
||||||
|
|
Loading…
Reference in New Issue