import attr
from navmazing import NavigateToAttribute, NavigateToSibling, NavigationDestinationNotFound
from widgetastic.utils import VersionPick, Version
from widgetastic.widget import View
from widgetastic_patternfly import Button, Dropdown
from cfme.common.vm import Template, TemplateCollection
from cfme.common.vm_views import (
EditView, SetOwnershipView, PolicySimulationView, BasicProvisionFormView,
VMDetailsEntities, VMEntities)
from cfme.exceptions import ImageNotFound, DestinationNotFound
from cfme.utils.appliance.implementations.ui import navigate_to, CFMENavigateStep, navigator
from cfme.utils.providers import get_crud_by_name
from widgetastic_manageiq import ItemsToolBarViewSelector, SummaryTable, ItemNotFound, Search
from . import CloudInstanceView, InstanceAccordion
[docs]class ImageDetailsEntities(VMDetailsEntities):
pass
[docs]class ImageAllView(CloudInstanceView):
"""View for the Image collection"""
toolbar = View.nested(ImageToolbar)
sidebar = View.nested(InstanceAccordion)
search = View.nested(Search)
including_entities = View.include(VMEntities, use_parent=True)
@property
def is_displayed(self):
return (
self.in_cloud_instance and
self.sidebar.images.is_opened and
self.sidebar.images.tree.selected_item.text == 'All Images' and
self.entities.title.text == 'All Images')
[docs]class ImageProviderAllView(CloudInstanceView):
"""View for the Image collection"""
toolbar = View.nested(ImageToolbar)
sidebar = View.nested(InstanceAccordion)
including_entities = View.include(VMEntities, use_parent=True)
@property
def is_displayed(self):
expected_title = 'Images under Provider "{}"'.format(self.context['object'].provider.name)
accordion = self.sidebar.images_by_provider
return (
self.in_cloud_instance and
accordion.is_opened and
accordion.tree.selected_item.text == self.context['object'].provider.name and
self.entities.title.text == expected_title)
[docs]class ImageDetailsView(CloudInstanceView):
"""View for an Image"""
toolbar = View.nested(ImageToolbar)
sidebar = View.nested(InstanceAccordion)
entities = View.nested(ImageDetailsEntities)
tag = SummaryTable(title='Smart Management') # to satisfy WidgetasticTagable, CHANGEME
@property
def is_displayed(self):
accordion = self.sidebar.images_by_provider
relationships = self.entities.relationships
return (
self.in_cloud_instance and
accordion.is_opened and
accordion.tree.selected_item.text == self.context['object'].provider.name and
relationships.get_text_of('Cloud Provider') == self.context['object'].provider.name and
self.entities.title.text == 'Image "{}"'.format(self.context['object'].name))
[docs]class ImageProvisionView(CloudInstanceView):
"""
View for provisioning image, built from common provisioning form.
No before_fill, image already selected
"""
@View.nested
class form(BasicProvisionFormView): # noqa
"""Tabs from BasicProvisionFormView, just adding buttons
"""
submit = Button('Submit') # Submit for 2nd page, tabular form
cancel = Button('Cancel')
@property
def is_displayed(self):
prov_name = self.context['object'].provider.name
return (
self.in_cloud_instance and
self.form.is_displayed and
self.form.catalog.catalog_name.currently_selected == self.context['object'].name and
len(self.form.catalog.catalog_name.read_content()) == 1 and
self.form.catalog.catalog_name.read_content()[0].get('Provider', None) == prov_name)
@attr.s
[docs]class Image(Template):
ALL_LIST_LOCATION = "clouds_images"
TO_OPEN_EDIT = "Edit this Image"
QUADICON_TYPE = "image"
@property
def exists(self):
"""Whether the image exists in CFME"""
try:
navigate_to(self, 'Details')
except ImageNotFound:
return False
return True
@attr.s
[docs]class ImageCollection(TemplateCollection):
ENTITY = Image
[docs] def all(self):
"""Return entities for all items in image collection"""
# Pretty much same as instance, but defining at VMCollection would only work for cloud
# provider filter means we're viewing images through provider details relationships
provider = self.filters.get('provider') # None if no filter, need for entity instantiation
view = navigate_to(self,
'AllForProvider' if provider else 'All')
# iterate pages here instead of use surf_pages=True because data is needed
entities = []
for _ in view.entities.paginator.pages(): # auto-resets to first page
page_entities = [entity for entity in view.entities.get_all(surf_pages=False)]
entities.extend(
# when provider filtered view, there's no provider data value
[self.instantiate(e.data['name'], provider or get_crud_by_name(e.data['provider']))
for e in page_entities
if e.data.get('provider') != ''] # safe provider check, archived shows no provider
)
return entities
@navigator.register(ImageCollection, 'All')
@navigator.register(Image, 'All')
[docs]class ImageAll(CFMENavigateStep):
VIEW = ImageAllView
prerequisite = NavigateToAttribute('appliance.server', 'LoggedIn')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.navigation.select('Compute', 'Clouds', 'Instances')
self.view.sidebar.images.tree.click_path('All Images')
@navigator.register(ImageCollection, 'AllForProvider')
@navigator.register(Image, 'AllForProvider')
[docs]class ImageAllForProvider(CFMENavigateStep):
VIEW = ImageProviderAllView
[docs] def prerequisite(self):
try:
view = navigate_to(self.obj, 'All')
except NavigationDestinationNotFound:
view = navigate_to(self.obj.parent, 'All')
finally:
return view
[docs] def step(self, *args, **kwargs):
"""Navigate to provider filtered collection
Raises:
CollectionFilterngError: When the collection has not yet been filtered
"""
if isinstance(self.obj, ImageCollection) and self.obj.filters.get('provider'):
# the collection is navigation target, use its filter value
provider_name = self.obj.filters['provider'].name
elif isinstance(self.obj, Image):
# entity is navigation target, use its provider attr
provider_name = self.obj.provider.name
else:
raise DestinationNotFound("Unable to identify a provider for AllForProvider navigation")
self.view.sidebar.images_by_provider.tree.click_path('Images by Provider', provider_name)
[docs] def resetter(self):
self.view.entities.search.remove_search_filters()
@navigator.register(Image, 'Details')
[docs]class ImageDetails(CFMENavigateStep):
VIEW = ImageDetailsView
prerequisite = NavigateToSibling('AllForProvider')
[docs] def step(self):
self.prerequisite_view.toolbar.view_selector.select('List View')
try:
row = self.prerequisite_view.entities.get_entity(name=self.obj.name, surf_pages=True)
except ItemNotFound:
raise ImageNotFound('Failed to locate image with name "{}"'.format(self.obj.name))
row.click()
@navigator.register(Image, 'ProvisionImage')
[docs]class ImageProvisionImage(CFMENavigateStep):
VIEW = ImageProvisionView
prerequisite = NavigateToSibling('Details')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.lifecycle.item_select('Provision Instances using this Image')
@navigator.register(Image, 'Edit')
[docs]class ImageEdit(CFMENavigateStep):
VIEW = EditView
prerequisite = NavigateToSibling('Details')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.configuration.item_select('Edit this Image')
@navigator.register(Image, 'SetOwnership')
[docs]class ImageSetOwnership(CFMENavigateStep):
VIEW = SetOwnershipView
prerequisite = NavigateToSibling('Details')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.configuration.item_select('Set Ownership')
@navigator.register(Image, 'PolicySimulation')
[docs]class ImagePolicySimulation(CFMENavigateStep):
VIEW = PolicySimulationView
prerequisite = NavigateToSibling('Details')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.policy.item_select('Policy Simulation')