summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2020-09-10 18:04:09 +0000
committerGerrit Code Review <review@openstack.org>2020-09-10 18:04:09 +0000
commit79e505520fc307eeedc1f5c81fb516e9638ebd72 (patch)
tree81c3f8dc3294c9c977dba62d08800af0f5d73628
parent584aa54985e6d0945f8ea08195530cb67e7ff72a (diff)
parent79ff0d45c4f653da35db695b4ae313edb38cc67d (diff)
downloadhorizon-18.5.0.tar.gz
Merge "Add cinder-user-facing messages"18.5.0
-rw-r--r--openstack_dashboard/api/cinder.py4
-rw-r--r--openstack_dashboard/dashboards/admin/snapshots/tabs.py12
-rw-r--r--openstack_dashboard/dashboards/admin/volumes/tabs.py8
-rw-r--r--openstack_dashboard/dashboards/admin/volumes/tests.py9
-rw-r--r--openstack_dashboard/dashboards/project/snapshots/tables.py18
-rw-r--r--openstack_dashboard/dashboards/project/snapshots/tabs.py27
-rw-r--r--openstack_dashboard/dashboards/project/volumes/tables.py18
-rw-r--r--openstack_dashboard/dashboards/project/volumes/tabs.py26
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/_detail_overview.html18
-rw-r--r--openstack_dashboard/dashboards/project/volumes/tests.py20
-rw-r--r--openstack_dashboard/dashboards/project/volumes/views.py12
-rw-r--r--openstack_dashboard/test/test_data/cinder_data.py26
-rw-r--r--openstack_dashboard/test/unit/api/test_cinder.py13
-rw-r--r--releasenotes/notes/cinder-user-facing-messages-92cfd25492616d6d.yaml7
14 files changed, 156 insertions, 62 deletions
diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py
index e09e409da..d1f52f447 100644
--- a/openstack_dashboard/api/cinder.py
+++ b/openstack_dashboard/api/cinder.py
@@ -185,6 +185,10 @@ class VolumePool(base.APIResourceWrapper):
'storage_protocol', 'extra_specs']
+class Message(base.APIResourceWrapper):
+ _attrs = ['id', 'event_id', 'created_at', 'resource_type', 'user_message']
+
+
class Group(base.APIResourceWrapper):
_attrs = ['id', 'status', 'availability_zone', 'created_at', 'name',
'description', 'group_type', 'volume_types',
diff --git a/openstack_dashboard/dashboards/admin/snapshots/tabs.py b/openstack_dashboard/dashboards/admin/snapshots/tabs.py
index 29b35e4f2..bea8398b5 100644
--- a/openstack_dashboard/dashboards/admin/snapshots/tabs.py
+++ b/openstack_dashboard/dashboards/admin/snapshots/tabs.py
@@ -16,10 +16,12 @@ from django.utils.translation import ugettext_lazy as _
from horizon import tabs
from openstack_dashboard.dashboards.project.snapshots \
- import tabs as overview_tab
+ import tables as snap_messages_tables
+from openstack_dashboard.dashboards.project.snapshots \
+ import tabs as project_tab
-class OverviewTab(overview_tab.OverviewTab):
+class OverviewTab(project_tab.OverviewTab):
name = _("Overview")
slug = "overview"
template_name = ("project/snapshots/_detail_overview.html")
@@ -28,6 +30,10 @@ class OverviewTab(overview_tab.OverviewTab):
return reverse('horizon:admin:snapshots:index')
+class SnapshotMessagesTab(project_tab.SnapshotMessagesTab):
+ table_classes = (snap_messages_tables.SnapshotMessagesTable,)
+
+
class SnapshotDetailsTabs(tabs.TabGroup):
slug = "snapshot_details"
- tabs = (OverviewTab,)
+ tabs = (OverviewTab, SnapshotMessagesTab)
diff --git a/openstack_dashboard/dashboards/admin/volumes/tabs.py b/openstack_dashboard/dashboards/admin/volumes/tabs.py
index 7535dbd61..3571475be 100644
--- a/openstack_dashboard/dashboards/admin/volumes/tabs.py
+++ b/openstack_dashboard/dashboards/admin/volumes/tabs.py
@@ -11,6 +11,8 @@
# under the License.
from openstack_dashboard.dashboards.admin.snapshots import tables
+from openstack_dashboard.dashboards.project.volumes \
+ import tables as vol_messages_tables
from openstack_dashboard.dashboards.project.volumes import tabs as project_tabs
@@ -34,5 +36,9 @@ class SnapshotTab(project_tabs.SnapshotTab):
table_classes = (tables.VolumeDetailsSnapshotsTable,)
+class VolumeMessagesTab(project_tabs.VolumeMessagesTab):
+ table_classes = (vol_messages_tables.VolumeMessagesTable,)
+
+
class VolumeDetailTabs(project_tabs.VolumeDetailTabs):
- tabs = (OverviewTab, SnapshotTab)
+ tabs = (OverviewTab, SnapshotTab, VolumeMessagesTab)
diff --git a/openstack_dashboard/dashboards/admin/volumes/tests.py b/openstack_dashboard/dashboards/admin/volumes/tests.py
index f7bf53f6c..a633c8e2a 100644
--- a/openstack_dashboard/dashboards/admin/volumes/tests.py
+++ b/openstack_dashboard/dashboards/admin/volumes/tests.py
@@ -380,7 +380,7 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({
api.nova: ['server_get'],
api.cinder: ['tenant_absolute_limits', 'volume_get',
- 'volume_snapshot_list', 'message_list']})
+ 'volume_snapshot_list']})
def test_detail_view_snapshot_tab(self):
volume = self.cinder_volumes.first()
server = self.servers.first()
@@ -394,7 +394,6 @@ class VolumeTests(test.BaseAdminViewTests):
self.mock_tenant_absolute_limits.return_value = volume_limits
self.mock_volume_get.return_value = volume
self.mock_volume_snapshot_list.return_value = this_volume_snapshots
- self.mock_message_list.return_value = []
url = (reverse(DETAIL_URL, args=[volume.id]) + '?' +
'='.join(['tab', 'volume_details__snapshots_tab']))
@@ -414,9 +413,3 @@ class VolumeTests(test.BaseAdminViewTests):
self.mock_volume_snapshot_list.assert_called_once_with(
test.IsHttpRequest(),
search_opts={'volume_id': volume.id, 'all_tenants': True})
- self.mock_message_list.assert_called_once_with(
- test.IsHttpRequest(),
- {
- 'resource_uuid': volume.id,
- 'resource_type': 'volume'
- })
diff --git a/openstack_dashboard/dashboards/project/snapshots/tables.py b/openstack_dashboard/dashboards/project/snapshots/tables.py
index 5db1b52b6..c43c7a740 100644
--- a/openstack_dashboard/dashboards/project/snapshots/tables.py
+++ b/openstack_dashboard/dashboards/project/snapshots/tables.py
@@ -263,3 +263,21 @@ class VolumeSnapshotsTable(VolumeDetailsSnapshotsTable):
class Meta(VolumeDetailsSnapshotsTable.Meta):
pass
+
+
+class SnapshotMessagesTable(tables.DataTable):
+ message_id = tables.Column("id", verbose_name=_("ID"))
+ message_level = tables.Column("message_level",
+ verbose_name=_("Message Level"))
+ event_id = tables.Column("event_id",
+ verbose_name=_("Event Id"))
+ user_message = tables.Column("user_message",
+ verbose_name=_("User Message"))
+ created_at = tables.Column("created_at",
+ verbose_name=_("Created At"))
+ guaranteed_until = tables.Column("guaranteed_until",
+ verbose_name=_("Guaranteed Until"))
+
+ class Meta(object):
+ name = "snapshot_messages"
+ verbose_name = _("Messages")
diff --git a/openstack_dashboard/dashboards/project/snapshots/tabs.py b/openstack_dashboard/dashboards/project/snapshots/tabs.py
index 548fd4044..2c29e99cc 100644
--- a/openstack_dashboard/dashboards/project/snapshots/tabs.py
+++ b/openstack_dashboard/dashboards/project/snapshots/tabs.py
@@ -19,6 +19,8 @@ from horizon import exceptions
from horizon import tabs
from openstack_dashboard.api import cinder
+from openstack_dashboard.dashboards.project.snapshots \
+ import tables as snap_messages_tables
class OverviewTab(tabs.Tab):
@@ -43,6 +45,29 @@ class OverviewTab(tabs.Tab):
return reverse('horizon:project:snapshots:index')
+class SnapshotMessagesTab(tabs.TableTab):
+ table_classes = (snap_messages_tables.SnapshotMessagesTable,)
+ name = _("Messages")
+ slug = "messages_tab"
+ template_name = ("horizon/common/_detail_table.html")
+ preload = False
+
+ def get_snapshot_messages_data(self):
+ messages = []
+ snapshot = self.tab_group.kwargs['snapshot']
+ snap_id = snapshot.id
+ try:
+ snap_msgs = cinder.message_list(self.request, search_opts={
+ 'resource_type': 'volume_snapshot', 'resource_uuid': snap_id})
+ for snap_msg in snap_msgs:
+ messages.append(snap_msg)
+
+ except Exception:
+ exceptions.handle(self.request, _("Unable to retrieve "
+ "snapshot messages."))
+ return messages
+
+
class SnapshotDetailTabs(tabs.TabGroup):
slug = "snapshot_details"
- tabs = (OverviewTab,)
+ tabs = (OverviewTab, SnapshotMessagesTab)
diff --git a/openstack_dashboard/dashboards/project/volumes/tables.py b/openstack_dashboard/dashboards/project/volumes/tables.py
index 7f3a60371..8a7b9c87d 100644
--- a/openstack_dashboard/dashboards/project/volumes/tables.py
+++ b/openstack_dashboard/dashboards/project/volumes/tables.py
@@ -656,3 +656,21 @@ class AttachmentsTable(tables.DataTable):
verbose_name = _("Attachments")
table_actions = (DetachVolume,)
row_actions = (DetachVolume,)
+
+
+class VolumeMessagesTable(tables.DataTable):
+ message_id = tables.Column("id", verbose_name=_("ID"))
+ message_level = tables.Column("message_level",
+ verbose_name=_("Message Level"))
+ event_id = tables.Column("event_id",
+ verbose_name=_("Event Id"))
+ user_message = tables.Column("user_message",
+ verbose_name=_("User Message"))
+ created_at = tables.Column("created_at",
+ verbose_name=_("Created At"))
+ guaranteed_until = tables.Column("guaranteed_until",
+ verbose_name=_("Guaranteed Until"))
+
+ class Meta(object):
+ name = "volume_messages"
+ verbose_name = _("Messages")
diff --git a/openstack_dashboard/dashboards/project/volumes/tabs.py b/openstack_dashboard/dashboards/project/volumes/tabs.py
index 22322e520..13f703149 100644
--- a/openstack_dashboard/dashboards/project/volumes/tabs.py
+++ b/openstack_dashboard/dashboards/project/volumes/tabs.py
@@ -19,6 +19,8 @@ from horizon import tabs
from openstack_dashboard.api import cinder
from openstack_dashboard.dashboards.project.snapshots import tables
+from openstack_dashboard.dashboards.project.volumes \
+ import tables as vol_messages_tables
class OverviewTab(tabs.Tab):
@@ -77,6 +79,28 @@ class SnapshotTab(tabs.TableTab):
return snapshots
+class VolumeMessagesTab(tabs.TableTab):
+ table_classes = (vol_messages_tables.VolumeMessagesTable,)
+ name = _("Messages")
+ slug = "messages_tab"
+ template_name = ("horizon/common/_detail_table.html")
+ preload = False
+
+ def get_volume_messages_data(self):
+ messages = []
+ volume = self.tab_group.kwargs['volume'].id
+ try:
+ vol_msgs = cinder.message_list(self.request, search_opts={
+ 'resource_type': 'volume', 'resource_uuid': volume})
+ for vol_msg in vol_msgs:
+ messages.append(vol_msg)
+
+ except Exception:
+ exceptions.handle(self.request, _("Unable to retrieve "
+ "volume messages."))
+ return messages
+
+
class VolumeDetailTabs(tabs.DetailTabsGroup):
slug = "volume_details"
- tabs = (OverviewTab, SnapshotTab)
+ tabs = (OverviewTab, SnapshotTab, VolumeMessagesTab)
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_detail_overview.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_detail_overview.html
index 96e9e638e..e3d820411 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_detail_overview.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_detail_overview.html
@@ -105,22 +105,4 @@
<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>
diff --git a/openstack_dashboard/dashboards/project/volumes/tests.py b/openstack_dashboard/dashboards/project/volumes/tests.py
index 6d3e158a4..65b0ba0aa 100644
--- a/openstack_dashboard/dashboards/project/volumes/tests.py
+++ b/openstack_dashboard/dashboards/project/volumes/tests.py
@@ -1404,8 +1404,7 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
@test.create_mocks({
api.nova: ['server_get'],
- cinder: ['message_list',
- 'volume_snapshot_list',
+ cinder: ['volume_snapshot_list',
'volume_get',
'tenant_absolute_limits'],
})
@@ -1422,7 +1421,6 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.mock_server_get.return_value = server
self.mock_tenant_absolute_limits.return_value = \
self.cinder_limits['absolute']
- self.mock_message_list.return_value = []
url = reverse('horizon:project:volumes:detail',
args=[volume.id])
@@ -1438,12 +1436,6 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.mock_server_get.assert_called_once_with(test.IsHttpRequest(),
server.id)
self.mock_tenant_absolute_limits.assert_called_once()
- self.mock_message_list.assert_called_once_with(
- test.IsHttpRequest(),
- {
- 'resource_uuid': '11023e92-8008-4c8b-8059-7f2293ff3887',
- 'resource_type': 'volume',
- })
@mock.patch.object(cinder, 'volume_get_encryption_metadata')
@mock.patch.object(cinder, 'volume_get')
@@ -1530,8 +1522,7 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
api.nova: ['server_get'],
cinder: ['tenant_absolute_limits',
'volume_get',
- 'volume_snapshot_list',
- 'message_list'],
+ 'volume_snapshot_list'],
})
def test_detail_view_snapshot_tab(self):
volume = self.cinder_volumes.first()
@@ -1546,7 +1537,6 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.mock_server_get.return_value = server
self.mock_tenant_absolute_limits.return_value = \
self.cinder_limits['absolute']
- self.mock_message_list.return_value = []
self.mock_volume_snapshot_list.return_value = this_volume_snapshots
url = '?'.join([reverse(DETAIL_URL, args=[volume.id]),
@@ -1564,12 +1554,6 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
self.mock_volume_snapshot_list.assert_called_once_with(
test.IsHttpRequest(), search_opts={'volume_id': volume.id})
self.mock_tenant_absolute_limits.assert_called_once()
- self.mock_message_list.assert_called_once_with(
- test.IsHttpRequest(),
- {
- 'resource_uuid': volume.id,
- 'resource_type': 'volume'
- })
@mock.patch.object(cinder, 'volume_get')
def test_detail_view_with_exception(self, mock_get):
diff --git a/openstack_dashboard/dashboards/project/volumes/views.py b/openstack_dashboard/dashboards/project/volumes/views.py
index 496cc8b34..76d93c5f3 100644
--- a/openstack_dashboard/dashboards/project/volumes/views.py
+++ b/openstack_dashboard/dashboards/project/volumes/views.py
@@ -223,18 +223,6 @@ class DetailView(tabs.TabbedTableView):
exceptions.handle(self.request,
_('Unable to retrieve volume details.'),
redirect=redirect)
- try:
- volume.messages = cinder.message_list(
- self.request,
- {'resource_type': 'volume', 'resource_uuid': volume.id},
- )
- except Exception:
- volume.messages = []
- exceptions.handle(
- self.request,
- _('Unable to retrieve volume messages.'),
- ignore=True,
- )
return volume, snapshots
def get_redirect_url(self):
diff --git a/openstack_dashboard/test/test_data/cinder_data.py b/openstack_dashboard/test/test_data/cinder_data.py
index 2dc59a39a..7f67a160f 100644
--- a/openstack_dashboard/test/test_data/cinder_data.py
+++ b/openstack_dashboard/test/test_data/cinder_data.py
@@ -28,6 +28,7 @@ from cinderclient.v2 import volumes
from cinderclient.v3 import group_snapshots
from cinderclient.v3 import group_types
from cinderclient.v3 import groups
+from cinderclient.v3 import messages
from openstack_dashboard import api
from openstack_dashboard.api import cinder as cinder_api
@@ -36,6 +37,7 @@ from openstack_dashboard.usage import quotas as usage_quotas
def data(TEST):
+ TEST.cinder_messages = utils.TestDataContainer()
TEST.cinder_services = utils.TestDataContainer()
TEST.cinder_volumes = utils.TestDataContainer()
TEST.cinder_volume_backups = utils.TestDataContainer()
@@ -547,3 +549,27 @@ def data(TEST):
TEST.cinder_volume_snapshots_with_groups.add(
api.cinder.VolumeSnapshot(snapshot5))
+
+ # Cinder Messages
+ messages_1 = messages.Message(
+ messages.MessageManager(None),
+ {'created_at': '2020-07-08T17:12:06.000000',
+ 'event_id': 'VOLUME_VOLUME_001_001',
+ 'guaranteed_until': '2020-08-07T17:12:06.000000',
+ 'id': '2d2bb0d7-af28-4566-9a65-6d987c19093c',
+ 'resource_type': 'VOLUME',
+ 'resource_uuid': '6d53d143-e10f-440a-a65f-16a6b6d068f7',
+ 'user_message': 'schedule allocate volume:An unknown error occurred.'
+ })
+
+ messages_2 = messages.Message(
+ messages.MessageManager(None),
+ {'created_at': '2020-07-12T12:56:43.000000',
+ 'event_id': 'VOLUME_VOLUME_SNAPSHOT_009_015',
+ 'guaranteed_until': '2020-08-11T12:56:43.000000',
+ 'id': 'd360b4e2-bda5-4289-b673-714a90cde80b',
+ 'resource_type': 'VOLUME_SNAPSHOT',
+ 'resource_uuid': '761634b0-fa1c-4e59-b8ad-d720807cb355',
+ 'user_message': 'create snapshot:Snapshot is busy.'})
+ TEST.cinder_messages.add(api.cinder.Message(messages_1))
+ TEST.cinder_messages.add(api.cinder.Message(messages_2))
diff --git a/openstack_dashboard/test/unit/api/test_cinder.py b/openstack_dashboard/test/unit/api/test_cinder.py
index 769f29bed..026b7a627 100644
--- a/openstack_dashboard/test/unit/api/test_cinder.py
+++ b/openstack_dashboard/test/unit/api/test_cinder.py
@@ -447,6 +447,19 @@ class CinderApiTests(test.APIMockTestCase):
self.assertEqual(default_volume_type, volume_type)
cinderclient.volume_types.default.assert_called_once()
+ @test.create_mocks({
+ api.cinder: [('_cinderclient_with_features', 'cinderclient'), ]})
+ def test_cinder_message_list(self):
+ search_opts = {'resource_type': 'VOLUME',
+ 'resource_uuid': '6d53d143-e10f-440a-a65f-16a6b6d068f7'}
+ messages = self.cinder_messages.list()
+ cinderclient = self.mock_cinderclient.return_value
+ messages_mock = cinderclient.messages.list
+ messages_mock.return_value = messages
+
+ api.cinder.message_list(self.request, search_opts=search_opts)
+ messages_mock.assert_called_once_with(search_opts)
+
class CinderApiVersionTests(test.TestCase):
diff --git a/releasenotes/notes/cinder-user-facing-messages-92cfd25492616d6d.yaml b/releasenotes/notes/cinder-user-facing-messages-92cfd25492616d6d.yaml
new file mode 100644
index 000000000..4d51056e1
--- /dev/null
+++ b/releasenotes/notes/cinder-user-facing-messages-92cfd25492616d6d.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ [`cinder-user-facing messages <https://blueprints.launchpad.net/horizon/+spec/cinder-user-facing-messages>`_]
+ This bp add a new tab "Messages" in volume/snapshot detail pages where User can see failure summary messages
+ for corresponding volume and snapshot resources. Before this bp it only shows user messages and message-level
+ info. for a specific volume in the detail page but now more parameters will be displayed for that volume.