class DefaultDashboard(Updateable, Pretty, Navigatable): form = Form(fields=[ ("title", Input("description")), ("locked", Input("locked")), ("widgets", NewerDashboardWidgetSelector("//div[@id='form_widgets_div']")), ]) reset_button = "//*[@title='Reset Dashboard Widgets to the defaults']" pretty_attrs = ['title', 'widgets'] def __init__(self, title=None, locked=None, widgets=None, appliance=None): Navigatable.__init__(self, appliance) self.title = title self.locked = locked self.widgets = widgets def update(self, updates): navigate_to(self, 'Edit') fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): navigate_to(self, 'Details') toolbar.select("Configuration", "Delete this Dashboard from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors() @classmethod def reset_widgets(cls, cancel=False): navigate_to(Server, 'Dashboard') sel.click(cls.reset_button, wait_ajax=False) sel.handle_alert(cancel) flash.assert_no_errors()
class ChartWidget(Updateable): form = Form(fields=[ ("title", "//input[@id='title']"), ("description", "//input[@id='description']"), ("active", "//input[@id='enabled']"), ("filter", Select("//select[@id='repfilter_typ']")), ("timer", Timer()), ("visibility", visibility_obj), ]) def __init__(self, title, description=None, active=None, filter=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.filter = filter self.timer = timer self.visibility = visibility def create(self, cancel=False): sel.force_navigate("reports_widgets_chart_add") fill(self.form, self.__dict__, action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): sel.force_navigate("reports_widgets_chart_edit", context={"widget": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): sel.force_navigate("reports_widgets_chart", context={"widget": self}) toolbar.select("Configuration", "Delete this Widget from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
class SNMPForm(object): """Class encapsulating the most common (and hopefully single) configuration of SNMP form Usage: form = SNMPForm() fill(form, dict( hosts=["host1", "host2"], traps=[ ("aaa", "Counter32", 125), # Takes 3-tuples ("bbb", "Null"), # 2-tuples with no value specified SNMPTrap("ccc", "Gauge32", 256), # objects dtto SNMPTrap("ddd", "Null"), # value can be unspecified too {"oid": "eee", "type": "Integer", "value": 42} # omg dict too! Yay. ], version="v2", id="aabcd", )) """ fields = Form(fields=[ ("hosts", SNMPHostsField()), ("version", Select("//select[@id='snmp_version']")), ("id", Input('trap_id')), ("traps", SNMPTrapsField(10)), ])
class RSSFeedWidget(Widget): form = Form(fields=[ ("title", Input("title")), ("description", Input("description")), ("active", Input("enabled")), ("type", Select("//select[@id='feed_type']")), ("feed", Select("//select[@id='rss_feed']")), ("external", ExternalRSSFeed()), ("rows", Select("//select[@id='row_count']")), ("timer", Timer()), ("visibility", visibility_obj), ]) TITLE = "RSS Feeds" pretty_attrs = ['title', 'description', 'type', 'feed', 'visibility'] def __init__(self, title, description=None, active=None, type=None, feed=None, external=None, rows=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.type = type self.feed = feed self.external = external self.rows = rows self.timer = timer self.visibility = visibility
class ChartWidget(Widget): form = Form(fields=[ ("title", Input("title")), ("description", Input("description")), ("active", Input("enabled")), ("filter", Select("//select[@id='repfilter_typ']")), ("timer", Timer()), ("visibility", visibility_obj), ]) TITLE = "Charts" pretty_attrs = ['title', 'description', 'filter', 'visibility'] def __init__(self, title, description=None, active=None, filter=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.filter = filter self.timer = timer self.visibility = visibility
class Timer(object): form = Form(fields=[ ("run", { version.LOWEST: Select("//select[@id='timer_typ']"), '5.5': AngularSelect('timer_typ')}), ("hours", { version.LOWEST: Select("//select[@id='timer_hours']"), '5.5': AngularSelect('timer_hours')}), ("days", { version.LOWEST: Select("//select[@id='timer_days']"), '5.5': AngularSelect('timer_days')}), ("weeks", { version.LOWEST: Select("//select[@id='timer_weeks']"), '5.5': AngularSelect('timer_weeks')}), ("months", { version.LOWEST: Select("//select[@id='timer_months']"), '5.5': AngularSelect('timer_months')}), ("time_zone", { version.LOWEST: Select("//select[@id='time_zone']"), '5.5': AngularSelect('time_zone')}), ("start_date", Calendar("miq_date_1")), ("start_hour", { version.LOWEST: Select("//select[@id='start_hour']"), '5.5': AngularSelect('start_hour')}), ("start_min", { version.LOWEST: Select("//select[@id='start_min']"), '5.5': AngularSelect('start_min')}), ])
class Role(Updateable, Pretty, Navigatable): form = Form(fields=[ ('name_txt', Input('name')), ('vm_restriction_select', AngularSelect('vm_restriction')), ('product_features_tree', { version.LOWEST: CheckboxTree("//div[@id='features_treebox']/ul"), '5.7': BootstrapTreeview("features_treebox") }), ]) pretty_attrs = ['name', 'product_features'] def __init__(self, name=None, vm_restriction=None, product_features=None, appliance=None): Navigatable.__init__(self, appliance=appliance) self.name = name self.vm_restriction = vm_restriction self.product_features = product_features or [] def create(self): navigate_to(self, 'Add') fill(self.form, { 'name_txt': self.name, 'vm_restriction_select': self.vm_restriction, 'product_features_tree': self.product_features }, action=form_buttons.add) flash.assert_success_message('Role "{}" was saved'.format(self.name)) def update(self, updates): navigate_to(self, 'Edit') fill(self.form, { 'name_txt': updates.get('name'), 'vm_restriction_select': updates.get('vm_restriction'), 'product_features_tree': updates.get('product_features') }, action=form_buttons.save) flash.assert_success_message('Role "{}" was saved'.format( updates.get('name', self.name))) def delete(self): navigate_to(self, 'Details') tb_select('Delete this Role', invokes_alert=True) sel.handle_alert() flash.assert_success_message('Role "{}": Delete successful'.format( self.name)) def copy(self, name=None): if not name: name = self.name + "copy" navigate_to(self, 'Details') tb.select('Configuration', 'Copy this Role to a new Role') new_role = Role(name=name) fill(self.form, {'name_txt': new_role.name}, action=form_buttons.add) flash.assert_success_message('Role "{}" was saved'.format( new_role.name)) return new_role
def form(self): """Returns the form with fields targeted at our row_id. Does not need to be on the page. """ return Form(fields=[(col_name, "//input[contains(@id, '{}')]".format( self.fields[i].format(self._row_id))) for i, col_name in enumerate(self.columns)])
class ProvisioningDialog(Updateable, Pretty): form = Form(fields=[ ("name", Input('name')), ("description", Input('description')), ("type", DialogTypeSelect("//select[@id='dialog_type']")), ("content", "//textarea[@id='content_data']"), ]) HOST_PROVISION = ("host_provision", "Host Provision") VM_MIGRATE = ("vm_migrate", "VM Migrate") VM_PROVISION = ("vm_provision", "VM Provision") ALLOWED_TYPES = {HOST_PROVISION, VM_MIGRATE, VM_PROVISION} pretty_attrs = ['name', 'description', 'content'] def __init__(self, type, name=None, description=None, content=None): self.name = name self.description = description self.type = type self.content = content @property def type_nav(self): return self.type[0] @property def exists(self): try: sel.force_navigate("{}_dialog".format(self.type_nav), context={"dialog": self}) return True except CandidateNotFound: return False def create(self, cancel=False): sel.force_navigate("{}_dialogs".format(self.type_nav)) cfg_btn("Add a new Dialog") fill(self.form, self.__dict__, action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): sel.force_navigate("{}_dialog".format(self.type_nav), context={"dialog": self}) cfg_btn("Edit this Dialog") fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): sel.force_navigate("{}_dialog".format(self.type_nav), context={"dialog": self}) cfg_btn("Remove from the VMDB", invokes_alert=True) sel.handle_alert(cancel) def change_type(self, new_type): """Safely changes type of the dialog. It would normally mess up the navigation""" sel.force_navigate("{}_dialog".format(self.type_nav), context={"dialog": self}) cfg_btn("Edit this Dialog") self.type = new_type fill(self.form, {"type": new_type}, action=form_buttons.save) flash.assert_no_errors()
class RSSFeedWidget(Widget): form = Form(fields=[ ("title", Input("title")), ("description", Input("description")), ("active", Input("enabled")), ("type", Select("//select[@id='feed_type']")), ("feed", Select("//select[@id='rss_feed']")), ("external", ExternalRSSFeed()), ("rows", Select("//select[@id='row_count']")), ("timer", Timer()), ("visibility", visibility_obj), ]) TITLE = "RSS Feed" pretty_attrs = ['title', 'description', 'type', 'feed', 'visibility'] DETAIL_PAGE = "reports_widgets_rss_feed" def __init__(self, title, description=None, active=None, type=None, feed=None, external=None, rows=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.type = type self.feed = feed self.external = external self.rows = rows self.timer = timer self.visibility = visibility def create(self, cancel=False): sel.force_navigate("reports_widgets_rss_feed_add") fill(self.form, self.__dict__, action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): sel.force_navigate("reports_widgets_rss_feed_edit", context={"widget": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): self.go_to_detail() toolbar.select("Configuration", "Delete this Widget from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
def get_form(self, blank=False): """Gets a form for a field that already exists (by its name). Or if blank=True, get the form for a new field. Must be on the correct page before calling this. """ idx = "" if blank: row_id = "" # for new entries, id attribute has no trailing '_x' else: idx = sel.get_attribute( "//input[starts-with(@id, 'fields_name') and @value='%s']" % self.name, 'id').split("_")[-1] row_id = "_" + idx def loc(fmt, underscore=True): if blank: plural = "" else: plural = "s" return fmt % (plural, row_id if underscore else row_id.lstrip("_")) def remove(loc): """Return a callable that clicks but still allows popup dismissal""" return lambda _: sel.click(loc, wait_ajax=False) return Form(fields=[ ('name_text', Input(loc('field%s_name%s'))), ('type_select', { version.LOWEST: DHTMLSelect(loc("//div[@id='field%s_aetype_id%s']")), "5.5": AngularSelect(loc("field%s_aetype%s", underscore=False)) }), ('data_type_select', { version.LOWEST: DHTMLSelect(loc("//div[@id='field%s_datatype_id%s']")), "5.5": AngularSelect(loc("field%s_datatype%s", underscore=False)) }), ('default_value_text', Input(loc('field%s_default_value%s'))), ('display_name_text', Input(loc('field%s_display_name%s')) ), ('description_text', Input(loc('field%s_description%s')) ), ('sub_cb', Input(loc('field%s_substitution%s')) ), ('collect_text', Input(loc('field%s_collect%s'))), ('message_text', Input(loc('field%s_message%s')) ), ('on_entry_text', Input(loc('field%s_on_entry%s')) ), ('on_exit_text', Input(loc('field%s_on_exit%s'))), ('max_retries_text', Input(loc('field%s_max_retries%s')) ), ('max_time_text', Input(loc('field%s_max_time%s')) ), ('add_entry_button', "//img[@alt='Add this entry']"), ('remove_entry_button', remove("//a[(contains(@title, 'delete this') or " "contains(@confirm, 'delete field')) and " "contains(@href, 'arr_id=%s')]/img" % idx)) ])
class Role(Updateable, Pretty): form = Form(fields=[ ('name_txt', Input('name')), ('vm_restriction_select', Select("//*[@id='vm_restriction']")), ('product_features_tree', CheckboxTree("//div[@id='features_treebox']/ul")), ]) pretty_attrs = ['name', 'product_features'] def __init__(self, name=None, vm_restriction=None, product_features=None): self.name = name self.vm_restriction = vm_restriction self.product_features = product_features or [] def create(self): sel.force_navigate('cfg_accesscontrol_role_add') fill(self.form, { 'name_txt': self.name, 'vm_restriction_select': self.vm_restriction, 'product_features_tree': self.product_features }, action=form_buttons.add) flash.assert_success_message('Role "{}" was saved'.format(self.name)) def update(self, updates): sel.force_navigate("cfg_accesscontrol_role_edit", context={"role": self}) fill(self.form, { 'name_txt': updates.get('name'), 'vm_restriction_select': updates.get('vm_restriction'), 'product_features_tree': updates.get('product_features') }, action=form_buttons.save) flash.assert_success_message('Role "{}" was saved'.format( updates.get('name', self.name))) def delete(self): sel.force_navigate("cfg_accesscontrol_role_ed", context={"role": self}) tb_select('Delete this Role', invokes_alert=True) sel.handle_alert() flash.assert_success_message('Role "{}": Delete successful'.format( self.name)) def copy(self, name=None): if not name: name = self.name + "copy" sel.force_navigate("cfg_accesscontrol_role_ed", context={"role": self}) tb.select('Configuration', 'Copy this Role to a new Role') new_role = Role(name=name) fill(self.form, {'name_txt': new_role.name}, action=form_buttons.add) flash.assert_success_message('Role "{}" was saved'.format( new_role.name)) return new_role
class Timer(object): form = Form(fields=[ ("run", Select("//select[@id='timer_typ']")), ("hours", Select("//select[@id='timer_hours']")), ("days", Select("//select[@id='timer_days']")), ("weeks", Select("//select[@id='timer_weeks']")), ("months", Select("//select[@id='timer_months']")), ("time_zone", Select("//select[@id='time_zone']")), ("start_date", Calendar("miq_date_1")), ("start_hour", Select("//select[@id='start_hour']")), ("start_min", Select("//select[@id='start_min']")), ])
class CfmeRelationship(object): relationship_form = Form(fields=[( 'server_select', Select("//*[@id='server_id']")), ( 'save_button', form_buttons.save), ( 'reset_button', form_buttons.reset), ('cancel_button', form_buttons.cancel)]) def __init__(self, o): self.o = o def navigate(self): self.o.load_details() cfg_btn('Edit Management Engine Relationship') def is_relationship_set(self): return "<Not a Server>" not in self.get_relationship() def get_relationship(self): self.navigate() rel = str(self.relationship_form.server_select. all_selected_options[0].text) form_buttons.cancel() return rel def set_relationship(self, server_name, server_id, click_cancel=False): self.navigate() option = "{} ({})".format(server_name, server_id) if click_cancel: fill(self.relationship_form, {'server_select': option}, action=self.relationship_form.cancel_button) else: fill(self.relationship_form, {'server_select': option}, action=self.relationship_form.save_button) # something weird going on where changing the select doesn't POST to undim save sel.wait_for_ajax() if self.relationship_form.save_button.is_dimmed: logger.warning("Worked around dimmed save button") sel.browser().execute_script( "$j.ajax({type: 'POST', url: '/vm_infra/evm_relationship_field_changed'," " data: {'server_id':'%s'}})" % (server_id)) sel.click( form_buttons.FormButton("Save Changes", dimmed_alt="Save", force_click=True)) flash.assert_success_message( "Management Engine Relationship saved")
class Dashboard(Updateable, Pretty, Navigatable): form = Form(fields=[ ("name", Input("name")), ("title", Input("description")), ("locked", Input("locked")), ("widgets", NewerDashboardWidgetSelector("//div[@id='form_widgets_div']")), ]) pretty_attrs = ['name', 'group', 'title', 'widgets'] def __init__(self, name, group, title=None, locked=None, widgets=None, appliance=None): Navigatable.__init__(self, appliance) self.name = name self.title = title self.locked = locked self.widgets = widgets self._group = group @property def group(self): return self._group def create(self, cancel=False): navigate_to(self, 'Add') fill( self.form, { k: v for k, v in self.__dict__.iteritems() if not k.startswith("_") }, # non-private action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): navigate_to(self, 'Edit') fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): navigate_to(self, 'Details') toolbar.select("Configuration", "Delete this Dashboard from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
class Dashboard(Updateable, Pretty): form = Form(fields=[ ("name", Input("name")), ("title", Input("description")), ("locked", Input("locked")), ("widgets", { version.LOWEST: DashboardWidgetSelector("//div[@id='form_widgets_div']"), "5.5": NewerDashboardWidgetSelector("//div[@id='form_widgets_div']") }), ]) pretty_attrs = ['name', 'group', 'title', 'widgets'] def __init__(self, name, group, title=None, locked=None, widgets=None): self.name = name self.title = title self.locked = locked self.widgets = widgets self._group = group @property def group(self): return self._group def create(self, cancel=False): sel.force_navigate("reports_dashboard_add", context={"group": self._group}) fill( self.form, { k: v for k, v in self.__dict__.iteritems() if not k.startswith("_") }, # non-private action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): sel.force_navigate("reports_dashboard_edit", context={"dashboard": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): sel.force_navigate("reports_dashboard", context={"dashboard": self}) toolbar.select("Configuration", "Delete this Dashboard from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
class ReportWidget(Updateable): form = Form(fields=[ ("title", "//input[@id='title']"), ("description", "//input[@id='description']"), ("active", "//input[@id='enabled']"), ("filter", ShowingInputs( Select("//select[@id='filter_typ']"), Select("//select[@id='subfilter_typ']"), Select("//select[@id='repfilter_typ']"), min_values=3 )), # Might be abstracted out too ("columns", ShowingInputs( Select("//select[@id='chosen_pivot1']"), Select("//select[@id='chosen_pivot2']"), Select("//select[@id='chosen_pivot3']"), Select("//select[@id='chosen_pivot4']"), min_values=1 )), ("rows", Select("//select[@id='row_count']")), ("timer", Timer()), ("visibility", visibility_obj), ]) def __init__(self, title, description=None, active=None, filter=None, columns=None, rows=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.filter = filter self.columns = columns self.rows = rows self.timer = timer self.visibility = visibility def create(self, cancel=False): sel.force_navigate("reports_widgets_report_add") fill(self.form, self.__dict__, action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): sel.force_navigate("reports_widgets_report_edit", context={"widget": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): sel.force_navigate("reports_widgets_report", context={"widget": self}) toolbar.select("Configuration", "Delete this Widget from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
class Group(Updateable, Pretty): group_form = Form( fields=[ ('description_txt', Input('description')), ('role_select', Select("//*[@id='group_role']")), ]) pretty_attrs = ['description', 'role'] def __init__(self, description=None, role=None): self.description = description self.role = role def create(self): sel.force_navigate('cfg_accesscontrol_group_add') fill(self.group_form, {'description_txt': self.description, 'role_select': self.role}, action=form_buttons.add) flash.assert_success_message('Group "%s" was saved' % self.description) def update(self, updates): sel.force_navigate("cfg_accesscontrol_group_edit", context={"group": self}) fill(self.group_form, {'description_txt': updates.get('description'), 'role_select': updates.get('role')}, action=form_buttons.save) flash.assert_success_message( 'Group "%s" was saved' % updates.get('description', self.description)) def delete(self): sel.force_navigate("cfg_accesscontrol_group_ed", context={"group": self}) tb_select('Delete this Group', invokes_alert=True) sel.handle_alert() flash.assert_success_message('EVM Group "%s": Delete successful' % self.description) def edit_tags(self, tag, value): sel.force_navigate("cfg_accesscontrol_group_ed", context={"group": self}) pol_btn("Edit 'My Company' Tags for this Group", invokes_alert=True) fill(edit_tags_form, {'select_tag': tag, 'select_value': value}, action=form_buttons.save) flash.assert_success_message('Tag edits were successfully saved') def remove_tag(self, tag, value): sel.force_navigate("cfg_accesscontrol_group_ed", context={"group": self}) pol_btn("Edit 'My Company' Tags for this Group", invokes_alert=True) row = tag_table.find_row_by_cells({'category': tag, 'assigned_value': value}, partial_check=True) sel.click(row[0]) form_buttons.save() flash.assert_success_message('Tag edits were successfully saved')
def form(self): """Returns Form filled with fields. Scraps the webpage to determine the fields. Requires to be on the page """ names = [] for cell in sel.elements(self.fields): # The received text is something like u' (blabla)' so we extract 'blabla' sel.move_to_element( cell ) # This is required in order to correctly read the content names.append( re.sub(r"^[^(]*\(([^)]+)\)[^)]*$", "\\1", sel.text(cell).encode("utf-8"))) return Form(fields=[(name, InstanceFieldsRow(i)) for i, name in enumerate(names)])
class DefaultFilter(Updateable, Pretty): filter_form = Form(fields=[ ("filter_tree", CheckboxTree("//div[@id='all_views_treebox']/ul")), ]) pretty_attrs = ['name', 'filters'] def __init__(self, name=None, filters=None): self.name = name self.filters = filters or [] def update(self, updates, expect_success=True): sel.force_navigate("my_settings_default_filters", context=self) fill(self.filter_form, {'filter_tree': updates.get('filters')}, action=form_buttons.save) if expect_success: flash.assert_success_message('Default Filters saved successfully')
class MenuWidget(Widget): form = Form(fields=[ ("title", Input("title")), ("description", Input("description")), ("active", Input("enabled")), ("shortcuts", MenuShortcuts("//select[@id='add_shortcut']")), ("visibility", visibility_obj), ]) TITLE = "Menu" pretty_attrs = ['description', 'shortcuts', 'visibility'] DETAIL_PAGE = "reports_widgets_menu" def __init__(self, title, description=None, active=None, shortcuts=None, visibility=None): self.title = title self.description = description self.active = active self.shortcuts = shortcuts self.visibility = visibility def create(self, cancel=False): sel.force_navigate("reports_widgets_menu_add") fill(self.form, self.__dict__, action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): sel.force_navigate("reports_widgets_menu_edit", context={"widget": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): self.go_to_detail() toolbar.select("Configuration", "Delete this Widget from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
class CfmeRelationship(object): relationship_form = Form(fields=[( 'server_select', AngularSelect("server_id")), ( 'save_button', form_buttons.save), ( 'reset_button', form_buttons.reset), ('cancel_button', form_buttons.cancel)]) def __init__(self, o): self.o = o def navigate(self): self.o.load_details() cfg_btn('Edit Management Engine Relationship') def is_relationship_set(self): return "<Not a Server>" not in self.get_relationship() def get_relationship(self): self.navigate() rel = str(self.relationship_form.server_select. all_selected_options[0].text) form_buttons.cancel() return rel def set_relationship(self, server_name, server_id, click_cancel=False): self.navigate() option = "{} ({})".format(server_name, server_id) if click_cancel: fill(self.relationship_form, {'server_select': option}, action=self.relationship_form.cancel_button) else: fill(self.relationship_form, {'server_select': option}) sel.click( form_buttons.FormButton("Save Changes", dimmed_alt="Save", force_click=True)) flash.assert_success_message( "Management Engine Relationship saved")
class DefaultFilter(Updateable, Pretty, Navigatable): filter_form = Form(fields=[ ("filter_tree", { version.LOWEST: CheckboxTree("//div[@id='all_views_treebox']/ul"), '5.7': BootstrapTreeview('df_treebox') }), ]) pretty_attrs = ['name', 'filters'] def __init__(self, name=None, filters=None, appliance=None): Navigatable.__init__(self, appliance=appliance) self.name = name self.filters = filters or [] def update(self, updates, expect_success=True): navigate_to(self, 'All') fill(self.filter_form, {'filter_tree': updates.get('filters')}, action=form_buttons.save) if expect_success: flash.assert_success_message('Default Filters saved successfully')
class Role(Updateable): form = Form(fields=[ ('name_txt', "//*[@id='name']"), ('vm_restriction_select', Select("//*[@id='vm_restriction']")), ('product_features_tree', CheckboxTree("//div[@id='features_treebox']/ul")), ]) def __init__(self, name=None, vm_restriction=None, product_features=None): self.name = name self.vm_restriction = vm_restriction self.product_features = product_features or [] def create(self): sel.force_navigate('cfg_accesscontrol_role_add') fill(self.form, { 'name_txt': self.name, 'vm_restriction_select': self.vm_restriction, 'product_features_tree': self.product_features }, action=form_buttons.add) flash.assert_success_message('Role "%s" was saved' % self.name) def update(self, updates): sel.force_navigate("cfg_accesscontrol_role_edit", context=self) fill(self.form, { 'name_txt': updates.get('name'), 'vm_restriction_select': updates.get('vm_restriction'), 'product_features_tree': updates.get('product_features') }, action=form_buttons.save) flash.assert_success_message('Role "%s" was saved' % updates.get('name', self.name)) def delete(self): sel.force_navigate("cfg_accesscontrol_role_ed", context=self) tb_select('Delete this Role', invokes_alert=True) sel.handle_alert() flash.assert_success_message('Role "%s": Delete successful' % self.name)
class ReportWidget(Widget): form = Form(fields=[ ("title", Input("title")), ("description", Input("description")), ("active", Input("enabled")), ("filter", ShowingInputs(Select("//select[@id='filter_typ']"), Select("//select[@id='subfilter_typ']"), Select("//select[@id='repfilter_typ']"), min_values=3)), # Might be abstracted out too ("columns", ShowingInputs(Select("//select[@id='chosen_pivot1']"), Select("//select[@id='chosen_pivot2']"), Select("//select[@id='chosen_pivot3']"), Select("//select[@id='chosen_pivot4']"), min_values=1)), ("rows", Select("//select[@id='row_count']")), ("timer", Timer()), ("visibility", visibility_obj), ]) TITLE = "Reports" pretty_attrs = ['description', 'filter', 'visibility'] def __init__(self, title, description=None, active=None, filter=None, columns=None, rows=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.filter = filter self.columns = columns self.rows = rows self.timer = timer self.visibility = visibility
class MenuWidget(Widget): form = Form(fields=[ ("title", Input("title")), ("description", Input("description")), ("active", Input("enabled")), ("shortcuts", MenuShortcuts("add_shortcut")), ("visibility", visibility_obj), ]) TITLE = "Menus" pretty_attrs = ['description', 'shortcuts', 'visibility'] def __init__(self, title, description=None, active=None, shortcuts=None, visibility=None): self.title = title self.description = description self.active = active self.shortcuts = shortcuts self.visibility = visibility
class DefaultDashboard(Updateable): form = Form(fields=[ ("title", "//input[@id='description']"), ("locked", "//input[@id='locked']"), ("widgets", DashboardWidgetSelector("//div[@id='form_widgets_div']")), ]) def __init__(self, title=None, locked=None, widgets=None): self.locked = locked self.widgets = widgets def update(self, updates): sel.force_navigate("reports_default_dashboard_edit") fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): sel.force_navigate("reports_default_dashboard") toolbar.select("Configuration", "Delete this Dashboard from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
class DefaultDashboard(Updateable, Pretty): form = Form(fields=[ ("title", Input("description")), ("locked", Input("locked")), ("widgets", { version.LOWEST: DashboardWidgetSelector("//div[@id='form_widgets_div']"), "5.5": NewerDashboardWidgetSelector("//div[@id='form_widgets_div']") }), ]) reset_button = "//*[@title='Reset Dashboard Widgets to the defaults']" pretty_attrs = ['title', 'widgets'] def __init__(self, title=None, locked=None, widgets=None): self.locked = locked self.widgets = widgets def update(self, updates): sel.force_navigate("reports_default_dashboard_edit") fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): sel.force_navigate("reports_default_dashboard") toolbar.select("Configuration", "Delete this Dashboard from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors() @classmethod def reset_widgets(cls, cancel=False): sel.force_navigate("dashboard") sel.click(cls.reset_button, wait_ajax=False) sel.handle_alert(cancel) flash.assert_no_errors()
class Group(Updateable): group_form = Form(fields=[ ('description_txt', "//*[@id='description']"), ('role_select', Select("//*[@id='group_role']")), ]) def __init__(self, description=None, role=None): self.description = description self.role = role def create(self): sel.force_navigate('cfg_accesscontrol_group_add') fill(self.group_form, { 'description_txt': self.description, 'role_select': self.role }, action=form_buttons.add) flash.assert_success_message('Group "%s" was saved' % self.description) def update(self, updates): sel.force_navigate("cfg_accesscontrol_group_edit", context=self) fill(self.group_form, { 'description_txt': updates.get('description'), 'role_select': updates.get('role') }, action=form_buttons.save) flash.assert_success_message( 'Group "%s" was saved' % updates.get('description', self.description)) def delete(self): sel.force_navigate("cfg_accesscontrol_group_ed", context=self) tb_select('Delete this Group', invokes_alert=True) sel.handle_alert() flash.assert_success_message('EVM Group "%s": Delete successful' % self.description)
class Schedule(Updateable): """Represents a schedule in Intelligence/Reports/Schedules. Args: name: Schedule name. description: Schedule description. filter: 3-tuple with filter selection (see the UI). active: Whether is this schedule active. run: Specifies how often this schedule runs. It can be either string "Once", or a tuple, which maps to the two selects in UI ("Hourly", "Every hour")... time_zone: Specify time zone. start_date: Specify the start date. start_time: Specify the start time either as a string ("0:15") or tuple ("0", "15") send_email: If specifies, turns on e-mail sending. Can be string, or list or set. """ form = Form(fields=[ ("name", "//input[@id='name']"), ("description", "//input[@id='description']"), ("active", "//input[@id='enabled']"), ("filter", ShowingInputs( Select("//select[@id='filter_typ']"), Select("//select[@id='subfilter_typ']"), Select("//select[@id='repfilter_typ']"), min_values=3 )), ("timer", Timer()), ("send_email", "//input[@id='send_email_cb']"), ("emails", EmailSelectForm()) ]) _run_mapping = { "Once": None, "Hourly": "run_hours", "Daily": "run_days", "Weekly": "run_weekly", "Monthly": "run_months" } info_block = InfoBlock("detail") def __init__( self, name, description, filter, active=None, timer=None, send_email=None): self.name = name self.description = description self.filter = filter self.active = active self.timer = timer self.send_email = send_email @property def exists(self): schedules = cfmedb["miq_schedules"] return cfmedb.session\ .query(schedules.name)\ .filter(schedules.name == self.name)\ .count() > 0 def _fill(self, action): fill( self.form, self._create_fill_dict(), action=action ) def create(self, cancel=False): sel.force_navigate("schedule_add") self._fill(form_buttons.add if not cancel else form_buttons.cancel) flash.assert_no_errors() assert self.exists, "Schedule does not exist!" def update(self, updates): sel.force_navigate("schedule_edit", context={"schedule": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() assert self.exists, "Schedule does not exist!" def delete(self, cancel=False): sel.force_navigate("schedule", context={"schedule": self}) cfg_btn("Delete this Schedule from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors() assert not self.exists, "Schedule does not exist!" def table_item(self, item): """Works both up- and downstream. I think this should be incorporated into InfoBlock somehow. Currently there is the fieldset issue. """ return "//td[preceding-sibling::td[contains(@class, 'key') and .='{}']]".format(item) def queue(self, wait_for_finish=False): """Queue this schedule. Args: wait_for_finish: If True, then this function blocks until the action is finished. """ if not self.exists: self.create() sel.force_navigate("schedule", context={"schedule": self}) last_run = sel.text(self.table_item("Last Run Time")).strip() cfg_btn("Queue up this Schedule to run now") flash.assert_no_errors() if wait_for_finish: wait_for( lambda: sel.text(self.table_item("Last Run Time")).strip() != last_run, delay=2, fail_func=lambda: toolbar.select("Reload current display"), message="wait for report queue finish" ) def _create_fill_dict(self): """Handle the values, create dictionary for form""" # Simple values come fields = { "name": self.name, "description": self.description, "active": self.active, "filter": self.filter, "timer": self.timer, } # Send e-mail if self.send_email is not None: fields["send_email"] = True fields["emails"] = self.send_email return fields # Methods for all schedules @classmethod def _select_schedules(cls, schedules): """Select schedules in the table. Args: schedules: Schedules to select. Raises: :py:class:`NameError` when some of the schedules were not found. """ sel.force_navigate("schedules") failed_selections = [] for schedule in schedules: if isinstance(schedule, cls): name = schedule.name else: name = str(schedule) if not schedules_table.select_row("Name", name): failed_selections.append(name) if failed_selections: raise NameError("These schedules were not found: {}.".format( ", ".join(failed_selections) )) @classmethod def _action_on_schedules(cls, action, schedules, cancel=None): """Select schedules and perform an action on them Args: action: Action in Configuration to perform. schedules: List of schedules. cancel: If specified, the nalert is expected after clicking on action and value of the variable specifies handling behaviour. Raises: :py:class:`NameError` when some of the schedules were not found. """ cls._select_schedules(schedules) if cancel is None: cfg_btn(action) else: cfg_btn(action, invokes_alert=True) sel.handle_alert(bool(cancel)) flash.assert_no_errors() @classmethod def enable_schedules(cls, *schedules): """Select and enable specified schedules. Args: *schedules: Schedules to enable. Can be objects or strings. Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules("Enable the selected Schedules", schedules) @classmethod def disable_schedules(cls, *schedules): """Select and disable specified schedules. Args: *schedules: Schedules to disable. Can be objects or strings. Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules("Disable the selected Schedules", schedules) @classmethod def queue_schedules(cls, *schedules): """Select and queue specified schedules. Args: *schedules: Schedules to queue. Can be objects or strings. Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules("Queue up selected Schedules to run now", schedules) @classmethod def delete_schedules(cls, *schedules, **kwargs): """Select and delete specified schedules from VMDB. Args: *schedules: Schedules to delete. Can be objects or strings. Keywords: cancel: Whether to cancel the deletion (Default: False) Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules( "Delete the selected Schedules from the VMDB", schedules, kwargs.get("cancel", False) )