Merge "Add cinder-user-facing messages for Backup"

This commit is contained in:
Zuul 2022-09-08 12:42:30 +00:00 committed by Gerrit Code Review
commit 1a4d9e8025
11 changed files with 113 additions and 7 deletions

View File

@ -121,7 +121,7 @@ class VolumeBackup(BaseCinderAPIResourceWrapper):
_attrs = ['id', 'name', 'description', 'container', 'size', 'status', _attrs = ['id', 'name', 'description', 'container', 'size', 'status',
'created_at', 'volume_id', 'availability_zone', 'snapshot_id', 'created_at', 'volume_id', 'availability_zone', 'snapshot_id',
'os-backup-project-attr:project_id'] 'os-backup-project-attr:project_id', 'fail_reason']
_volume = None _volume = None
_snapshot = None _snapshot = None

View File

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from openstack_dashboard.dashboards.project.backups \
import tables as backup_messages_tables
from openstack_dashboard.dashboards.project.backups \ from openstack_dashboard.dashboards.project.backups \
import tabs as project_tabs import tabs as project_tabs
@ -19,5 +21,9 @@ class AdminBackupOverviewTab(project_tabs.BackupOverviewTab):
redirect_url = 'horizon:admin:backups:index' redirect_url = 'horizon:admin:backups:index'
class BackupMessagesTab(project_tabs.BackupMessagesTab):
table_classes = (backup_messages_tables.BackupMessagesTable,)
class AdminBackupDetailTabs(project_tabs.BackupDetailTabs): class AdminBackupDetailTabs(project_tabs.BackupDetailTabs):
tabs = (AdminBackupOverviewTab,) tabs = (AdminBackupOverviewTab, BackupMessagesTab)

View File

@ -14,6 +14,10 @@
<dd>{{ backup.project_id|default:_("-") }}</dd> <dd>{{ backup.project_id|default:_("-") }}</dd>
<dt>{% trans "Status" %}</dt> <dt>{% trans "Status" %}</dt>
<dd>{{ backup.status|capfirst }}</dd> <dd>{{ backup.status|capfirst }}</dd>
{% if backup.status == 'error' %}
<dt>{%trans "Fail reason"%}</dt>
<dd>{{ backup.fail_reason }} <dd>
{% endif %}
{% if volume %} {% if volume %}
<dt>{% trans "Volume" %}</dt> <dt>{% trans "Volume" %}</dt>
<dd> <dd>

View File

@ -34,6 +34,6 @@ class SnapshotMessagesTab(project_tab.SnapshotMessagesTab):
table_classes = (snap_messages_tables.SnapshotMessagesTable,) table_classes = (snap_messages_tables.SnapshotMessagesTable,)
class SnapshotDetailsTabs(tabs.TabGroup): class SnapshotDetailsTabs(tabs.DetailTabsGroup):
slug = "snapshot_details" slug = "snapshot_details"
tabs = (OverviewTab, SnapshotMessagesTab) tabs = (OverviewTab, SnapshotMessagesTab)

View File

@ -197,3 +197,21 @@ class BackupsTable(tables.DataTable):
row_class = UpdateRow row_class = UpdateRow
table_actions = (DeleteBackup,) table_actions = (DeleteBackup,)
row_actions = (RestoreBackup, 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")

View File

@ -18,6 +18,8 @@ from horizon import exceptions
from horizon import tabs from horizon import tabs
from openstack_dashboard.api import cinder from openstack_dashboard.api import cinder
from openstack_dashboard.dashboards.project.backups \
import tables as backup_messages_tables
class BackupOverviewTab(tabs.Tab): class BackupOverviewTab(tabs.Tab):
@ -53,6 +55,26 @@ class BackupOverviewTab(tabs.Tab):
redirect=redirect) 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" slug = "backup_details"
tabs = (BackupOverviewTab,) tabs = (BackupOverviewTab, BackupMessagesTab)

View File

@ -12,6 +12,10 @@
{% endif %} {% endif %}
<dt>{% trans "Status" %}</dt> <dt>{% trans "Status" %}</dt>
<dd>{{ backup.status|capfirst }}</dd> <dd>{{ backup.status|capfirst }}</dd>
{% if backup.status == 'error' %}
<dt>{%trans "Fail reason"%}</dt>
<dd>{{ backup.fail_reason }} <dd>
{% endif %}
{% if volume %} {% if volume %}
<dt>{% trans "Volume" %}</dt> <dt>{% trans "Volume" %}</dt>
<dd> <dd>

View File

@ -9,7 +9,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from unittest import mock
from urllib import parse from urllib import parse
from django.conf import settings from django.conf import settings
@ -20,6 +20,8 @@ from django.utils.http import urlencode
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.dashboards.project.backups \ from openstack_dashboard.dashboards.project.backups \
import tables as backup_tables import tables as backup_tables
from openstack_dashboard.dashboards.project.backups \
import tabs
from openstack_dashboard.test import helpers as test from openstack_dashboard.test import helpers as test
@ -399,6 +401,38 @@ class VolumeBackupsViewTests(test.TestCase):
self.mock_volume_get.assert_called_once_with( self.mock_volume_get.assert_called_once_with(
test.IsHttpRequest(), backup.volume_id) 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', @test.create_mocks({api.cinder: ('volume_list',
'volume_backup_restore')}) 'volume_backup_restore')})
def test_restore_backup(self): def test_restore_backup(self):

View File

@ -68,6 +68,6 @@ class SnapshotMessagesTab(tabs.TableTab):
return messages return messages
class SnapshotDetailTabs(tabs.TabGroup): class SnapshotDetailTabs(tabs.DetailTabsGroup):
slug = "snapshot_details" slug = "snapshot_details"
tabs = (OverviewTab, SnapshotMessagesTab) tabs = (OverviewTab, SnapshotMessagesTab)

View File

@ -579,6 +579,20 @@ def data(TEST):
'user_message': ('schedule allocate volume:' 'user_message': ('schedule allocate volume:'
'Could not find any available weighted backend.'), '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_1))
TEST.cinder_messages.add(api.cinder.Message(messages_2)) 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_3))
TEST.cinder_messages.add(api.cinder.Message(messages_4))

View File

@ -0,0 +1,4 @@
---
features:
- |
Cinder user messages are now available for volume backups in a messages tab.