Source code for

# -*- coding: utf-8 -*-
import attr
from navmazing import NavigateToAttribute, NavigateToSibling
from widgetastic.exceptions import MoveTargetOutOfBoundsException
from widgetastic.widget import View
from widgetastic.utils import VersionPick, Version
from widgetastic_patternfly import BreadCrumb, Button, Dropdown

from cfme.base.ui import BaseLoggedInPage
from cfme.common import Taggable
from cfme.exceptions import KeyPairNotFound
from cfme.modeling.base import BaseCollection, BaseEntity
from cfme.utils.appliance.implementations.ui import navigate_to, navigator, CFMENavigateStep
from cfme.utils.wait import wait_for
from widgetastic_manageiq import (
    ItemsToolBarViewSelector, Text, TextInput, Accordion, ManageIQTree, SummaryTable,
    BootstrapSelect, ItemNotFound, BaseEntitiesView, PaginationPane, Search)

[docs]class KeyPairToolbar(View): policy = Dropdown('Policy') configuration = Dropdown('Configuration') download = Dropdown('Download') view_selector = View.nested(ItemsToolBarViewSelector)
[docs]class KeyPairDetailsToolbar(View): policy = Dropdown('Policy') configuration = Dropdown('Configuration') download = Button(title='Download summary in PDF format')
[docs]class KeyPairDetailsAccordion(View): @View.nested class properties(Accordion): # noqa tree = ManageIQTree() @View.nested class relationships(Accordion): # noqa tree = ManageIQTree()
[docs]class KeyPairDetailsEntities(View): breadcrumb = BreadCrumb() title = Text('//div[@id="main-content"]//h1') properties = SummaryTable(title='Properties') relationships = SummaryTable(title='Relationships') smart_management = SummaryTable(title='Smart Management')
[docs]class KeyPairAddEntities(View): breadcrumb = BreadCrumb() title = Text('//div[@id="main-content"]//h1')
[docs]class KeyPairAddForm(View): name = TextInput(id='name') public_key = TextInput(id='public_key') provider = BootstrapSelect(id='ems_id') add = Button('Add') cancel = Button('Cancel')
[docs]class KeyPairView(BaseLoggedInPage): """Base view for header and nav checking, navigatable views should inherit this""" @property def in_keypair(self): return( self.logged_in_as_current_user and self.navigation.currently_selected == ['Compute', 'Clouds', 'Key Pairs'] )
[docs]class KeyPairAllView(KeyPairView): @property def is_displayed(self): return ( self.in_keypair and self.entities.title.text == 'Key Pairs') paginator = PaginationPane() toolbar = View.nested(KeyPairToolbar) search = View.nested(Search) including_entities = View.include(BaseEntitiesView, use_parent=True)
[docs]class KeyPairDetailsView(KeyPairView): @property def is_displayed(self): expected_title = '{} (Summary)'.format(self.context['object'].name) return ( self.in_keypair and self.entities.title.text == expected_title and self.entities.breadcrumb.active_location == expected_title) toolbar = View.nested(KeyPairDetailsToolbar) sidebar = View.nested(KeyPairDetailsAccordion) entities = View.nested(KeyPairDetailsEntities)
[docs]class KeyPairAddView(KeyPairView): @property def is_displayed(self): return ( self.in_keypair and self.entities.breadcrumb.active_location == 'Add New Key Pair' and self.entities.title.text == 'Add New Key Pair') entities = View.nested(KeyPairAddEntities) form = View.nested(KeyPairAddForm)
[docs]class KeyPair(BaseEntity, Taggable): """ Automate Model page of KeyPairs Args: name: Name of Keypairs. """ _param_name = "KeyPair" name = attr.ib() provider = attr.ib() public_key = attr.ib(default="")
[docs] def delete(self, cancel=False, wait=False): view = navigate_to(self, 'Details') # TODO: get rid of this resolve when widgetastic.core/pull/68 is merged item_name = VersionPick({Version.lowest(): 'Remove this Key Pair', '5.9': 'Remove this Key Pair from Inventory'} ).pick(self.appliance.version) view.toolbar.configuration.item_select(item_name, handle_alert=(not cancel)) # cancel doesn't redirect, confirmation does view.flush_widget_cache() if cancel: view = self.create_view(KeyPairDetailsView) else: view = self.create_view(KeyPairAllView) wait_for(lambda: view.is_displayed, fail_condition=False, num_sec=10, delay=1) # flash message only displayed if it was deleted if not cancel: view.flash.assert_no_error() view.flash.assert_success_message('Delete initiated for 1 Key Pair') if wait: def refresh(): self.provider.refresh_provider_relationships() view.browser.refresh() view.flush_widget_cache() view = navigate_to(self.parent, 'All') wait_for( lambda: in view.entities.all_entity_names, message="Wait keypairs to disappear", fail_condition=True, num_sec=300, delay=5, fail_func=refresh )
@property def exists(self): try: navigate_to(self, 'Details') except KeyPairNotFound: return False else: return True
[docs]class KeyPairCollection(BaseCollection): """ Collection object for the :py:class: ``. """ ENTITY = KeyPair
[docs] def create(self, name, provider, public_key=None, cancel=False): """Create new keyPair. Args: name (str): name of the KeyPair public_key (str): RSA Key if present provider (str): Cloud Provider cancel (boolean): Cancel Keypair creation """ view = navigate_to(self, 'Add') changed = view.form.fill({'name': name, 'public_key': public_key, 'provider': }) if cancel and not changed: flash_message = 'Add of new Key Pair was cancelled by the user' else: flash_message = 'Key Pair "{}" created'.format(name) # add/cancel should redirect, new view view = self.create_view(KeyPairAllView) # TODO BZ 1444520 causing ridiculous redirection times after submitting the form wait_for(lambda: view.is_displayed, num_sec=240, delay=2, fail_func=view.flush_widget_cache, handle_exception=True) assert view.is_displayed view.flash.assert_success_message(flash_message) return self.instantiate(name, provider, public_key=public_key)
@navigator.register(KeyPairCollection, 'All')
[docs]class CloudKeyPairs(CFMENavigateStep): VIEW = KeyPairAllView prerequisite = NavigateToAttribute('appliance.server', 'LoggedIn')
[docs] def step(self, *args, **kwargs):'Compute', 'Clouds', 'Key Pairs')
@navigator.register(KeyPair, 'Details')
[docs]class Details(CFMENavigateStep): VIEW = KeyPairDetailsView prerequisite = NavigateToAttribute('parent', 'All')
[docs] def step(self, *args, **kwargs): try: item = self.prerequisite_view.entities.get_entity(, surf_pages=True) except ItemNotFound: raise KeyPairNotFound
@navigator.register(KeyPairCollection, 'Add')
[docs]class Add(CFMENavigateStep): VIEW = KeyPairAddView prerequisite = NavigateToSibling("All")
[docs] def step(self, *args, **kwargs): """Raises DropdownItemDisabled from widgetastic_patternfly if no RHOS provider present""" try: self.prerequisite_view.toolbar.configuration.item_select('Add a new Key Pair') # TODO: Remove once fixed 1475303 except MoveTargetOutOfBoundsException: self.prerequisite_view.toolbar.configuration.item_select('Add a new Key Pair')