Source code for

# -*- 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 VolumeBackupToolbar(View): """The toolbar on the Volume Backup page""" configuration = Dropdown('Configuration') policy = Dropdown('Policy') download = Dropdown('Download') view_selector = View.nested(ItemsToolBarViewSelector)
[docs]class VolumeBackupDetailsToolbar(View): """The toolbar on the Volume Backup detail page""" configuration = Dropdown('Configuration') policy = Dropdown('Policy') download = Button('Download summary in PDF format')
[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 VolumeBackupDetailSidebar(View): """The accordion on the Volume Backup details page""" @View.nested class properties(Accordion): # noqa tree = ManageIQTree() @View.nested class relationships(Accordion): # noqa tree = ManageIQTree()
[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')
[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.flash.assert_success_message('Restoring Cloud Volume "{}"'.format(
[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('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'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')
[docs]class VolumeBackupCollection(BaseCollection): """Collection object for :py:class:'' """ ENTITY = VolumeBackup
[docs] def all(self): """returning all backup objects for respective storage manager type""" view = navigate_to(self, 'All')"List View") backups = [] try: if 'provider' in self.filters: for item in 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 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 '' objects """ view = navigate_to(self, 'All') if view.entities.get_all(): for backup in backups: try: view.entities.get_entity( except ItemNotFound: raise BackupNotFoundError("Volume backup {} not found".format( view.toolbar.configuration.item_select('Delete selected Backups', handle_alert=True) wait_for( lambda: not bool({ 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): '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(, surf_pages=True).click() except ItemNotFound: raise BackupNotFoundError('Could not locate volume backup {}'.format(
@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')