# -*- coding: utf-8 -*-
import random
import attr
from navmazing import NavigateToSibling, NavigateToAttribute
from widgetastic.widget import View, Text, NoSuchElementException
from widgetastic_patternfly import BreadCrumb, BootstrapSelect, Button, Dropdown
from cfme.base.ui import BaseLoggedInPage
from cfme.common import TagPageView, Taggable
from cfme.exceptions import BackupNotFoundError, ItemNotFound
from cfme.modeling.base import BaseCollection, BaseEntity
from cfme.utils.appliance.implementations.ui import CFMENavigateStep, navigator, navigate_to
from cfme.utils.log import logger
from cfme.utils.providers import get_crud_by_name
from cfme.utils.wait import wait_for
from widgetastic_manageiq import (
Accordion, BaseEntitiesView, ItemsToolBarViewSelector, ManageIQTree, SummaryTable)
[docs]class VolumeBackupDetailsEntities(View):
"""The entities on the Volume Backup detail page"""
breadcrumb = BreadCrumb()
properties = SummaryTable('Properties')
relationships = SummaryTable('Relationships')
smart_management = SummaryTable('Smart Management')
[docs]class VolumeBackupView(BaseLoggedInPage):
"""A base view for all the Volume Backup pages"""
title = Text('.//div[@id="center_div" or @id="main-content"]//h1')
@property
def in_volume_backup(self):
return (
self.logged_in_as_current_user and
self.navigation.currently_selected == ['Storage', 'Block Storage', 'Volume Backups']
)
@property
def is_displayed(self):
return self.in_volume_backup
[docs]class VolumeBackupAllView(VolumeBackupView):
"""The all Volume Backup page"""
toolbar = View.nested(VolumeBackupToolbar)
including_entities = View.include(BaseEntitiesView, use_parent=True)
@property
def is_displayed(self):
return (
self.in_volume_backup and
self.title.text == 'Cloud Volume Backups')
[docs]class VolumeBackupDetailsView(VolumeBackupView):
"""The detail Volume Backup page"""
@property
def is_displayed(self):
expected_title = '{} (Summary)'.format(self.context['object'].name)
return (
self.in_volume_backup and
self.title.text == expected_title and
self.entities.breadcrumb.active_location == expected_title)
toolbar = View.nested(VolumeBackupDetailsToolbar)
sidebar = View.nested(VolumeBackupDetailSidebar)
entities = View.nested(VolumeBackupDetailsEntities)
[docs]class VolumeRestoreView(VolumeBackupView):
"""The restore Volume backup view"""
@property
def is_displayed(self):
return False
volume_name = BootstrapSelect(name='volume_id')
save = Button('Save')
reset = Button('Reset')
cancel = Button('cancel')
@attr.s
[docs]class VolumeBackup(BaseEntity, Taggable):
""" Model of an Storage Volume Backups in cfme
Args:
name: name of the backup
provider: provider
"""
name = attr.ib()
provider = attr.ib()
[docs] def restore(self, name):
"""Restore the volume backup. this feature included in 5.9 and above.
Args:
name: volume name
"""
view = navigate_to(self, 'Restore')
view.volume_name.fill(name)
view.save.click()
view.flash.assert_success_message('Restoring Cloud Volume "{}"'.format(self.name))
[docs] def refresh(self):
self.provider.refresh_provider_relationships()
self.browser.refresh()
@property
def exists(self):
try:
navigate_to(self, 'Details')
return True
except BackupNotFoundError:
return False
@property
def size(self):
"""size of cloud volume backup.
Returns:
:py:class:`int` size of volume backup in GB.
"""
view = navigate_to(self, 'Details')
return int(view.entities.properties.get_text_of('Size').split()[0])
@property
def status(self):
"""Present status of cloud volume backup.
Returns:
:py:class:`str` status [available/restoring] of volume backup.
"""
view = navigate_to(self, 'Details')
return view.entities.properties.get_text_of('Status')
@property
def volume(self):
"""volume name of backup.
Returns:
:py:class:`str` respective volume name.
"""
view = navigate_to(self, 'Details')
return view.entities.relationships.get_text_of('Cloud Volume')
@attr.s
[docs]class VolumeBackupCollection(BaseCollection):
"""Collection object for :py:class:'cfme.storage.volume_backups.VolumeBackup' """
ENTITY = VolumeBackup
[docs] def all(self):
"""returning all backup objects for respective storage manager type"""
view = navigate_to(self, 'All')
view.toolbar.view_selector.select("List View")
backups = []
try:
if 'provider' in self.filters:
for item in view.entities.elements.read():
if self.filters.get('provider').name in item['Storage Manager']:
backups.append(self.instantiate(name=item['Name'],
provider=self.filters.get('provider')))
else:
for item in view.entities.elements.read():
provider_name = item['Storage Manager'].split()[0]
provider = get_crud_by_name(provider_name)
backups.append(self.instantiate(name=item['Name'], provider=provider))
except NoSuchElementException:
if backups:
# In the middle of reading, that may be bad
logger.error(
'VolumeBackupCollection: NoSuchElementException in the middle of entities read')
raise
else:
# This is probably fine, just warn
logger.warning('The volume backup table is probably not present (=empty)')
return backups
[docs] def delete(self, *backups):
"""Delete one or more backups
Args:
One or Multiple 'cfme.storage.volume_backup.VolumeBackup' objects
"""
view = navigate_to(self, 'All')
if view.entities.get_all():
for backup in backups:
try:
view.entities.get_entity(name=backup.name).check()
except ItemNotFound:
raise BackupNotFoundError("Volume backup {} not found".format(backup.name))
view.toolbar.configuration.item_select('Delete selected Backups', handle_alert=True)
wait_for(
lambda: not bool({backup.name for backup in backups} &
set(view.entities.all_entity_names)),
message="Wait backups to disappear",
delay=20,
timeout=800,
fail_func=random.choice(backups).refresh
)
else:
raise BackupNotFoundError('No Volume Backups for Deletion')
@navigator.register(VolumeBackupCollection, 'All')
[docs]class All(CFMENavigateStep):
VIEW = VolumeBackupAllView
prerequisite = NavigateToAttribute('appliance.server', 'LoggedIn')
[docs] def step(self):
self.prerequisite_view.navigation.select(
'Storage', 'Block Storage', 'Volume Backups')
@navigator.register(VolumeBackup, 'Details')
[docs]class Details(CFMENavigateStep):
VIEW = VolumeBackupDetailsView
prerequisite = NavigateToAttribute('parent', 'All')
[docs] def step(self, *args, **kwargs):
try:
self.prerequisite_view.entities.get_entity(name=self.obj.name,
surf_pages=True).click()
except ItemNotFound:
raise BackupNotFoundError('Could not locate volume backup {}'.format(self.obj.name))
@navigator.register(VolumeBackup, 'EditTagsFromDetails')
[docs]class BackupDetailEditTag(CFMENavigateStep):
""" This navigation destination help to Taggable"""
VIEW = TagPageView
prerequisite = NavigateToSibling('Details')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.policy.item_select('Edit Tags')
@navigator.register(VolumeBackup, 'Restore')
[docs]class VolumeRestore(CFMENavigateStep):
VIEW = VolumeRestoreView
prerequisite = NavigateToSibling('Details')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.configuration.item_select('Restore backup to Cloud Volume')