diff options
author | Jesper Schmitz Mouridsen <jesper@schmitz.computer> | 2022-06-14 21:32:18 +0000 |
---|---|---|
committer | Jesper Schmitz Mouridsen <jesper@schmitz.computer> | 2022-09-06 07:29:40 +0000 |
commit | 20a571fdd299f18c497bbb22ab0af7ead1bc4690 (patch) | |
tree | 8bc0fc4652e8484bbd397c0bc38b63134ab3f55d | |
parent | f044c4b0a30da4b4b5e3df1b7888811efddce447 (diff) | |
download | horizon-20a571fdd299f18c497bbb22ab0af7ead1bc4690.tar.gz |
Add cinder-user-facing messages for Backup
This patch adds a tab for cinder user messages for volume backups.
Cinder user messages show error details for cinder resources like if we
are unable to create a volume backup due to some failure in cinder it
will show us the reason for failure.
It also updates project and admin SnapshotDetailsTabs to use
DetailTabsGroup instead of TabGroup to improve top padding.
Also adds the fail_reason in the detail view, if backup errored.
Related-Bug https://bugs.launchpad.net/cinder/+bug/1978729
Change-Id: I4e639211043270e814fac489f915588af03f966a
11 files changed, 113 insertions, 7 deletions
diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py index 03ac5aee3..89319cd4a 100644 --- a/openstack_dashboard/api/cinder.py +++ b/openstack_dashboard/api/cinder.py @@ -121,7 +121,7 @@ class VolumeBackup(BaseCinderAPIResourceWrapper): _attrs = ['id', 'name', 'description', 'container', 'size', 'status', 'created_at', 'volume_id', 'availability_zone', 'snapshot_id', - 'os-backup-project-attr:project_id'] + 'os-backup-project-attr:project_id', 'fail_reason'] _volume = None _snapshot = None diff --git a/openstack_dashboard/dashboards/admin/backups/tabs.py b/openstack_dashboard/dashboards/admin/backups/tabs.py index d4631822c..dfb40ddaa 100644 --- a/openstack_dashboard/dashboards/admin/backups/tabs.py +++ b/openstack_dashboard/dashboards/admin/backups/tabs.py @@ -11,6 +11,8 @@ # under the License. from openstack_dashboard.dashboards.project.backups \ + import tables as backup_messages_tables +from openstack_dashboard.dashboards.project.backups \ import tabs as project_tabs @@ -19,5 +21,9 @@ class AdminBackupOverviewTab(project_tabs.BackupOverviewTab): redirect_url = 'horizon:admin:backups:index' +class BackupMessagesTab(project_tabs.BackupMessagesTab): + table_classes = (backup_messages_tables.BackupMessagesTable,) + + class AdminBackupDetailTabs(project_tabs.BackupDetailTabs): - tabs = (AdminBackupOverviewTab,) + tabs = (AdminBackupOverviewTab, BackupMessagesTab) diff --git a/openstack_dashboard/dashboards/admin/backups/templates/backups/_detail_overview.html b/openstack_dashboard/dashboards/admin/backups/templates/backups/_detail_overview.html index 948df205b..c878d33bf 100644 --- a/openstack_dashboard/dashboards/admin/backups/templates/backups/_detail_overview.html +++ b/openstack_dashboard/dashboards/admin/backups/templates/backups/_detail_overview.html @@ -14,6 +14,10 @@ <dd>{{ backup.project_id|default:_("-") }}</dd> <dt>{% trans "Status" %}</dt> <dd>{{ backup.status|capfirst }}</dd> + {% if backup.status == 'error' %} + <dt>{%trans "Fail reason"%}</dt> + <dd>{{ backup.fail_reason }} <dd> + {% endif %} {% if volume %} <dt>{% trans "Volume" %}</dt> <dd> diff --git a/openstack_dashboard/dashboards/admin/snapshots/tabs.py b/openstack_dashboard/dashboards/admin/snapshots/tabs.py index 940fb074f..7ef2f5616 100644 --- a/openstack_dashboard/dashboards/admin/snapshots/tabs.py +++ b/openstack_dashboard/dashboards/admin/snapshots/tabs.py @@ -34,6 +34,6 @@ class SnapshotMessagesTab(project_tab.SnapshotMessagesTab): table_classes = (snap_messages_tables.SnapshotMessagesTable,) -class SnapshotDetailsTabs(tabs.TabGroup): +class SnapshotDetailsTabs(tabs.DetailTabsGroup): slug = "snapshot_details" tabs = (OverviewTab, SnapshotMessagesTab) diff --git a/openstack_dashboard/dashboards/project/backups/tables.py b/openstack_dashboard/dashboards/project/backups/tables.py index 4cbf34ef8..6c0a1c46d 100644 --- a/openstack_dashboard/dashboards/project/backups/tables.py +++ b/openstack_dashboard/dashboards/project/backups/tables.py @@ -197,3 +197,21 @@ class BackupsTable(tables.DataTable): row_class = UpdateRow table_actions = (DeleteBackup,) row_actions = (RestoreBackup, DeleteBackup) + + +class BackupMessagesTable(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 = "backup_messages" + verbose_name = _("Messages") diff --git a/openstack_dashboard/dashboards/project/backups/tabs.py b/openstack_dashboard/dashboards/project/backups/tabs.py index d867af485..74606fa45 100644 --- a/openstack_dashboard/dashboards/project/backups/tabs.py +++ b/openstack_dashboard/dashboards/project/backups/tabs.py @@ -18,6 +18,8 @@ from horizon import exceptions from horizon import tabs from openstack_dashboard.api import cinder +from openstack_dashboard.dashboards.project.backups \ + import tables as backup_messages_tables class BackupOverviewTab(tabs.Tab): @@ -53,6 +55,26 @@ class BackupOverviewTab(tabs.Tab): redirect=redirect) -class BackupDetailTabs(tabs.TabGroup): +class BackupMessagesTab(tabs.TableTab): + table_classes = (backup_messages_tables.BackupMessagesTable,) + name = _("Messages") + slug = "messages_tab" + template_name = ("horizon/common/_detail_table.html") + preload = False + + def get_backup_messages_data(self): + messages = [] + backup = self.tab_group.kwargs['backup'] + backup_id = backup.id + try: + messages = cinder.message_list(self.request, search_opts={ + 'resource_type': 'volume_backup', 'resource_uuid': backup_id}) + except Exception: + exceptions.handle(self.request, _("Unable to retrieve " + "backup messages.")) + return messages + + +class BackupDetailTabs(tabs.DetailTabsGroup): slug = "backup_details" - tabs = (BackupOverviewTab,) + tabs = (BackupOverviewTab, BackupMessagesTab) diff --git a/openstack_dashboard/dashboards/project/backups/templates/backups/_detail_overview.html b/openstack_dashboard/dashboards/project/backups/templates/backups/_detail_overview.html index 26e78b518..6567b88be 100644 --- a/openstack_dashboard/dashboards/project/backups/templates/backups/_detail_overview.html +++ b/openstack_dashboard/dashboards/project/backups/templates/backups/_detail_overview.html @@ -12,6 +12,10 @@ {% endif %} <dt>{% trans "Status" %}</dt> <dd>{{ backup.status|capfirst }}</dd> + {% if backup.status == 'error' %} + <dt>{%trans "Fail reason"%}</dt> + <dd>{{ backup.fail_reason }} <dd> + {% endif %} {% if volume %} <dt>{% trans "Volume" %}</dt> <dd> diff --git a/openstack_dashboard/dashboards/project/backups/tests.py b/openstack_dashboard/dashboards/project/backups/tests.py index 4a93d782a..d769f10a8 100644 --- a/openstack_dashboard/dashboards/project/backups/tests.py +++ b/openstack_dashboard/dashboards/project/backups/tests.py @@ -9,7 +9,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. - +from unittest import mock from urllib import parse from django.conf import settings @@ -20,6 +20,8 @@ from django.utils.http import urlencode from openstack_dashboard import api from openstack_dashboard.dashboards.project.backups \ import tables as backup_tables +from openstack_dashboard.dashboards.project.backups \ + import tabs from openstack_dashboard.test import helpers as test @@ -399,6 +401,38 @@ class VolumeBackupsViewTests(test.TestCase): self.mock_volume_get.assert_called_once_with( test.IsHttpRequest(), backup.volume_id) + @test.create_mocks({api.cinder: ('volume_backup_get', + 'volume_get', + 'message_list')}) + def test_volume_backup_detail_view_with_messages_tab(self): + + backup = self.cinder_volume_backups.first() + volume = self.cinder_volumes.first() + + self.mock_volume_backup_get.return_value = backup + self.mock_volume_get.return_value = volume + messages = [msg for msg in self.cinder_messages.list() + if msg.resource_type == 'VOLUME_BACKUP'] + self.mock_message_list.return_value = messages + url = reverse('horizon:project:backups:detail', + args=[backup.id]) + detail_view = tabs.BackupDetailTabs(self.request) + messages_tab_link = "?%s=%s" % ( + detail_view.param_name, + detail_view.get_tab("messages_tab").get_id()) + url += messages_tab_link + res = self.client.get(url) + self.assertTemplateUsed(res, 'horizon/common/_detail.html') + self.assertContains(res, messages[0].user_message) + self.assertNoMessages() + self.mock_volume_backup_get.assert_has_calls([ + mock.call(test.IsHttpRequest(), backup.id), + ]) + search_opts = {'resource_type': 'volume_backup', + 'resource_uuid': backup.id} + self.mock_message_list.assert_called_once_with( + test.IsHttpRequest(), search_opts=search_opts) + @test.create_mocks({api.cinder: ('volume_list', 'volume_backup_restore')}) def test_restore_backup(self): diff --git a/openstack_dashboard/dashboards/project/snapshots/tabs.py b/openstack_dashboard/dashboards/project/snapshots/tabs.py index 5a3f63deb..34957b8a4 100644 --- a/openstack_dashboard/dashboards/project/snapshots/tabs.py +++ b/openstack_dashboard/dashboards/project/snapshots/tabs.py @@ -68,6 +68,6 @@ class SnapshotMessagesTab(tabs.TableTab): return messages -class SnapshotDetailTabs(tabs.TabGroup): +class SnapshotDetailTabs(tabs.DetailTabsGroup): slug = "snapshot_details" tabs = (OverviewTab, SnapshotMessagesTab) diff --git a/openstack_dashboard/test/test_data/cinder_data.py b/openstack_dashboard/test/test_data/cinder_data.py index cc2f72681..8aa0b5e6c 100644 --- a/openstack_dashboard/test/test_data/cinder_data.py +++ b/openstack_dashboard/test/test_data/cinder_data.py @@ -579,6 +579,20 @@ def data(TEST): 'user_message': ('schedule allocate volume:' 'Could not find any available weighted backend.'), }) + messages_4 = messages.Message( + messages.MessageManager(None), + {'created_at': '2020-09-24T11:03:31.000000', + 'event_id': 'VOLUME_VOLUME_BACKUP_001_004', + 'guaranteed_until': '2020-10-24T11:03:31.000000', + 'id': '029c84a0-5810-47ed-94b6-c2aa61c5aaaf', + 'resource_type': 'VOLUME_BACKUP', + 'resource_uuid': '3c2106cb-ebef-490e-803d-b92f061e7308', + 'message_level': 'ERROR', + 'user_message': ('create backup:' + 'Backup driver failed to create backup.'), + }) + TEST.cinder_messages.add(api.cinder.Message(messages_1)) TEST.cinder_messages.add(api.cinder.Message(messages_2)) TEST.cinder_messages.add(api.cinder.Message(messages_3)) + TEST.cinder_messages.add(api.cinder.Message(messages_4)) diff --git a/releasenotes/notes/cinder-backup-cinder-messages-2127d04da3c82033.yaml b/releasenotes/notes/cinder-backup-cinder-messages-2127d04da3c82033.yaml new file mode 100644 index 000000000..aa52ddfce --- /dev/null +++ b/releasenotes/notes/cinder-backup-cinder-messages-2127d04da3c82033.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Cinder user messages are now available for volume backups in a messages tab. |