# -*- coding: utf-8 -*-
# added new list_tbl definition
from functools import partial
import attr
import random
import itertools
from cached_property import cached_property
from wrapanapi.containers.node import Node as ApiNode
from navmazing import NavigateToAttribute, NavigateToSibling
from widgetastic.widget import View
from widgetastic_manageiq import (BootstrapSelect, Button, Table, Accordion, ManageIQTree,
PaginationPane, BaseNonInteractiveEntitiesView)
from cfme.common import Taggable, SummaryMixin
from cfme.containers.provider import ContainersProvider, Labelable,\
ContainerObjectAllBaseView, LoggingableView
from cfme.exceptions import NodeNotFound
from cfme.fixtures import pytest_selenium as sel
from cfme.web_ui import CheckboxTable, toolbar as tb, InfoBlock, match_location
from cfme.modeling.base import BaseCollection, BaseEntity
from cfme.utils.appliance.implementations.ui import CFMENavigateStep, navigator, navigate_to
list_tbl = CheckboxTable(table_locator="//div[@id='list_grid']//table")
match_page = partial(match_location, controller='container_node', title='Nodes')
# TODO Replace with resource table widget
resource_locator = "//div[@id='records_div']/table//span[@title='{}']"
[docs]class NodeView(ContainerObjectAllBaseView, LoggingableView):
TITLE_TEXT = "Nodes"
nodes = Table(locator="//div[@id='list_grid']//table")
@property
def table(self):
return self.nodes
@property
def in_cloud_instance(self):
return (
self.logged_in_as_current_user and
self.navigation.currently_selected == ['Compute', 'Containers', 'Container Nodes'] and
match_page() # No summary, just match controller and title
)
[docs]class NodeAllView(NodeView):
@property
def is_displayed(self):
return (
self.in_cloud_instance and
match_page(summary='Nodes')
)
paginator = PaginationPane()
@attr.s
[docs]class Node(Taggable, Labelable, SummaryMixin, BaseEntity):
PLURAL = 'Nodes'
name = attr.ib()
provider = attr.ib()
@cached_property
def mgmt(self):
return ApiNode(self.provider.mgmt, self.name)
[docs] def load_details(self, refresh=False):
navigate_to(self, 'Details')
if refresh:
tb.refresh()
[docs] def get_detail(self, *ident):
""" Gets details from the details infoblock
Args:
*ident: Table name and Key name, e.g. "Relationships", "Images"
Returns: A string representing the contents of the summary's value.
"""
self.load_details()
return InfoBlock.text(*ident)
@classmethod
[docs] def get_random_instances(cls, provider, count=1, appliance=None):
"""Generating random instances."""
node_list = provider.mgmt.list_node()
random.shuffle(node_list)
collection = NodeCollection(appliance)
return [collection.instantiate(obj.name, provider)
for obj in itertools.islice(node_list, count)]
@attr.s
[docs]class NodeCollection(BaseCollection):
"""Collection object for :py:class:`Node`."""
ENTITY = Node
[docs] def all(self):
# container_nodes table has ems_id, join with ext_mgmgt_systems on id for provider name
node_table = self.appliance.db.client['container_nodes']
ems_table = self.appliance.db.client['ext_management_systems']
node_query = self.appliance.db.client.session.query(node_table.name, ems_table.name)\
.join(ems_table, node_table.ems_id == ems_table.id)
nodes = []
for name, provider_name in node_query.all():
# Hopefully we can get by with just provider name?
nodes.append(self.instantiate(name=name,
provider=ContainersProvider(name=provider_name,
appliance=self.appliance)))
return nodes
# Still registering Node to keep on consistency on container objects navigations
@navigator.register(Node, 'All')
@navigator.register(NodeCollection, 'All')
[docs]class All(CFMENavigateStep):
VIEW = NodeAllView
prerequisite = NavigateToAttribute('appliance.server', 'LoggedIn')
[docs] def step(self, *args, **kwargs):
self.prerequisite_view.navigation.select('Compute', 'Containers', 'Container Nodes')
[docs] def resetter(self):
# Reset view and selection
tb.select("List View")
[docs]class NodeDetailsView(NodeView):
download = Button(name='download_view')
@property
def is_displayed(self):
return (
self.in_cloud_instance and
match_page(summary='{} (Summary)'.format(self.context['object'].name))
)
@View.nested
class properties(Accordion): # noqa
tree = ManageIQTree()
@View.nested
class relationships(Accordion): # noqa
tree = ManageIQTree()
@navigator.register(Node, 'Details')
[docs]class Details(CFMENavigateStep):
VIEW = NodeDetailsView
prerequisite = NavigateToAttribute('parent', 'All')
[docs] def step(self, *args, **kwargs):
# Need to account for paged view
for _ in self.prerequisite_view.paginator.pages():
row = self.view.nodes.row(name=self.obj.name, provider=self.obj.provider.name)
if row:
row.click()
break
else:
raise NodeNotFound('Failed to navigate to node, could not find matching row')
@navigator.register(Node, 'EditTags')
@navigator.register(Node, 'ManagePolicies')
[docs]class ManagePolicies(CFMENavigateStep):
VIEW = NodeManagePoliciesForm
prerequisite = NavigateToSibling('Details')
[docs] def step(self):
self.prerequisite_view.policy.item_select('Manage Policies')
[docs]class NodeUtilizationView(NodeView):
# TODO manageIQ/patternfly C&U view/widget?
@property
def is_displayed(self):
return (
self.in_cloud_instance and
match_page(summary='{} Capacity & Utilization'.format(self.context['object'].name))
)
@navigator.register(Node, 'Utilization')
[docs]class Utilization(CFMENavigateStep):
VIEW = NodeUtilizationView
prerequisite = NavigateToSibling('Details')
[docs] def step(self):
self.prerequisite_view.monitor.item_select('Utilization')
@navigator.register(Node, 'Timelines')
[docs]class Timelines(CFMENavigateStep):
VIEW = NodeTimelinesForm
prerequisite = NavigateToSibling('Details')
[docs] def step(self):
self.prerequisite_view.monitor.item_select('Timelines')