# -*- coding: utf-8 -*-
# added new list_tbl definition
import attr
from cached_property import cached_property
from wrapanapi.containers.node import Node as ApiNode
from navmazing import NavigateToAttribute, NavigateToSibling
from widgetastic.exceptions import NoSuchElementException
from widgetastic.widget import View
from widgetastic_manageiq import Button, Text, TimelinesView, BreadCrumb
from cfme.common import Taggable, TagPageView, PolicyProfileAssignable
from cfme.containers.provider import (Labelable,
ContainerObjectAllBaseView, LoggingableView, ContainerObjectDetailsBaseView,
GetRandomInstancesMixin)
from cfme.modeling.base import BaseCollection, BaseEntity
from cfme.utils.appliance.implementations.ui import (CFMENavigateStep, navigator,
navigate_to)
from cfme.common.provider_views import ProviderDetailsToolBar
from cfme.utils.providers import get_crud_by_name
[docs]class NodeView(ContainerObjectAllBaseView, LoggingableView):
SUMMARY_TEXT = "Nodes"
@property
def nodes(self):
return self.table
@property
def in_node(self):
"""Determine if the Nodes page is currently open"""
return (
self.logged_in_as_current_user and
self.navigation.currently_selected == ['Compute', 'Containers', 'Container Nodes']
)
[docs]class NodeAllView(NodeView):
@property
def is_displayed(self):
return self.in_node and super(NodeAllView, self).is_displayed
[docs]class NodeDetailsView(ContainerObjectDetailsBaseView):
toolbar = View.nested(NodeDetailsToolBar)
@attr.s
[docs]class Node(BaseEntity, Taggable, Labelable, PolicyProfileAssignable):
"""Node Class"""
PLURAL = 'Nodes'
all_view = NodeAllView
details_view = NodeDetailsView
name = attr.ib()
provider = attr.ib()
@cached_property
def mgmt(self):
"""API to use for Nodes"""
return ApiNode(self.provider.mgmt, self.name)
@property
def exists(self):
"""Return True if the Node exists"""
# TODO: move this to some ContainerObjectBase so it'll be shared among all objects
try:
navigate_to(self, 'Details')
except NoSuchElementException:
return False
else:
return True
@attr.s
[docs]class NodeCollection(GetRandomInstancesMixin, 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
# TODO Update to use REST API instead of DB queries
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))
if self.filters.get('archived'):
node_query = node_query.filter(node_table.deleted_on.isnot(None))
if self.filters.get('active'):
node_query = node_query.filter(node_table.deleted_on.is_(None))
provider = None
# filtered
if self.filters.get('provider'):
provider = self.filters.get('provider')
node_query = node_query.filter(ems_table.name == provider.name)
nodes = []
for name, ems_name in node_query.all():
nodes.append(self.instantiate(name=name,
provider=provider or get_crud_by_name(ems_name)))
return nodes
@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
self.view.toolbar.view_selector.select("List View")
self.view.paginator.reset_selection()
@navigator.register(Node, 'Details')
[docs]class Details(CFMENavigateStep):
VIEW = NodeDetailsView
prerequisite = NavigateToAttribute('parent', 'All')
[docs] def step(self, *args, **kwargs):
search_visible = self.prerequisite_view.entities.search.is_displayed
self.prerequisite_view.entities.get_entity(name=self.obj.name,
provider=self.obj.provider.name,
surf_pages=not search_visible,
use_search=search_visible).click()
@navigator.register(Node, 'EditTags')
[docs]class NodeUtilizationView(NodeView):
"""View for utilization of a node"""
title = Text('//div[@id="main-content"]//h1')
@property
def is_displayed(self):
"""Is this page currently being displayed"""
return (
self.in_node and
self.title.text == '{} Capacity & Utilization'.format(self.context['object'].name)
)
@navigator.register(Node, 'Utilization')
[docs]class Utilization(CFMENavigateStep):
VIEW = NodeUtilizationView
prerequisite = NavigateToSibling('Details')
[docs] def step(self):
"""Navigate to the Utilization page"""
self.prerequisite_view.toolbar.monitoring.item_select('Utilization')
[docs]class NodeTimelinesView(TimelinesView, NodeView):
"""Timeline page for Nodes"""
breadcrumb = BreadCrumb()
@property
def is_displayed(self):
"""Is this page currently being displayed"""
return (
self.in_node and
'{} (Summary)'.format(self.context['object'].name) in self.breadcrumb.locations and
self.is_timelines)
@navigator.register(Node, 'Timelines')
[docs]class Timelines(CFMENavigateStep):
VIEW = NodeTimelinesView
prerequisite = NavigateToSibling('Details')
[docs] def step(self):
"""Navigate to the Timelines page"""
self.prerequisite_view.toolbar.monitoring.item_select('Timelines')
# TODO Need Ad hoc Metrics
# TODO Need External Logging