def f(context): # Here it also can have long spinners with sel.ajax_timeout(90): toolbar.select('Lifecycle', tb_item) provider = context['provider'] template_name = context['template_name'] template_select_form.template_table._update_cache() template = template_select_form.template_table.find_row_by_cells({ 'Name': template_name, 'Provider': provider if isinstance(provider, basestring) else provider.name }) if template: sel.click(template) # In order to mitigate the sometimes very long spinner timeout, raise the timeout with sel.ajax_timeout(90): if current_version() < "5.4": sel.click(submit_button) else: sel.click( form_buttons.FormButton("Continue", force_click=True)) else: raise TemplateNotFound( 'Unable to find template "{}" for provider "{}"'.format( template_name, provider.key))
def select_provision_image(template_name, provider): """ Navigate to provision and select the template+click continue, leaving UI on provision form :param template_name: The image/template name to select :param provider: Provider where the image/template resides :return: none """ logger.debug( 'Selecting an image {} from provider {} for provisioning'.format( template_name, provider.name)) navigate_to(Instance, 'Provision') template = image_select_form.template_table.find_row_by_cells({ 'Name': template_name, 'Provider': provider.name }) if template: sel.click(template) # In order to mitigate the sometimes very long spinner timeout, raise the timeout with sel.ajax_timeout(90): sel.click(form_buttons.FormButton("Continue", force_click=True)) else: raise TemplateNotFound( 'Unable to find template "{}" for provider "{}"'.format( template_name, provider.key))
class CloudProvider(Pretty, CloudInfraProvider): """ Abstract model of a cloud provider in cfme. See EC2Provider or OpenStackProvider. Args: name: Name of the provider. details: a details record (see EC2Details, OpenStackDetails inner class). credentials (:py:class:`Credential`): see Credential class. key: The CFME key of the provider in the yaml. Usage: myprov = EC2Provider(name='foo', region='us-west-1', credentials=Credential(principal='admin', secret='foobar')) myprov.create() """ provider_types = {} in_version = (version.LOWEST, version.LATEST) category = "cloud" pretty_attrs = ['name', 'credentials', 'zone', 'key'] STATS_TO_MATCH = ['num_template', 'num_vm'] string_name = "Cloud" page_name = "clouds" templates_destination_name = "Images" quad_name = "cloud_prov" vm_name = "Instances" template_name = "Images" _properties_region = prop_region # This will get resolved in common to a real form db_types = ["CloudManager"] # Specific Add button add_provider_button = deferred_verpick({ version.LOWEST: form_buttons.FormButton("Add this Cloud Provider"), '5.5': form_buttons.add }) save_button = deferred_verpick({ version.LOWEST: form_buttons.save, '5.5': form_buttons.angular_save }) def __init__(self, name=None, credentials=None, zone=None, key=None, appliance=None): Navigatable.__init__(self, appliance=appliance) if not credentials: credentials = {} self.name = name self.credentials = credentials self.zone = zone self.key = key def _form_mapping(self, create=None, **kwargs): return {'name_text': kwargs.get('name')}
class Provider(Pretty, CloudInfraProvider): """ Abstract model of a cloud provider in cfme. See EC2Provider or OpenStackProvider. Args: name: Name of the provider. details: a details record (see EC2Details, OpenStackDetails inner class). credentials (Credential): see Credential inner class. key: The CFME key of the provider in the yaml. Usage: myprov = EC2Provider(name='foo', region='us-west-1', credentials=Provider.Credential(principal='admin', secret='foobar')) myprov.create() """ pretty_attrs = ['name', 'credentials', 'zone', 'key'] STATS_TO_MATCH = ['num_template', 'num_vm'] string_name = "Cloud" page_name = "clouds" instances_page_name = "clouds_instances_by_provider" templates_page_name = "clouds_images_by_provider" quad_name = "cloud_prov" vm_name = "Instances" template_name = "Images" properties_form = properties_form # Specific Add button add_provider_button = deferred_verpick( {version.LOWEST: form_buttons.FormButton("Add this Cloud Provider"), '5.5': form_buttons.FormButton("Add")}) save_button = deferred_verpick( {version.LOWEST: form_buttons.FormButton("Save Changes"), '5.5': form_buttons.FormButton("Save changes")}) def __init__(self, name=None, credentials=None, zone=None, key=None): if not credentials: credentials = {} self.name = name self.credentials = credentials self.zone = zone self.key = key def _form_mapping(self, create=None, **kwargs): return {'name_text': kwargs.get('name')}
class MiddlewareProvider(BaseProvider): in_version = ('5.7', version.LATEST) category = "middleware" page_name = 'middleware' string_name = 'Middleware' provider_types = {} STATS_TO_MATCH = [] property_tuples = [] detail_page_suffix = 'provider_detail' edit_page_suffix = 'provider_edit_detail' refresh_text = "Refresh items and relationships" quad_name = 'middleware' _properties_region = prop_region # This will get resolved in common to a real form add_provider_button = form_buttons.FormButton("Add") save_button = form_buttons.FormButton("Save") taggable_type = 'ExtManagementSystem' db_types = ["MiddlewareManager"]
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")
def step(self, *args, **kwargs): lcl_btn("Provision VMs") # choosing template and going further template_select_form.template_table._update_cache() template = template_select_form.template_table.find_row_by_cells({ 'Name': self.obj.template_name, 'Provider': self.obj.provider.name }) if template: sel.click(template) # In order to mitigate the sometimes very long spinner timeout, raise the timeout with sel.ajax_timeout(90): sel.click(form_buttons.FormButton("Continue", force_click=True)) else: raise TemplateNotFound('Unable to find template "{}" for provider "{}"'.format( self.obj.template_name, self.obj.provider.key))
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 ContainersProvider(BaseProvider, Pretty): PLURAL = 'Providers' provider_types = {} in_version = ('5.5', version.LATEST) category = "container" pretty_attrs = ['name', 'key', 'zone'] STATS_TO_MATCH = [ 'num_project', 'num_service', 'num_replication_controller', 'num_pod', 'num_node', 'num_image_registry', 'num_container' ] # TODO add 'num_volume' string_name = "Containers" page_name = "containers" detail_page_suffix = 'provider_detail' edit_page_suffix = 'provider_edit_detail' refresh_text = "Refresh items and relationships" quad_name = None db_types = ["ContainerManager"] _properties_region = prop_region # This will get resolved in common to a real form add_provider_button = deferred_verpick({ version.LOWEST: form_buttons.FormButton("Add this Containers Provider"), '5.6': form_buttons.add }) save_button = deferred_verpick({ version.LOWEST: form_buttons.save, '5.6': form_buttons.angular_save }) def __init__(self, name=None, credentials=None, key=None, zone=None, hawkular=None, hostname=None, api_port=None, sec_protocol=None, hawkular_sec_protocol=None, hawkular_hostname=None, hawkular_api_port=None, provider_data=None, appliance=None): Navigatable.__init__(self, appliance=appliance) if not credentials: credentials = {} self.name = name self.credentials = credentials self.key = key self.zone = zone self.hawkular = hawkular self.hostname = hostname self.api_port = api_port self.sec_protocol = sec_protocol self.hawkular_sec_protocol = hawkular_sec_protocol self.hawkular_hostname = hawkular_hostname self.hawkular_api_port = hawkular_api_port self.provider_data = provider_data def _on_detail_page(self): """ Returns ``True`` if on the providers detail page, ``False`` if not.""" ensure_browser_open() return sel.is_displayed( '//div//h1[contains(., "{} (Summary)")]'.format(self.name)) def load_details(self, refresh=False): navigate_to(self, 'Details') if refresh: tb.refresh() def get_detail(self, *ident): """ Gets details from the details infoblock Args: *ident: An InfoBlock title, followed by the Key name, e.g. "Relationships", "Images" Returns: A string representing the contents of the InfoBlock's value. """ navigate_to(self, 'Details') return details_page.infoblock.text(*ident) @variable(alias='db') def num_project(self): return self._num_db_generic('container_projects') @num_project.variant('ui') def num_project_ui(self): return int(self.get_detail("Relationships", "Projects")) @variable(alias='db') def num_service(self): return self._num_db_generic('container_services') @num_service.variant('ui') def num_service_ui(self): if self.appliance.version < "5.7": name = "Services" else: name = "Container Services" return int(self.get_detail("Relationships", name)) @variable(alias='db') def num_replication_controller(self): return self._num_db_generic('container_replicators') @num_replication_controller.variant('ui') def num_replication_controller_ui(self): return int(self.get_detail("Relationships", "Replicators")) @variable(alias='db') def num_container_group(self): return self._num_db_generic('container_groups') @num_container_group.variant('ui') def num_container_group_ui(self): return int(self.get_detail("Relationships", "Pods")) @variable(alias='db') def num_pod(self): # potato tomato return self.num_container_group() @num_pod.variant('ui') def num_pod_ui(self): # potato tomato return self.num_container_group(method='ui') @variable(alias='db') def num_node(self): return self._num_db_generic('container_nodes') @num_node.variant('ui') def num_node_ui(self): return int(self.get_detail("Relationships", "Nodes")) @variable(alias='db') def num_container(self): # Containers are linked to providers through container definitions and then through pods res = self.appliance.db.client.engine.execute( "SELECT count(*) " "FROM ext_management_systems, container_groups, container_definitions, containers " "WHERE containers.container_definition_id=container_definitions.id " "AND container_definitions.container_group_id=container_groups.id " "AND container_groups.ems_id=ext_management_systems.id " "AND ext_management_systems.name='{}'".format(self.name)) return int(res.first()[0]) @num_container.variant('ui') def num_container_ui(self): return int(self.get_detail("Relationships", "Containers")) @variable(alias='db') def num_image(self): return self._num_db_generic('container_images') @num_image.variant('ui') def num_image_ui(self): if self.appliance.version < "5.7": name = "Images" else: name = "Container Images" return int(self.get_detail("Relationships", name)) @variable(alias='db') def num_image_registry(self): return self._num_db_generic('container_image_registries') @num_image_registry.variant('ui') def num_image_registry_ui(self): return int(self.get_detail("Relationships", "Image Registries")) def pods_per_ready_status(self): """Grabing the Container Statuses Summary of the pods from API""" # TODO: Add later this logic to wrapanapi entities = self.mgmt.api.get('pod')[1]['items'] out = {} for entity_j in entities: out[entity_j['metadata']['name']] = { condition['type']: eval_strings([condition['status']]).pop() for condition in entity_j['status'].get('conditions', []) } return out
class Genealogy(object): """Class, representing genealogy of an infra object with possibility of data retrieval and comparison. Args: o: The :py:class:`Vm` or :py:class:`Template` object. """ genealogy_tree = deferred_verpick({ version.LOWEST: CheckboxTree("//div[@id='genealogy_treebox']/ul"), 5.7: BootstrapTreeview('genealogy_treebox') }) section_comparison_tree = CheckboxTree( "//div[@id='all_sections_treebox']/div/table") apply_button = form_buttons.FormButton("Apply sections") mode_mapping = { "exists": "Exists Mode", "details": "Details Mode", } attr_mapping = { "all": "All Attributes", "different": "Attributes with different values", "same": "Attributes with same values", } def __init__(self, o): self.o = o def navigate(self): self.o.load_details() sel.click(InfoBlock.element("Relationships", "Genealogy")) def compare(self, *objects, **kwargs): """Compares two or more objects in the genealogy. Args: *objects: :py:class:`Vm` or :py:class:`Template` or :py:class:`str` with name. Keywords: sections: Which sections to compare. attributes: `all`, `different` or `same`. Default: `all`. mode: `exists` or `details`. Default: `exists`.""" sections = kwargs.get("sections") attributes = kwargs.get("attributes", "all").lower() mode = kwargs.get("mode", "exists").lower() assert len(objects) >= 2, "You must specify at least two objects" objects = map(lambda o: o.name if isinstance(o, (Vm, Template)) else o, objects) self.navigate() for obj in objects: if not isinstance(obj, list): path = self.genealogy_tree.find_path_to(obj) self.genealogy_tree.check_node(*path) toolbar.select("Compare selected VMs") # COMPARE PAGE flash.assert_no_errors() if sections is not None: map(lambda path: self.section_comparison_tree.check_node(*path), sections) sel.click(self.apply_button) flash.assert_no_errors() # Set requested attributes sets toolbar.select(self.attr_mapping[attributes]) # Set the requested mode toolbar.select(self.mode_mapping[mode]) @property def tree(self): """Returns contents of the tree with genealogy""" self.navigate() return self.genealogy_tree.read_contents() @property def ancestors(self): """Returns list of ancestors of the represented object.""" self.navigate() path = self.genealogy_tree.find_path_to( re.compile(r"^.*?\(Selected\)$")) if not path: raise ValueError("Something wrong happened, path not found!") processed_path = [] for step in path[:-1]: # We will remove the (parent) and (Selected) suffixes processed_path.append( re.sub(r"\s*(?:\(Current\)|\(Parent\))$", "", step)) return processed_path
class Host(Updateable, Pretty, Navigatable, PolicyProfileAssignable): """ Model of an infrastructure host in cfme. Args: name: Name of the host. hostname: Hostname of the host. ip_address: The IP address as a string. custom_ident: The custom identifiter. host_platform: Included but appears unused in CFME at the moment. ipmi_address: The IPMI address. mac_address: The mac address of the system. credentials (:py:class:`Credential`): see Credential inner class. ipmi_credentials (:py:class:`Credential`): see Credential inner class. Usage: myhost = Host(name='vmware', credentials=Provider.Credential(principal='admin', secret='foobar')) myhost.create() """ pretty_attrs = ['name', 'hostname', 'ip_address', 'custom_ident'] forced_saved = deferred_verpick({ version.LOWEST: form_buttons.FormButton("Save Changes", dimmed_alt="Save", force_click=True), '5.5': form_buttons.FormButton("Save changes", dimmed_alt="Save changes", force_click=True) }) def __init__(self, name=None, hostname=None, ip_address=None, custom_ident=None, host_platform=None, ipmi_address=None, mac_address=None, credentials=None, ipmi_credentials=None, interface_type='lan', provider=None, appliance=None): Navigatable.__init__(self, appliance=appliance) self.name = name self.quad_name = 'host' self.hostname = hostname self.ip_address = ip_address self.custom_ident = custom_ident self.host_platform = host_platform self.ipmi_address = ipmi_address self.mac_address = mac_address self.credentials = credentials self.ipmi_credentials = ipmi_credentials self.interface_type = interface_type self.db_id = None self.provider = provider def _form_mapping(self, create=None, **kwargs): return { 'name_text': kwargs.get('name'), 'hostname_text': kwargs.get('hostname'), 'ipaddress_text': kwargs.get('ip_address'), 'custom_ident_text': kwargs.get('custom_ident'), 'host_platform': kwargs.get('host_platform'), 'ipmi_address_text': kwargs.get('ipmi_address'), 'mac_address_text': kwargs.get('mac_address') } class Credential(cfme.Credential, Updateable): """Provider credentials Args: **kwargs: If using IPMI type credential, ipmi = True""" def __init__(self, **kwargs): super(Host.Credential, self).__init__(**kwargs) self.ipmi = kwargs.get('ipmi') def _submit(self, cancel, submit_button): if cancel: sel.click(form_buttons.cancel) # sel.wait_for_element(page.configuration_btn) else: sel.click(submit_button) flash.assert_no_errors() def create(self, cancel=False, validate_credentials=False): """ Creates a host in the UI Args: cancel (boolean): Whether to cancel out of the creation. The cancel is done after all the information present in the Host has been filled in the UI. validate_credentials (boolean): Whether to validate credentials - if True and the credentials are invalid, an error will be raised. """ navigate_to(self, 'Add') fill(properties_form, self._form_mapping(True, **self.__dict__)) fill(credential_form, self.credentials, validate=validate_credentials) fill(credential_form, self.ipmi_credentials, validate=validate_credentials) self._submit(cancel, host_add_btn) def update(self, updates, cancel=False, validate_credentials=False): """ Updates a host in the UI. Better to use utils.update.update context manager than call this directly. Args: updates (dict): fields that are changing. cancel (boolean): whether to cancel out of the update. """ navigate_to(self, 'Edit') change_stored_password() fill(credential_form, updates.get('credentials', None), validate=validate_credentials) logger.debug("Trying to save update for host with id: " + str(self.get_db_id)) self._submit(cancel, self.forced_saved) def delete(self, cancel=True): """ Deletes a host from CFME Args: cancel: Whether to cancel the deletion, defaults to True """ navigate_to(self, 'Details') if self.appliance.version >= '5.7': btn_name = "Remove item" else: btn_name = "Remove from the VMDB" cfg_btn(btn_name, invokes_alert=True) sel.handle_alert(cancel=cancel) def load_details(self, refresh=False): """To be compatible with the Taggable and PolicyProfileAssignable mixins.""" navigate_to(self, 'Details') if refresh: sel.refresh() def execute_button(self, button_group, button, cancel=True): navigate_to(self, 'Details') host_btn = partial(tb.select, button_group) host_btn(button, invokes_alert=True) sel.click(form_buttons.submit) flash.assert_success_message("Order Request was Submitted") host_btn(button, invokes_alert=True) sel.click(form_buttons.cancel) flash.assert_success_message("Service Order was cancelled by the user") def power_on(self): navigate_to(self, 'Details') pow_btn('Power On', invokes_alert=True) sel.handle_alert() def power_off(self): navigate_to(self, 'Details') pow_btn('Power Off', invokes_alert=True) sel.handle_alert() def get_power_state(self): return self.get_detail('Properties', 'Power State') # return str(find_quadicon(self.name, do_not_navigate=True).state) # return state.split()[1] def refresh(self, cancel=False): tb.select("Configuration", "Refresh Relationships and Power States", invokes_alert=True) sel.handle_alert(cancel=cancel) # TODO remove provider_crud when issue #4137 fixed,host linked with provider def wait_for_host_state_change(self, desired_state, timeout=300, provider_crud=None): """Wait for Host to come to desired state. This function waits just the needed amount of time thanks to wait_for. Args: self: self desired_state: 'on' or 'off' timeout: Specify amount of time (in seconds) to wait until TimedOutError is raised provider_crud: provider object where vm resides on (optional) """ def _looking_for_state_change(): tb.refresh() return 'currentstate-' + desired_state in find_quadicon( self.name, do_not_navigate=False).state navigate_and_select_all_hosts(self.name, provider_crud) return wait_for(_looking_for_state_change, num_sec=timeout) def get_ipmi(self): return IPMI(hostname=self.ipmi_address, username=self.ipmi_credentials.principal, password=self.ipmi_credentials.secret, interface_type=self.interface_type) def get_detail(self, *ident): """ Gets details from the details infoblock The function first ensures that we are on the detail page for the specific host. Args: *ident: An InfoBlock title, followed by the Key name, e.g. "Relationships", "Images" Returns: A string representing the contents of the InfoBlock's value. """ navigate_to(self, 'Details') return details_page.infoblock.text(*ident) @property def exists(self): navigate_to(self, 'All') for page in paginator.pages(): if sel.is_displayed(Quadicon(self.name, 'host')): return True else: return False @property def has_valid_credentials(self): """ Check if host has valid credentials saved Returns: ``True`` if credentials are saved and valid; ``False`` otherwise """ navigate_to(self, 'All') quad = Quadicon(self.name, 'host') return 'checkmark' in quad.creds def get_datastores(self): """ Gets list of all datastores used by this host""" navigate_to(self, 'Details') list_acc.select('Relationships', 'Datastores', by_title=False, partial=True) return [q.name for q in Quadicon.all("datastore")] @property def get_db_id(self): if self.db_id is None: self.db_id = self.appliance.host_id(self.name) return self.db_id else: return self.db_id def run_smartstate_analysis(self): """ Runs smartstate analysis on this host Note: The host must have valid credentials already set up for this to work. """ navigate_to(self, 'Details') tb.select('Configuration', 'Perform SmartState Analysis', invokes_alert=True) sel.handle_alert() flash.assert_message_contain( '"{}": Analysis successfully initiated'.format(self.name)) def check_compliance(self, timeout=240): """Initiates compliance check and waits for it to finish.""" navigate_to(self, 'Details') original_state = self.compliance_status tb.select('Policy', 'Check Compliance of Last Known Configuration', invokes_alert=True) sel.handle_alert() flash.assert_no_errors() wait_for(lambda: self.compliance_status != original_state, num_sec=timeout, delay=5, message="compliance of {} checked".format(self.name)) @property def compliance_status(self): """Returns the title of the compliance infoblock. The title contains datetime so it can be compared. Returns: :py:class:`NoneType` if no title is present (no compliance checks before), otherwise str """ sel.refresh() return self.get_detail('Compliance', 'Status') @property def is_compliant(self): """Check if the Host is compliant Returns: :py:class:`bool` """ text = self.compliance_status.strip().lower() if text.startswith("non-compliant"): return False elif text.startswith("compliant"): return True else: raise ValueError( "{} is not a known state for compliance".format(text)) def equal_drift_results(self, row_text, section, *indexes): """ Compares drift analysis results of a row specified by it's title text Args: row_text: Title text of the row to compare section: Accordion section where the change happened; this section must be activated indexes: Indexes of results to compare starting with 0 for first row (latest result). Compares all available drifts, if left empty (default). Note: There have to be at least 2 drift results available for this to work. Returns: ``True`` if equal, ``False`` otherwise. """ # mark by indexes or mark all navigate_to(self, 'Details') list_acc.select( 'Relationships', version.pick({ version.LOWEST: 'Show host drift history', '5.4': 'Show Host drift history' })) if indexes: drift_table.select_rows_by_indexes(*indexes) else: # We can't compare more than 10 drift results at once # so when selecting all, we have to limit it to the latest 10 if len(list(drift_table.rows())) > 10: drift_table.select_rows_by_indexes(*range(0, 10)) else: drift_table.select_all() tb.select("Select up to 10 timestamps for Drift Analysis") # Make sure the section we need is active/open sec_loc_map = { 'Properties': 'Properties', 'Security': 'Security', 'Configuration': 'Configuration', 'My Company Tags': 'Categories' } active_sec_loc = "//div[@id='all_sections_treebox']//li[contains(@id, 'group_{}')]"\ "/span[contains(@class, 'dynatree-selected')]".format(sec_loc_map[section]) sec_checkbox_loc = "//div[@id='all_sections_treebox']//li[contains(@id, 'group_{}')]"\ "//span[contains(@class, 'dynatree-checkbox')]".format(sec_loc_map[section]) sec_apply_btn = "//div[@id='accordion']/a[contains(normalize-space(text()), 'Apply')]" # If the section is not active yet, activate it if not sel.is_displayed(active_sec_loc): sel.click(sec_checkbox_loc) sel.click(sec_apply_btn) if not tb.is_active("All attributes"): tb.select("All attributes") d_grid = DriftGrid() if any( d_grid.cell_indicates_change(row_text, i) for i in range(0, len(indexes))): return False return True def tag(self, tag, **kwargs): """Tags the system by given tag""" navigate_to(self, 'Details') mixins.add_tag(tag, **kwargs) def untag(self, tag): """Removes the selected tag off the system""" navigate_to(self, 'Details') mixins.remove_tag(tag)
class HawkularProvider(MiddlewareBase, TopologyMixin, BaseProvider): """ HawkularProvider class holds provider data. Used to perform actions on hawkular provider page Args: name: Name of the provider hostname: Hostname/IP of the provider port: http/https port of hawkular provider credentials: see Credential inner class. key: The CFME key of the provider in the yaml. db_id: database row id of provider Usage: myprov = HawkularProvider(name='foo', hostname='localhost', port=8080, credentials=Provider.Credential(principal='admin', secret='foobar'))) myprov.create() myprov.num_deployment(method="ui") """ STATS_TO_MATCH = ['num_server', 'num_deployment', 'num_datasource'] property_tuples = [('name', 'name'), ('hostname', 'host_name'), ('port', 'port'), ('provider_type', 'type')] type_tclass = "middleware" type_name = "hawkular" mgmt_class = Hawkular page_name = 'middleware' string_name = 'Middleware' detail_page_suffix = 'provider_detail' edit_page_suffix = 'provider_edit_detail' refresh_text = "Refresh items and relationships" quad_name = None _properties_form = properties_form add_provider_button = form_buttons.FormButton( "Add this Middleware Provider") save_button = form_buttons.FormButton("Save Changes") taggable_type = 'ExtManagementSystem' def __init__(self, name=None, hostname=None, port=None, credentials=None, key=None, **kwargs): self.name = name self.hostname = hostname self.port = port self.provider_type = 'Hawkular' if not credentials: credentials = {} self.credentials = credentials self.key = key self.db_id = kwargs['db_id'] if 'db_id' in kwargs else None def _form_mapping(self, create=None, **kwargs): return { 'name_text': kwargs.get('name'), 'type_select': create and 'Hawkular', 'hostname_text': kwargs.get('hostname'), 'port_text': kwargs.get('port') } @variable(alias='db') def num_deployment(self): return self._num_db_generic('middleware_deployments') @num_deployment.variant('ui') def num_deployment_ui(self, reload_data=True): if reload_data: self.summary.reload() return self.summary.relationships.middleware_deployments.value @variable(alias='db') def num_server(self): return self._num_db_generic('middleware_servers') @num_server.variant('ui') def num_server_ui(self, reload_data=True): if reload_data: self.summary.reload() return self.summary.relationships.middleware_servers.value @variable(alias='db') def num_datasource(self): return self._num_db_generic('middleware_datasources') @num_datasource.variant('ui') def num_datasource_ui(self, reload_data=True): if reload_data: self.summary.reload() return self.summary.relationships.middleware_datasources.value @variable(alias='ui') def is_refreshed(self, reload_data=True): if reload_data: self.summary.reload() if re.match('Success.*Minute.*Ago', self.summary.status.last_refresh.text_value): return True else: return False @is_refreshed.variant('db') def is_refreshed_db(self): ems = cfmedb()['ext_management_systems'] dates = cfmedb().session.query( ems.created_on, ems.updated_on).filter(ems.name == self.name).first() return dates.updated_on > dates.created_on @classmethod def download(cls, extension): _get_providers_page() download(extension) def load_details(self, refresh=False): """Call super class `load_details` and load `db_id` if not set""" BaseProvider.load_details(self, refresh=refresh) if not self.db_id or refresh: tmp_provider = _db_select_query( name=self.name, type='ManageIQ::Providers::Hawkular::MiddlewareManager').first( ) self.db_id = tmp_provider.id def load_topology_page(self): self.summary.reload() self.summary.overview.topology.click() @staticmethod def configloader(prov_config, prov_key): credentials_key = prov_config['credentials'] credentials = HawkularProvider.process_credential_yaml_key( credentials_key) return HawkularProvider(name=prov_config['name'], key=prov_key, hostname=prov_config['hostname'], port=prov_config['port'], credentials={'default': credentials})
Dropdown, Input as WInput) from widgetastic_manageiq import TimelinesView from widgetastic_manageiq.vm_reconfigure import DisksTable # for provider specific vm/template page QUADICON_TITLE_LOCATOR = ( "//div[@id='quadicon']/../../../tr/td/a[contains(@href,'vm_infra/x_show')" " or contains(@href, '/show/')]") cfg_btn = partial(toolbar.select, 'Configuration') pol_btn = partial(toolbar.select, 'Policy') lcl_btn = partial(toolbar.select, 'Lifecycle') mon_btn = partial(toolbar.select, 'Monitoring') pwr_btn = partial(toolbar.select, 'Power') create_button = form_buttons.FormButton("Create") manage_policies_tree = CheckboxTree("//div[@id='protect_treebox']/ul") manage_policies_page = Region(locators={ 'save_button': form_buttons.save, }) template_select_form = Form(fields=[('template_table', Table('//div[@id="pre_prov_div"]//table') ), ('cancel_button', form_buttons.cancel)]) snapshot_form = Form( fields=[('name', Input('name')), ('description', Input('description')), ('snapshot_memory',
# -*- coding: utf-8 -*- from cfme import web_ui as ui from cfme.fixtures import pytest_selenium as sel from cfme.web_ui import Region, accordion, fill, flash, form_buttons from cfme.web_ui.menu import nav nav.add_branch( "reports", { "import_export": lambda ctx: accordion.tree("Import/Export", "Import / Export"), }) form = Region(locators=dict( export_select=ui.Select("//select[@id='choices_chosen']", multi=True), export_button=form_buttons.FormButton("Download Report to YAML"), import_overwrite=ui.Input('overwrite'), import_file=ui.Input('upload_file'), import_submit=ui.Input('upload_atags'))) export_select = ui.Select("//select[@id='choices_chosen']", multi=True) export_button = form_buttons.FormButton("Download Report to YAML") def export_reports(*custom_report_names): sel.force_navigate("import_export") fill(form.export_select, custom_report_names) sel.click(form.export_button) def import_reports(filename, overwrite=False):
Input('log_userid')), ('secret_pass', Input('log_password')), ('verify_secret_pass', Input('log_verify')), ('validate_btn', form_buttons.validate)]) def cfm_mgr_table(): return Table("//div[@id='main_div']//div[@id='list_grid']/table") page = Region( locators={ 'list_table_config_profiles': cfm_mgr_table(), 'list_table_config_systems': cfm_mgr_table() }) add_manager_btn = form_buttons.FormButton('Add') edit_manager_btn = form_buttons.FormButton('Save changes') cfg_btn = partial(tb.select, 'Configuration') match_page = partial(match_location, controller='provider_foreman', title='Red Hat Satellite Provider') class ConfigManager(Updateable, Pretty, Navigatable): """ This is base class for Configuration manager objects (Red Hat Satellite, Foreman, Ansible Tower) Args: name: Name of the config. manager url: URL, hostname or IP of the config. manager
from cfme.fixtures import pytest_selenium as sel from cfme.services import requests from cfme.web_ui import fill, flash, form_buttons, tabstrip, toolbar from cfme.web_ui.menu import nav from utils import version from utils.log import logger from utils.version import current_version from utils.wait import wait_for # nav imports import cfme.infrastructure.virtual_machines # NOQA import cfme.cloud.instance # NOQA instances_by_provider_tree = ui.Tree("ul.dynatree-container") submit_button = form_buttons.FormButton("Submit") template_select_form = ui.Form( fields=[ ('template_table', ui.Table('//div[@id="pre_prov_div"]//table')), ('cancel_button', form_buttons.cancel) ] ) def select_security_group(sg): """Workaround for select box that is immediately replaced by the same select box no matter what selenium clicks on (but works fine manually). For now only selects one item even though it's a multiselect.
class CopiableTreeNode(TreeNode): copy_form = Form(fields=[ ("domain", { version.LOWEST: Select("select#domain"), "5.5": AngularSelect("domain") }), ("domain_text_only", { version.LOWEST: "//fieldset[p]//tr[./td[@class='key' and normalize-space(.)=" "'To Domain']]/td[not(@class='key') and not(select)]", "5.5": "//label[contains(@class, 'control-label') and normalize-space(.)='To Domain']/" "../div/p" }), ("override", Input("override_source")) ]) copy_button = form_buttons.FormButton("Copy") @property def class_name(self): """Used for gathering the object name from the class name. If the name is not same, you can set it manually. This exploits the fact that the classes are named exactly as it appears in the UI, so it will work unless someone changes ui/class name. Then you can set it manually, as it contains setter.""" try: return self._class_name except AttributeError: return self.__class__.__name__ @class_name.setter def class_name(self, value): self._class_name = value def _open_copy_dialog(self): sel.force_navigate("automate_explorer_tree_path", context={"tree_item": self}) cfg_btn("Copy this {}".format(self.class_name)) # TODO: Make possible change `override` (did not do that because of pop-up tree) def copy_to(self, domain=None): self._open_copy_dialog() if isinstance(domain, Domain): domain_name = domain.name else: domain_name = str(domain) if sel.is_displayed(self.copy_form.domain): fill(self.copy_form, {"domain": domain_name, "override": True}) else: # If there is only one domain, therefore the select is not present, only text domain_selected = sel.text(self.copy_form.domain_text_only).strip() if domain_selected != domain_name: raise ValueError( "There is only one domain to select and that is {}".format( domain_selected)) fill(self.copy_form, {"override": True}) sel.click(self.copy_button) flash.assert_message_match( "Copy selected Automate {} was saved".format(self.class_name)) # Bunch'o functions that copy the chain to the domain and change domain's name def _change_path_in_namespace(o, new_domain_name): if isinstance(o, Domain): if isinstance(new_domain_name, Domain): return new_domain_name new_domain = copy(o) new_domain.name = new_domain_name return new_domain else: new_obj = copy(o) if new_obj.parent is None: # This should happen in the domain part of this func so Error here raise Exception( "It is not expected that {} has no parent!".format( type(new_obj).__name__)) new_obj.parent = _change_path_in_namespace( new_obj.parent, new_domain_name) return new_obj def _change_parent_path_until_namespace(obj, new_domain_name): if isinstance(obj, Namespace): return _change_path_in_namespace(obj, new_domain_name) else: new_obj = copy(obj) if new_obj.parent is None: # This should happen in the namespace func so Error here raise Exception( "It is not expected that {} has no parent!".format( type(new_obj).__name__)) new_obj.parent = _change_parent_path_until_namespace( new_obj.parent, new_domain_name) return new_obj return _change_parent_path_until_namespace(self, domain)
class Visual(Updateable, Navigatable): pretty_attrs = ['name'] item_form = Form( fields=[ ('grid_view', AngularSelect('perpage_grid')), ('tile_view', AngularSelect("perpage_tile")), ('list_view', AngularSelect("perpage_list")), ('reports', AngularSelect("perpage_reports")), ]) startpage_form = Form( fields=[ ('login_page', AngularSelect("start_page"))]) quadicons_form = Form( fields=[ ('infra_provider_quad', CFMECheckbox("quadicons_ems")), ('cloud_provider_quad', CFMECheckbox("quadicons_ems_cloud")), ('host_quad', CFMECheckbox("quadicons_host")), ('datastore_quad', CFMECheckbox("quadicons_storage")), ('datastoreitem_quad', Input("quadicons_storageitem")), ('vm_quad', CFMECheckbox("quadicons_vm")), ('vmitem_quad', Input("quadicons_vmitem")), ('template_quad', CFMECheckbox("quadicons_miq_template")), ]) display_form = Form( fields=[ ('chart_theme', AngularSelect("display_reporttheme")), ('time_zone', AngularSelect("display_timezone")), ]) save_button = form_buttons.FormButton("Add this Time Profile") @property def grid_view_limit(self): navigate_to(self, 'All') return int(re.findall("\d+", self.item_form.grid_view.first_selected_option_text)[0]) @grid_view_limit.setter def grid_view_limit(self, value): navigate_to(self, 'All') fill(self.item_form.grid_view, str(value)) sel.click(form_buttons.save) @property def tile_view_limit(self): navigate_to(self, 'All') return int(re.findall("\d+", self.item_form.tile_view.first_selected_option_text)[0]) @tile_view_limit.setter def tile_view_limit(self, value): navigate_to(self, 'All') fill(self.item_form.tile_view, str(value)) sel.click(form_buttons.save) @property def list_view_limit(self): navigate_to(self, 'All') return int(re.findall("\d+", self.item_form.list_view.first_selected_option_text)[0]) @list_view_limit.setter def list_view_limit(self, value): navigate_to(self, 'All') fill(self.item_form.list_view, str(value)) sel.click(form_buttons.save) @property def report_view_limit(self): navigate_to(self, 'All') return int(re.findall("\d+", self.item_form.reports.first_selected_option_text)[0]) @report_view_limit.setter def report_view_limit(self, value): navigate_to(self, 'All') fill(self.item_form.reports, str(value)) sel.click(form_buttons.save) @property def login_page(self): navigate_to(self, 'All') return self.startpage_form.login_page.first_selected_option_text @login_page.setter def login_page(self, value): navigate_to(self, 'All') fill(self.startpage_form.login_page, str(value)) sel.click(form_buttons.save) @property def infra_provider_quad(self): navigate_to(self, 'All') return self.infra_provider_quad @infra_provider_quad.setter def infra_provider_quad(self, value): navigate_to(self, 'All') fill(self.quadicons_form.infra_provider_quad, value) sel.click(form_buttons.save) @property def host_quad(self): navigate_to(self, 'All') return self.host_quad @host_quad.setter def host_quad(self, value): navigate_to(self, 'All') fill(self.quadicons_form.host_quad, value) sel.click(form_buttons.save) @property def datastore_quad(self): navigate_to(self, 'All') return self.datastore_quad @datastore_quad.setter def datastore_quad(self, value): navigate_to(self, 'All') fill(self.quadicons_form.datastore_quad, value) sel.click(form_buttons.save) @property def vm_quad(self): navigate_to(self, 'All') return self.vm_quad @vm_quad.setter def vm_quad(self, value): navigate_to(self, 'All') fill(self.quadicons_form.vm_quad, value) sel.click(form_buttons.save) @property def template_quad(self): navigate_to(self, 'All') return self.template_quad @template_quad.setter def template_quad(self, value): navigate_to(self, 'All') fill(self.quadicons_form.template_quad, value) sel.click(form_buttons.save) def check_image_exists(self): name = Quadicon.get_first_quad_title() quad = Quadicon(name, None) return quad.check_for_single_quadrant_icon @property def cloud_provider_quad(self): navigate_to(self, 'All') return self.cloud_provider_quad @cloud_provider_quad.setter def cloud_provider_quad(self, value): navigate_to(self, 'All') fill(self.quadicons_form.cloud_provider_quad, value) sel.click(form_buttons.save) @property def timezone(self): navigate_to(self, 'All') return self.display_form.time_zone.first_selected_option_text @timezone.setter def timezone(self, value): navigate_to(self, 'All') fill(self.display_form.time_zone, str(value)) sel.click(form_buttons.save)
class Timeprofile(Updateable): timeprofile_form = Form(fields=[ ("description", Input("description")), ("scope", { version.LOWEST: Select("select#profile_type"), "5.5": AngularSelect("profile_type") }), ("timezone", { version.LOWEST: Select("select#profile_tz"), "5.5": AngularSelect("profile_tz") }), ("days", Input("all_days")), ("hours", Input("all_hours")), ]) save_button = form_buttons.FormButton("Add this Time Profile") def __init__(self, description=None, scope=None, days=None, hours=None, timezone=None): self.description = description self.scope = scope self.days = days self.hours = hours self.timezone = timezone def create(self): sel.force_navigate('timeprofile_new') fill(self.timeprofile_form, { 'description': self.description, 'scope': self.scope, 'days': self.days, 'hours': self.hours, 'timezone': self.timezone, }, action=self.save_button) flash.assert_success_message('Time Profile "{}" was added'.format( self.description)) def update(self, updates): sel.force_navigate("timeprofile_edit", context={"timeprofile": self}) fill(self.timeprofile_form, { 'description': updates.get('description'), 'scope': updates.get('scope'), 'timezone': updates.get('timezone') }, action=form_buttons.save) flash.assert_success_message('Time Profile "{}" was saved'.format( updates.get('description', self.description))) def copy(self): sel.force_navigate("my_settings_time_profiles") row = timeprofile_table.find_row_by_cells( {'description': self.description}) sel.check(sel.element(".//input[@type='checkbox']", root=row[0])) cfg_btn('Copy selected Time Profile') new_timeprofile = Timeprofile(description=self.description + "copy", scope=self.scope) fill(self.timeprofile_form, { 'description': new_timeprofile.description, 'scope': new_timeprofile.scope }, action=self.save_button) flash.assert_success_message('Time Profile "{}" was added'.format( new_timeprofile.description)) return new_timeprofile def delete(self): sel.force_navigate("my_settings_time_profiles") row = timeprofile_table.find_row_by_cells( {'description': self.description}) sel.check(sel.element(".//input[@type='checkbox']", root=row[0])) cfg_btn('Delete selected Time Profiles', invokes_alert=True) sel.handle_alert() flash.assert_success_message( 'Time Profile "{}": Delete successful'.format(self.description))
class Timeprofile(Updateable, Navigatable): timeprofile_form = Form( fields=[ ("description", Input("description")), ("scope", AngularSelect("profile_type")), ("timezone", AngularSelect("profile_tz")), ("days", CFMECheckbox("all_days")), ("hours", CFMECheckbox("all_hours")), ] ) save_edit_button = deferred_verpick({'5.7': form_buttons.FormButton('Save changes'), '5.8': form_buttons.FormButton('Save')}) save_button = deferred_verpick({ version.LOWEST: form_buttons.FormButton("Add this Time Profile"), '5.7': form_buttons.FormButton('Add'), '5.8': form_buttons.FormButton('Save') }) def __init__(self, description=None, scope=None, days=None, hours=None, timezone=None, appliance=None): Navigatable.__init__(self, appliance=appliance) self.description = description self.scope = scope self.days = days self.hours = hours self.timezone = timezone def create(self, cancel=False): navigate_to(self, 'Add') fill(self.timeprofile_form, {'description': self.description, 'scope': self.scope, 'days': self.days, 'hours': self.hours, 'timezone': self.timezone, }) if not cancel: sel.click(self.save_button) end = "saved" if self.appliance.version > '5.7' else "added" flash.assert_success_message('Time Profile "{}" was {}' .format(self.description, end)) def update(self, updates): navigate_to(self, 'Edit') fill(self.timeprofile_form, {'description': updates.get('description'), 'scope': updates.get('scope'), 'timezone': updates.get('timezone')}, action={version.LOWEST: form_buttons.save, '5.7': self.save_edit_button}) flash.assert_success_message( 'Time Profile "{}" was saved'.format(updates.get('description', self.description))) def copy(self): navigate_to(self, 'All') row = timeprofile_table.find_row_by_cells({'description': self.description}) sel.check(sel.element(".//input[@type='checkbox']", root=row[0])) cfg_btn('Copy selected Time Profile') new_timeprofile = Timeprofile(description=self.description + "copy", scope=self.scope) fill(self.timeprofile_form, {'description': new_timeprofile.description, 'scope': new_timeprofile.scope}, action=self.save_button) end = "saved" if self.appliance.version > '5.7' else "added" flash.assert_success_message('Time Profile "{}" was {}' .format(new_timeprofile.description, end)) return new_timeprofile def delete(self): navigate_to(self, 'All') row = timeprofile_table.find_row_by_cells({'description': self.description}) sel.check(sel.element(".//input[@type='checkbox']", root=row[0])) cfg_btn('Delete selected Time Profiles', invokes_alert=True) sel.handle_alert() flash.assert_success_message( 'Time Profile "{}": Delete successful'.format(self.description))
from cfme.web_ui import Input from utils.log import logger from utils.providers import setup_provider_by_name from utils.wait import wait_for from utils import version, deferred_verpick from utils.pretty import Pretty # Forms discover_form = Form( fields=[ ('discover_select', AngularSelect("discover_type_selected"), {"appeared_in": "5.5"}), ('username', "#userid"), ('password', "#password"), ('password_verify', "#verify"), ('start_button', form_buttons.FormButton("Start the Host Discovery")) ]) properties_form = Form( fields=[ ('type_select', {version.LOWEST: Select('select#server_emstype'), '5.5': AngularSelect("emstype")}), ('name_text', Input("name")), ('hostname_text', Input("hostname")), ('ipaddress_text', Input("ipaddress"), {"removed_since": "5.4.0.0.15"}), ('amazon_region_select', {version.LOWEST: Select("select#provider_region"), "5.5": AngularSelect("provider_region")}), ('api_port', Input( { version.LOWEST: "port", "5.5": "api_port",
import cfme.fixtures.pytest_selenium as sel from cfme.web_ui import form_buttons from cfme.web_ui import toolbar as tb from cfme.common.provider import BaseProvider from cfme.web_ui.menu import nav from cfme.web_ui import Region, Quadicon, Form, Select, fill, paginator from cfme.web_ui import Input from utils.log import logger from utils.update import Updateable from utils.wait import wait_for from utils import version from utils.pretty import Pretty # Specific Add button add_provider_button = form_buttons.FormButton("Add this Cloud Provider") # Forms discover_form = Form( fields=[('username', "#userid"), ('password', "#password"), ('password_verify', "#verify"), ('start_button', form_buttons.FormButton("Start the Host Discovery"))]) properties_form = Form(fields=[ ('type_select', Select("select#server_emstype")), ('name_text', Input("name")), ('hostname_text', Input("hostname")), ('ipaddress_text', Input("ipaddress"), { "removed_since": "5.4.0.0.15"
from widgetastic_patternfly import Tab, BootstrapSelect, Input, BootstrapTreeview from widgetastic_manageiq import VersionPick, Version, CheckboxSelect, Table, Calendar from cfme import web_ui as ui from cfme import BaseLoggedInPage from cfme.fixtures import pytest_selenium as sel from cfme.infrastructure.virtual_machines import Vm from cfme.services import requests from cfme.web_ui import AngularSelect, fill, flash, form_buttons, tabstrip from utils import version from utils import normalize_text from utils.appliance.implementations.ui import navigate_to from utils.log import logger from utils.wait import wait_for submit_button = form_buttons.FormButton("Submit") def select_security_group(sg): """TODO: Not even sure this is needed any more, but removal of it is not part of this PR""" sel.wait_for_ajax() sel.sleep(1) class ProvisioningForm(BaseLoggedInPage): @View.nested class request(Tab): # noqa TAB_NAME = 'Request' email = Input(name='requester__owner_email') first_name = Input(name='requester__owner_first_name') last_name = Input(name='requester__owner_last_name')
class Host(Updateable, Pretty): """ Model of an infrastructure host in cfme. Args: name: Name of the host. hostname: Hostname of the host. ip_address: The IP address as a string. custom_ident: The custom identifiter. host_platform: Included but appears unused in CFME at the moment. ipmi_address: The IPMI address. mac_address: The mac address of the system. credentials (Credential): see Credential inner class. ipmi_credentials (Credential): see Credential inner class. Usage: myhost = Host(name='vmware', credentials=Provider.Credential(principal='admin', secret='foobar')) myhost.create() """ pretty_attrs = ['name', 'hostname', 'ip_address', 'custom_ident'] forced_saved = deferred_verpick( {version.LOWEST: form_buttons.FormButton( "Save Changes", dimmed_alt="Save", force_click=True), '5.5': form_buttons.FormButton( "Save changes", dimmed_alt="Save changes", force_click=True)}) def __init__(self, name=None, hostname=None, ip_address=None, custom_ident=None, host_platform=None, ipmi_address=None, mac_address=None, credentials=None, ipmi_credentials=None, interface_type='lan'): self.name = name self.hostname = hostname self.ip_address = ip_address self.custom_ident = custom_ident self.host_platform = host_platform self.ipmi_address = ipmi_address self.mac_address = mac_address self.credentials = credentials self.ipmi_credentials = ipmi_credentials self.interface_type = interface_type self.db_id = None def _form_mapping(self, create=None, **kwargs): return {'name_text': kwargs.get('name'), 'hostname_text': kwargs.get('hostname'), 'ipaddress_text': kwargs.get('ip_address'), 'custom_ident_text': kwargs.get('custom_ident'), 'host_platform': kwargs.get('host_platform'), 'ipmi_address_text': kwargs.get('ipmi_address'), 'mac_address_text': kwargs.get('mac_address')} class Credential(cfme.Credential, Updateable): """Provider credentials Args: **kwargs: If using IPMI type credential, ipmi = True""" def __init__(self, **kwargs): super(Host.Credential, self).__init__(**kwargs) self.ipmi = kwargs.get('ipmi') def _submit(self, cancel, submit_button): if cancel: sel.click(form_buttons.cancel) # sel.wait_for_element(page.configuration_btn) else: sel.click(submit_button) flash.assert_no_errors() def create(self, cancel=False, validate_credentials=False): """ Creates a host in the UI Args: cancel (boolean): Whether to cancel out of the creation. The cancel is done after all the information present in the Host has been filled in the UI. validate_credentials (boolean): Whether to validate credentials - if True and the credentials are invalid, an error will be raised. """ sel.force_navigate('infrastructure_host_new') fill(properties_form, self._form_mapping(True, **self.__dict__)) fill(credential_form, self.credentials, validate=validate_credentials) fill(credential_form, self.ipmi_credentials, validate=validate_credentials) self._submit(cancel, host_add_btn) def update(self, updates, cancel=False, validate_credentials=False): """ Updates a host in the UI. Better to use utils.update.update context manager than call this directly. Args: updates (dict): fields that are changing. cancel (boolean): whether to cancel out of the update. """ sel.force_navigate('infrastructure_host_edit', context={'host': self}) change_stored_password() fill(credential_form, updates.get('credentials', None), validate=validate_credentials) # Workaround for issue with form_button staying dimmed. try: logger.debug("Trying to save update for host with id: " + str(self.get_db_id)) self._submit(cancel, self.forced_saved) logger.debug("save worked, no exception") except Exception as e: logger.debug("exception detected: " + str(e)) sel.browser().execute_script( "$j.ajax({type: 'POST', url: '/host/form_field_changed/%s'," " data: {'default_userid':'%s'}})" % (str(sel.current_url().split('/')[5]), updates.get('credentials', None).principal)) sel.browser().execute_script( "$j.ajax({type: 'POST', url: '/host/form_field_changed/%s'," " data: {'default_password':'******'}})" % (str(sel.current_url().split('/')[5]), updates.get('credentials', None).secret)) sel.browser().execute_script( "$j.ajax({type: 'POST', url: '/host/form_field_changed/%s'," " data: {'default_verify':'%s'}})" % (str(sel.current_url().split('/')[5]), updates.get('credentials', None).verify_secret)) self._submit(cancel, self.forced_saved) def delete(self, cancel=True): """ Deletes a host from CFME Args: cancel: Whether to cancel the deletion, defaults to True """ sel.force_navigate('infrastructure_host', context={'host': self}) cfg_btn('Remove from the VMDB', invokes_alert=True) sel.handle_alert(cancel=cancel) def execute_button(self, button_group, button, cancel=True): sel.force_navigate('infrastructure_host', context={'host': self}) host_btn = partial(tb.select, button_group) host_btn(button, invokes_alert=True) sel.click(form_buttons.submit) flash.assert_success_message("Order Request was Submitted") host_btn(button, invokes_alert=True) sel.click(form_buttons.cancel) flash.assert_success_message("Service Order was cancelled by the user") def power_on(self): sel.force_navigate('infrastructure_host', context={'host': self}) pow_btn('Power On') sel.handle_alert() def power_off(self): sel.force_navigate('infrastructure_host', context={'host': self}) pow_btn('Power Off') sel.handle_alert() def get_ipmi(self): return IPMI(hostname=self.ipmi_address, username=self.ipmi_credentials.principal, password=self.ipmi_credentials.secret, interface_type=self.interface_type) def get_detail(self, *ident): """ Gets details from the details infoblock The function first ensures that we are on the detail page for the specific host. Args: *ident: An InfoBlock title, followed by the Key name, e.g. "Relationships", "Images" Returns: A string representing the contents of the InfoBlock's value. """ if not self._on_detail_page(): sel.force_navigate('infrastructure_host', context={'host': self}) return details_page.infoblock.text(*ident) def _on_detail_page(self): """ Returns ``True`` if on the hosts detail page, ``False`` if not.""" return sel.is_displayed('//div[@class="dhtmlxInfoBarLabel-2"][contains(., "%s")]' % self.name) @property def exists(self): sel.force_navigate('infrastructure_hosts') for page in paginator.pages(): if sel.is_displayed(Quadicon(self.name, 'host')): return True else: return False @property def has_valid_credentials(self): """ Check if host has valid credentials saved Returns: ``True`` if credentials are saved and valid; ``False`` otherwise """ sel.force_navigate('infrastructure_hosts') quad = Quadicon(self.name, 'host') return quad.creds == 'checkmark' def _assign_unassign_policy_profiles(self, assign, *policy_profile_names): """DRY function for managing policy profiles. See :py:func:`assign_policy_profiles` and :py:func:`assign_policy_profiles` Args: assign: Wheter to assign or unassign. policy_profile_names: :py:class:`str` with Policy Profile names. """ sel.force_navigate('infrastructure_host_policy_assignment', context={'host': self}) for policy_profile in policy_profile_names: if assign: manage_policies_tree.check_node(policy_profile) else: manage_policies_tree.uncheck_node(policy_profile) sel.click(form_buttons.save) def assign_policy_profiles(self, *policy_profile_names): """ Assign Policy Profiles to this Host. Args: policy_profile_names: :py:class:`str` with Policy Profile names. After Control/Explorer coverage goes in, PolicyProfile objects will be also passable. """ self._assign_unassign_policy_profiles(True, *policy_profile_names) def unassign_policy_profiles(self, *policy_profile_names): """ Unssign Policy Profiles to this Host. Args: policy_profile_names: :py:class:`str` with Policy Profile names. After Control/Explorer coverage goes in, PolicyProfile objects will be also passable. """ self._assign_unassign_policy_profiles(False, *policy_profile_names) def get_datastores(self): """ Gets list of all datastores used by this host""" sel.force_navigate('infrastructure_host', context={'host': self}) list_acc.select('Relationships', version.pick({version.LOWEST: 'Show Datastores', '5.3': 'Show all Datastores'})) datastores = set([]) for page in paginator.pages(): for title in sel.elements( "//div[@id='quadicon']/../../../tr/td/a[contains(@href,'storage/show')]"): datastores.add(sel.get_attribute(title, "title")) return datastores @property def get_db_id(self): if self.db_id is None: self.db_id = get_host_id(self.name) return self.db_id else: return self.db_id def run_smartstate_analysis(self): """ Runs smartstate analysis on this host Note: The host must have valid credentials already set up for this to work. """ sel.force_navigate('infrastructure_host', context={'host': self}) tb.select('Configuration', 'Perform SmartState Analysis', invokes_alert=True) sel.handle_alert() flash.assert_message_contain('"{}": Analysis successfully initiated'.format(self.name)) def equal_drift_results(self, row_text, section, *indexes): """ Compares drift analysis results of a row specified by it's title text Args: row_text: Title text of the row to compare section: Accordion section where the change happened; this section must be activated indexes: Indexes of results to compare starting with 0 for first row (latest result). Compares all available drifts, if left empty (default). Note: There have to be at least 2 drift results available for this to work. Returns: ``True`` if equal, ``False`` otherwise. """ # mark by indexes or mark all sel.force_navigate('infrastructure_host', context={'host': self}) list_acc.select('Relationships', version.pick({ version.LOWEST: 'Show host drift history', '5.4': 'Show Host drift history'})) if indexes: drift_table.select_rows_by_indexes(*indexes) else: # We can't compare more than 10 drift results at once # so when selecting all, we have to limit it to the latest 10 if len(list(drift_table.rows())) > 10: drift_table.select_rows_by_indexes(*range(0, 10)) else: drift_table.select_all() tb.select("Select up to 10 timestamps for Drift Analysis") # Make sure the section we need is active/open sec_loc_map = { 'Properties': 'Properties', 'Security': 'Security', 'Configuration': 'Configuration', 'My Company Tags': 'Categories'} active_sec_loc = "//div[@id='all_sections_treebox']//li[contains(@id, 'group_{}')]"\ "/span[contains(@class, 'dynatree-selected')]".format(sec_loc_map[section]) sec_checkbox_loc = "//div[@id='all_sections_treebox']//li[contains(@id, 'group_{}')]"\ "//span[contains(@class, 'dynatree-checkbox')]".format(sec_loc_map[section]) sec_apply_btn = "//div[@id='accordion']/a[contains(normalize-space(text()), 'Apply')]" # If the section is not active yet, activate it if not sel.is_displayed(active_sec_loc): sel.click(sec_checkbox_loc) sel.click(sec_apply_btn) if not tb.is_active("All attributes"): tb.select("All attributes") d_grid = DriftGrid() if any(d_grid.cell_indicates_change(row_text, i) for i in range(0, len(indexes))): return False return True def tag(self, tag, **kwargs): """Tags the system by given tag""" sel.force_navigate('infrastructure_host', context={'host': self}) mixins.add_tag(tag, **kwargs) def untag(self, tag): """Removes the selected tag off the system""" sel.force_navigate('infrastructure_host', context={'host': self}) mixins.remove_tag(tag)
class Provider(BaseProvider, Pretty): pretty_attrs = ['name', 'key', 'zone'] STATS_TO_MATCH = [ 'num_project', 'num_service', 'num_replication_controller', 'num_pod', 'num_node', 'num_container', 'num_image' ] # TODO add 'num_image_registry' and 'num_volume' string_name = "Containers" page_name = "containers" detail_page_suffix = 'provider_detail' edit_page_suffix = 'provider_edit_detail' refresh_text = "Refresh items and relationships" quad_name = None _properties_region = prop_region # This will get resolved in common to a real form add_provider_button = deferred_verpick({ version.LOWEST: form_buttons.FormButton("Add this Containers Provider"), '5.6': form_buttons.add }) save_button = deferred_verpick({ version.LOWEST: form_buttons.save, '5.6': form_buttons.angular_save }) def __init__(self, name=None, credentials=None, key=None, zone=None, hostname=None, port=None, provider_data=None): if not credentials: credentials = {} self.name = name self.credentials = credentials self.key = key self.zone = zone self.hostname = hostname self.port = port self.provider_data = provider_data def _on_detail_page(self): """ Returns ``True`` if on the providers detail page, ``False`` if not.""" ensure_browser_open() return sel.is_displayed( '//div//h1[contains(., "{} (Summary)")]'.format(self.name)) def load_details(self, refresh=False): if not self._on_detail_page(): self.navigate(detail=True) elif refresh: tb.refresh() def navigate(self, detail=True): if detail is True: if not self._on_detail_page(): sel.force_navigate('containers_provider_detail', context={'provider': self}) else: sel.force_navigate('containers_provider', context={'provider': self}) def get_detail(self, *ident): """ Gets details from the details infoblock Args: *ident: An InfoBlock title, followed by the Key name, e.g. "Relationships", "Images" Returns: A string representing the contents of the InfoBlock's value. """ self.navigate(detail=True) return details_page.infoblock.text(*ident) @variable(alias='db') def num_project(self): return self._num_db_generic('container_projects') @num_project.variant('ui') def num_project_ui(self): return int(self.get_detail("Relationships", "Projects")) @variable(alias='db') def num_service(self): return self._num_db_generic('container_services') @num_service.variant('ui') def num_service_ui(self): return int(self.get_detail("Relationships", "Services")) @variable(alias='db') def num_replication_controller(self): return self._num_db_generic('container_replicators') @num_replication_controller.variant('ui') def num_replication_controller_ui(self): return int(self.get_detail("Relationships", "Replicators")) @variable(alias='db') def num_container_group(self): return self._num_db_generic('container_groups') @num_container_group.variant('ui') def num_container_group_ui(self): return int(self.get_detail("Relationships", "Pods")) @variable(alias='db') def num_pod(self): # potato tomato return self.num_container_group() @num_pod.variant('ui') def num_pod_ui(self): # potato tomato return self.num_container_group(method='ui') @variable(alias='db') def num_node(self): return self._num_db_generic('container_nodes') @num_node.variant('ui') def num_node_ui(self): return int(self.get_detail("Relationships", "Nodes")) @variable(alias='db') def num_container(self): # Containers are linked to providers through container definitions and then through pods res = cfmedb().engine.execute( "SELECT count(*) " "FROM ext_management_systems, container_groups, container_definitions, containers " "WHERE containers.container_definition_id=container_definitions.id " "AND container_definitions.container_group_id=container_groups.id " "AND container_groups.ems_id=ext_management_systems.id " "AND ext_management_systems.name='{}'".format(self.name)) return int(res.first()[0]) @num_container.variant('ui') def num_container_ui(self): return int(self.get_detail("Relationships", "Containers")) @variable(alias='db') def num_image(self): return self._num_db_generic('container_images') @num_image.variant('ui') def num_image_ui(self): return int(self.get_detail("Relationships", "Images")) @variable(alias='db') def num_image_registry(self): return self._num_db_generic('container_image_registries') @num_image_registry.variant('ui') def num_image_registry_ui(self): return int(self.get_detail("Relationships", "Image Registries"))
class Provider(Pretty, CloudInfraProvider): """ Abstract model of an infrastructure provider in cfme. See VMwareProvider or RHEVMProvider. Args: name: Name of the provider. details: a details record (see VMwareDetails, RHEVMDetails inner class). credentials (Credential): see Credential inner class. key: The CFME key of the provider in the yaml. candu: C&U credentials if this is a RHEVMDetails class. Usage: myprov = VMwareProvider(name='foo', region='us-west-1', credentials=Provider.Credential(principal='admin', secret='foobar')) myprov.create() """ pretty_attrs = ['name', 'key', 'zone'] STATS_TO_MATCH = [ 'num_template', 'num_vm', 'num_datastore', 'num_host', 'num_cluster' ] string_name = "Infrastructure" page_name = "infrastructure" instances_page_name = "infra_vm_and_templates" templates_page_name = "infra_vm_and_templates" quad_name = "infra_prov" properties_form = properties_form add_provider_button = form_buttons.FormButton( "Add this Infrastructure Provider") save_button = form_buttons.FormButton("Save Changes") def __init__(self, name=None, credentials=None, key=None, zone=None, provider_data=None): if not credentials: credentials = {} self.name = name self.credentials = credentials self.key = key self.provider_data = provider_data self.zone = zone self.vm_name = version.pick({ version.LOWEST: "VMs", '5.5': "VMs and Instances" }) self.template_name = "Templates" def _form_mapping(self, create=None, **kwargs): return {'name_text': kwargs.get('name')} @variable(alias='db') def num_datastore(self): storage_table_name = version.pick({ version.LOWEST: 'hosts_storages', '5.5.0.8': 'host_storages' }) """ Returns the providers number of templates, as shown on the Details page.""" results = list(cfmedb().engine.execute( 'SELECT DISTINCT storages.name, hosts.ems_id ' 'FROM ext_management_systems, hosts, storages, {} ' 'WHERE hosts.id={}.host_id AND ' 'storages.id={}.storage_id AND ' 'hosts.ems_id=ext_management_systems.id AND ' 'ext_management_systems.name=\'{}\''.format( storage_table_name, storage_table_name, storage_table_name, self.name))) return len(results) @num_datastore.variant('ui') def num_datastore_ui(self): return int(self.get_detail("Relationships", "Datastores")) @variable(alias='rest') def num_host(self): provider = rest_api().collections.providers.find_by(name=self.name)[0] num_host = 0 for host in rest_api().collections.hosts: if host['ems_id'] == provider.id: num_host += 1 return num_host @num_host.variant('db') def num_host_db(self): ext_management_systems = cfmedb()["ext_management_systems"] hosts = cfmedb()["hosts"] hostlist = list(cfmedb().session.query(hosts.name).join( ext_management_systems, hosts.ems_id == ext_management_systems.id).filter( ext_management_systems.name == self.name)) return len(hostlist) @num_host.variant('ui') def num_host_ui(self): return int(self.get_detail("Relationships", "host.png", use_icon=True)) @variable(alias='rest') def num_cluster(self): provider = rest_api().collections.providers.find_by(name=self.name)[0] num_cluster = 0 for cluster in rest_api().collections.clusters: if cluster['ems_id'] == provider.id: num_cluster += 1 return num_cluster @num_cluster.variant('db') def num_cluster_db(self): """ Returns the providers number of templates, as shown on the Details page.""" ext_management_systems = cfmedb()["ext_management_systems"] clusters = cfmedb()["ems_clusters"] clulist = list(cfmedb().session.query(clusters.name).join( ext_management_systems, clusters.ems_id == ext_management_systems.id).filter( ext_management_systems.name == self.name)) return len(clulist) @num_cluster.variant('ui') def num_cluster_ui(self): return int( self.get_detail("Relationships", "cluster.png", use_icon=True)) def discover(self): """ Begins provider discovery from a provider instance Usage: discover_from_config(utils.providers.get_crud('rhevm')) """ vmware = isinstance(self, VMwareProvider) rhevm = isinstance(self, RHEVMProvider) scvmm = isinstance(self, SCVMMProvider) discover(rhevm, vmware, scvmm, cancel=False, start_ip=self.start_ip, end_ip=self.end_ip) @property def hosts(self): """Returns list of :py:class:`cfme.infrastructure.host.Host` that should belong to this provider according to the YAML """ result = [] for host in self.get_yaml_data().get("hosts", []): creds = conf.credentials.get(host["credentials"], {}) cred = Host.Credential( principal=creds["username"], secret=creds["password"], verify_secret=creds["password"], ) result.append(Host(name=host["name"], credentials=cred)) return result
class HawkularProvider(MiddlewareBase, BaseProvider): """ HawkularProvider class holds provider data. Used to perform actions on hawkular provider page Args: name: Name of the provider hostname: Hostname/IP of the provider port: http/https port of hawkular provider credentials: see Credential inner class. key: The CFME key of the provider in the yaml. Usage: myprov = HawkularProvider(name='foo', hostname='localhost', port=8080, credentials=Provider.Credential(principal='admin', secret='foobar'))) myprov.create() myprov.num_deployment(method="ui") """ STATS_TO_MATCH = ['num_server', 'num_deployment', 'num_datasource'] property_tuples = [('name', 'name'), ('hostname', 'host_name'), ('port', 'port'), ('provider_type', 'type')] page_name = 'middleware' string_name = 'Middleware' detail_page_suffix = 'provider_detail' edit_page_suffix = 'provider_edit_detail' refresh_text = "Refresh items and relationships" quad_name = None _properties_form = properties_form add_provider_button = form_buttons.FormButton( "Add this Middleware Provider") save_button = form_buttons.FormButton("Save Changes") def __init__(self, name=None, hostname=None, port=None, credentials=None, key=None): self.name = name self.hostname = hostname self.port = port self.provider_type = 'Hawkular' if not credentials: credentials = {} self.credentials = credentials self.key = key def _form_mapping(self, create=None, **kwargs): return { 'name_text': kwargs.get('name'), 'type_select': create and 'Hawkular', 'hostname_text': kwargs.get('hostname'), 'port_text': kwargs.get('port') } @variable(alias='db') def num_deployment(self): return self._num_db_generic('middleware_deployments') @num_deployment.variant('ui') def num_deployment_ui(self, reload_data=True): if reload_data: self.summary.reload() return self.summary.relationships.middleware_deployments.value @variable(alias='db') def num_server(self): return self._num_db_generic('middleware_servers') @num_server.variant('ui') def num_server_ui(self, reload_data=True): if reload_data: self.summary.reload() return self.summary.relationships.middleware_servers.value @variable(alias='db') def num_datasource(self): return self._num_db_generic('middleware_datasources') @num_datasource.variant('ui') def num_datasource_ui(self, reload_data=True): if reload_data: self.summary.reload() return self.summary.relationships.middleware_datasources.value @variable(alias='ui') def is_refreshed(self, reload_data=True): if reload_data: self.summary.reload() if re.match('Success.*Minute.*Ago', self.summary.status.last_refresh.text_value): return True else: return False @is_refreshed.variant('db') def is_refreshed_db(self): ems = cfmedb()['ext_management_systems'] dates = cfmedb().session.query( ems.created_on, ems.updated_on).filter(ems.name == self.name).first() return dates.updated_on > dates.created_on
import pytest from textwrap import dedent from cfme.automate.buttons import ButtonGroup, Button from cfme.automate.explorer import Namespace, Class, Instance, Domain, Method from cfme.automate.service_dialogs import ServiceDialog from cfme.common.vm import VM from cfme.web_ui import fill, flash, form_buttons, toolbar, Input from utils import testgen from utils.blockers import BZ from utils.log import logger from utils.providers import setup_provider from utils.wait import wait_for submit = form_buttons.FormButton("Submit") pytestmark = [ pytest.mark.meta(server_roles="+automate"), pytest.mark.ignore_stream("upstream", "5.2") ] def pytest_generate_tests(metafunc): argnames, argvalues, idlist = testgen.provider_by_type( metafunc, ['virtualcenter'], 'provisioning') metafunc.parametrize(argnames, argvalues, ids=idlist, scope='module') @pytest.yield_fixture(scope="module") def domain(request): domain = Domain(name=fauxfactory.gen_alphanumeric(), enabled=True)
class Tenant(Updateable, Pretty): """ Class representing CFME tenants in the UI. * Kudos to mfalesni * The behaviour is shared with Project, which is the same except it cannot create more nested tenants/projects. Args: name: Name of the tenant description: Description of the tenant parent_tenant: Parent tenant, can be None, can be passed as string or object """ save_changes = form_buttons.FormButton("Save changes") tenant_form = Form( fields=[('name', Input('name')), ('description', Input('description'))]) pretty_attrs = ["name", "description"] @classmethod def get_root_tenant(cls): return cls(name="My Company", _default=True) def __init__(self, name=None, description=None, parent_tenant=None, _default=False): self.name = name self.description = description self.parent_tenant = parent_tenant self._default = _default @property def parent_tenant(self): if self._default: return None if self._parent_tenant: return self._parent_tenant return self.get_root_tenant() @parent_tenant.setter def parent_tenant(self, tenant): if tenant is not None and isinstance(tenant, Project): # If we try to raise ValueError("Project cannot be a parent object.") if isinstance(tenant, basestring): # If parent tenant is passed as string, # we assume that tenant name was passed instead of object tenant = Tenant(tenant) self._parent_tenant = tenant def __eq__(self, other): if not isinstance(other, type(self)): return False else: return self.name == other.name @property def exists(self): try: sel.force_navigate("cfg_tenant_project", context={"tenant": self}) except CandidateNotFound: return False else: return True @property def tree_path(self): if self._default: return [self.name] else: return self.parent_tenant.tree_path + [self.name] @property def parent_path(self): return self.tree_path[:-1] def create(self, cancel=False): sel.force_navigate("cfg_tenant_project_create", context={"tenant": self}) fill(self.tenant_form, self, action=form_buttons.add) if type(self) is Tenant: flash.assert_success_message('Tenant "{}" was saved'.format( self.name)) elif type(self) is Project: flash.assert_success_message('Project "{}" was saved'.format( self.name)) else: raise TypeError( 'No Tenant or Project class passed to create method{}'.format( type(self).__name__)) def update(self, updates): sel.force_navigate("cfg_tenant_project_edit", context={"tenant": self}) # Workaround - without this, update was failing sometimes sel.wait_for_ajax() # Workaround - form is appearing after short delay sel.wait_for_element(self.tenant_form.description) fill(self.tenant_form, updates, action=self.save_changes) flash.assert_success_message('Project "{}" was saved'.format( updates.get('name', self.name))) def delete(self, cancel=False): sel.force_navigate("cfg_tenant_project", context={"tenant": self}) tb_select("Delete this item", invokes_alert=True) sel.handle_alert(cancel=cancel) flash.assert_success_message('Tenant "{}": Delete successful'.format( self.description))
}) manager = FolderManager("//div[@id='folder_lists']/table") report_select = MultiBoxSelect( "//select[@id='available_reports']", "//select[@id='selected_reports']", "//a[@title='Move selected reports right']/img", "//a[@title='Move selected reports left']/img", ) buttons = Region(locators=dict( commit="//a[@title='Commit report management changes']/img", discard="//a[@title='Discard report management changes']/img", )) default_button = form_buttons.FormButton("Reset All menus to CFME defaults") def get_folders(group): """Returns list of folders for given user group. Args: group: User group to check. """ sel.force_navigate("report_menus_group", context={"group": group}) reports_tree.click_path("Top Level") return manager.fields def get_subfolders(group, folder): """Returns list of sub-folders for given user group and folder.