Source code for cfme.intelligence.chargeback.rates

# -*- coding: utf-8 -*-
# Page model for Intel->Chargeback->Rates.
from wait_for import TimedOutError

from cached_property import cached_property
from navmazing import NavigateToSibling, NavigateToAttribute
from widgetastic.utils import ParametrizedLocator, ParametrizedString
from widgetastic.widget import Text, ParametrizedView, View
from widgetastic_patternfly import Button, Input, Dropdown

from cfme.exceptions import ChargebackRateNotFound
from cfme.utils import ParamClassName
from cfme.utils.appliance import Navigatable
from cfme.utils.appliance.implementations.ui import navigator, navigate_to, CFMENavigateStep
from cfme.utils.blockers import BZ
from cfme.utils.pretty import Pretty
from cfme.utils.update import Updateable
from widgetastic_manageiq import Select, Table
from . import ChargebackView


[docs]class RatesView(ChargebackView): title = Text("#explorer_title_text") table = Table(".//div[@id='records_div' or @class='miq-data-table']/table") @property def in_rates(self): """Determine if in the rates part of chargeback, includes check of in_chargeback""" return( self.in_chargeback and self.toolbar.configuration.is_displayed and self.rates.is_opened) @property def is_displayed(self): # BZ 1532701 for singular title on redirection to this page, but not direct navigation if BZ(1532701, forced_streams='5.9').blocks: title_test = ("{} Chargeback Rate".format(self.context['object'].RATE_TYPE) in self.title.text) else: title_test = ("{} Chargeback Rates".format(self.context['object'].RATE_TYPE) == self.title.text) return ( self.in_rates and self.rates.tree.currently_selected == ['Rates', self.context['object'].RATE_TYPE] and title_test) @View.nested class toolbar(View): # noqa configuration = Dropdown('Configuration')
[docs]class RatesDetailView(RatesView): # TODO add widget for rate details @property def is_displayed(self): return ( self.in_rates and self.rates.tree.currently_selected == ['Rates', self.context['object'].RATE_TYPE, self.context['object'].description] and self.title.text == '{} Chargeback Rate "{}"' .format(self.context['object'].RATE_TYPE, self.context['object'].description))
[docs]class AddComputeChargebackView(RatesView): title = Text('#explorer_title_text') description = Input(id='description') currency = Select(id='currency') @ParametrizedView.nested class fields(ParametrizedView): # noqa PARAMETERS = ('name',) ROOT = ParametrizedLocator('.//tr[./td[contains(normalize-space(.), {name|quote})]]') @cached_property def row_id(self): attr = self.browser.get_attribute( 'id', './td/select[starts-with(@id, "per_time_")]', parent=self) return int(attr.rsplit('_', 1)[-1]) @cached_property def sub_row_id(self): attr = self.browser.get_attribute( 'id', './td/input[starts-with(@id, "fixed_rate_")]', parent=self) return int(attr.rsplit('_', 1)[-1]) per_time = Select(id=ParametrizedString('per_time_{@row_id}')) per_unit = Select(id=ParametrizedString('per_unit_{@row_id}')) start = Input(id=ParametrizedString('start_{@row_id}_{@sub_row_id}')) finish = Input(id=ParametrizedString('finish_{@row_id}_{@sub_row_id}')) fixed_rate = Input(id=ParametrizedString('fixed_rate_{@row_id}_{@sub_row_id}')) variable_rate = Input(id=ParametrizedString('variable_rate_{@row_id}_{@sub_row_id}')) action_add = Button(title='Add a new tier') action_delete = Button(title='Remove the tier') add_button = Button(title='Add') cancel_button = Button(title='Cancel') @property def is_displayed(self): return False
[docs]class EditComputeChargebackView(AddComputeChargebackView): save_button = Button(title='Save Changes') reset_button = Button(title='Reset Changes') @property def is_displayed(self): return ( self.in_chargeback and self.title.text == 'Compute Chargeback Rate "{}"'.format(self.obj.description))
[docs]class AddStorageChargebackView(AddComputeChargebackView): pass
[docs]class EditStorageChargebackView(EditComputeChargebackView): @property def is_displayed(self): return ( self.in_chargeback and self.title.text == 'Storage Chargeback Rate "{}"'.format(self.obj.description))
# TODO Inherit BaseEntity and create a parent collection class
[docs]class ComputeRate(Updateable, Pretty, Navigatable): """This class represents a Compute Chargeback rate. Example: .. code-block:: python >>> import cfme.intelligence.chargeback.rates as rates >>> rate = rates.ComputeRate(description=desc, fields={'Used CPU': {'per_time': 'Hourly', 'variable_rate': '3'}, 'Used Disk I/O': {'per_time': 'Hourly', 'variable_rate': '2'}, 'Used Memory': {'per_time': 'Hourly', 'variable_rate': '2'}}) >>> rate.create() >>> rate.delete() Args: description: Rate description currency: Rate currency fields : Rate fields """ pretty_attrs = ['description'] _param_name = ParamClassName('description') RATE_TYPE = 'Compute' def __init__(self, description=None, currency=None, fields=None, appliance=None, ): Navigatable.__init__(self, appliance=appliance) self.description = description self.currency = currency self.fields = fields def __getitem__(self, name): return self.fields.get(name) @property def exists(self): try: navigate_to(self, 'Details', wait_for_view=True) except (ChargebackRateNotFound, TimedOutError): return False else: return True
[docs] def create(self): # Create a rate in UI view = navigate_to(self, 'Add') view.fill_with({'description': self.description, 'currency': self.currency, 'fields': self.fields}, on_change=view.add_button, no_change=view.cancel_button) view = self.create_view(navigator.get_class(self, 'All').VIEW) assert view.is_displayed view.flash.assert_no_error()
[docs] def copy(self, *args, **kwargs): new_rate = ComputeRate(*args, **kwargs) add_view = navigate_to(self, 'Copy') add_view.fill_with({'description': new_rate.description, 'currency': new_rate.currency, 'fields': new_rate.fields}, on_change=add_view.add_button, no_change=add_view.cancel_button) return new_rate
[docs] def update(self, updates): # Update a rate in UI view = navigate_to(self, 'Edit') view.fill_with(updates, on_change=view.save_button, no_change=view.cancel_button) view = self.create_view(navigator.get_class(self, 'Details').VIEW) view.flash.assert_no_error()
[docs] def delete(self, cancel=False): """Delete a CB rate in the UI Args: cancel: boolean, whether to cancel the action on alert """ view = navigate_to(self, 'Details', wait_for_view=True) view.toolbar.configuration.item_select('Remove from the VMDB', handle_alert=(not cancel)) view = self.create_view(navigator.get_class(self, 'All').VIEW) assert view.is_displayed view.flash.assert_no_error()
[docs]class StorageRate(ComputeRate): # Methods and form for this are similar to that of ComputeRate, but navigation is different # from that of ComputeRate. pretty_attrs = ['description'] RATE_TYPE = 'Storage'
@navigator.register(ComputeRate, 'All')
[docs]class ComputeRateAll(CFMENavigateStep): VIEW = RatesView prerequisite = NavigateToAttribute('appliance.server', 'IntelChargeback')
[docs] def step(self): self.view.rates.tree.click_path( "Rates", "Compute" )
@navigator.register(ComputeRate, 'Add')
[docs]class ComputeRateNew(CFMENavigateStep): VIEW = AddComputeChargebackView prerequisite = NavigateToSibling('All')
[docs] def step(self): self.view.toolbar.configuration.item_select("Add a new Chargeback Rate")
@navigator.register(ComputeRate, 'Details')
[docs]class ComputeRateDetails(CFMENavigateStep): VIEW = RatesDetailView prerequisite = NavigateToSibling('All')
[docs] def step(self): try: self.view.rates.tree.click_path( "Rates", "Compute", self.obj.description ) except Exception as ex: # TODO don't diaper here raise ChargebackRateNotFound('Exception navigating to ComputeRate {} "Details": {}' .format(self.obj.description, ex))
@navigator.register(ComputeRate, 'Copy')
[docs]class ComputeRateCopy(CFMENavigateStep): VIEW = AddComputeChargebackView prerequisite = NavigateToSibling('Details')
[docs] def step(self): self.view.toolbar.configuration.item_select('Copy this Chargeback Rate')
@navigator.register(ComputeRate, 'Edit')
[docs]class ComputeRateEdit(CFMENavigateStep): VIEW = EditComputeChargebackView prerequisite = NavigateToSibling('Details')
[docs] def step(self): self.view.toolbar.configuration.item_select("Edit this Chargeback Rate")
@navigator.register(StorageRate, 'All')
[docs]class StorageRateAll(CFMENavigateStep): VIEW = RatesView prerequisite = NavigateToAttribute('appliance.server', 'IntelChargeback')
[docs] def step(self): self.view.rates.tree.click_path( "Rates", "Storage" )
@navigator.register(StorageRate, 'Add')
[docs]class StorageRateNew(CFMENavigateStep): VIEW = AddStorageChargebackView prerequisite = NavigateToSibling('All')
[docs] def step(self): self.view.toolbar.configuration.item_select("Add a new Chargeback Rate")
@navigator.register(StorageRate, 'Details')
[docs]class StorageRateDetails(CFMENavigateStep): VIEW = RatesDetailView prerequisite = NavigateToSibling('All')
[docs] def step(self): try: self.view.rates.tree.click_path( "Rates", "Storage", self.obj.description ) except Exception as ex: # TODO don't diaper here raise ChargebackRateNotFound('Exception navigating to StorageRate {} "Details": {}' .format(self.obj.description, ex))
@navigator.register(StorageRate, 'Edit')
[docs]class StorageRateEdit(CFMENavigateStep): VIEW = EditStorageChargebackView prerequisite = NavigateToSibling('Details')
[docs] def step(self): self.view.toolbar.configuration.item_select("Edit this Chargeback Rate")