Merge "Add cinder-user-facing messages for Backup"
This commit is contained in:
commit
1a4d9e8025
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Cinder user messages are now available for volume backups in a messages tab.
|
Loading…
Reference in New Issue
Block a user