Source code for cfme.v2v.migrations

import attr

from navmazing import NavigateToAttribute, NavigateToSibling
from widgetastic.widget import View
from widgetastic_patternfly import Text, TextInput, Button, BootstrapSelect
from widgetastic_manageiq import InfraMappingTreeView, MultiSelectList, MigrationPlansList

from cfme.base.login import BaseLoggedInPage
from cfme.modeling.base import BaseCollection, BaseEntity
from cfme.utils.appliance.implementations.ui import navigator, CFMENavigateStep, navigate_to


# Views


[docs]class InfraMappingFormControlButtons(View): # common footer buttons for first 3 pages back_btn = Button('Back') next_btn = Button('Next') cancel_btn = Button('Cancel')
[docs]class InfraMappingWizardCommon(View): add_mapping = Button('Add Mapping') remove_mapping = Button('Remove Selected') remove_all_mappings = Button('Remove All') mappings_tree = InfraMappingTreeView(tree_class='treeview')
[docs]class InfraMappingWizardGeneralView(View): name = TextInput(name='name') description = TextInput(name='description') include_buttons = View.include(InfraMappingFormControlButtons)
[docs] def after_fill(self, was_change): if was_change: self.next_btn.click()
[docs]class InfraMappingWizardClustersView(View): include_buttons_set1 = View.include(InfraMappingFormControlButtons) include_buttons_set2 = View.include(InfraMappingWizardCommon) source_clusters = MultiSelectList('source_clusters') target_clusters = MultiSelectList('target_clusters')
[docs] def fill(self, values): """Use to add all mappings specified in values. Args: values: format as following: { 'mappings': [ { 'sources':['item1', 'item2'], 'target':['item_target'] } ] ... } """ source_clusters_filled = [] target_clusters_filled = [] for mapping in values['mappings']: source_clusters_filled.append(self.source_clusters.fill(mapping['sources'])) target_clusters_filled.append(self.target_clusters.fill(mapping['target'])) self.add_mapping.click() was_change = any(source_clusters_filled) and any(target_clusters_filled) if was_change: self.next_btn.click() return was_change
[docs]class InfraMappingWizardDatastoresView(View): include_buttons_set1 = View.include(InfraMappingFormControlButtons) include_buttons_set2 = View.include(InfraMappingWizardCommon) source_datastores = MultiSelectList('source_datastores') target_datastores = MultiSelectList('target_datastores') cluster_selector = BootstrapSelect(id='cluster_select')
[docs] def fill(self, values): """Use to add all mappings specified in values. Args: values: format as following: { 'cluster_name': { 'mappings': [ { 'sources':['item1','item2'], 'target':['item_target'] }, ... ] }, ... } """ source_datastores_filled = [] target_datastores_filled = [] for cluster in values: self.cluster_selector.fill(cluster) for mapping in values[cluster]['mappings']: source_datastores_filled.append(self.source_datastores.fill(mapping['sources'])) target_datastores_filled.append(self.target_datastores.fill(mapping['target'])) self.add_mapping.click() was_change = any(source_datastores_filled) and any(target_datastores_filled) if was_change: self.next_btn.click() return was_change
[docs]class InfraMappingWizardNetworksView(View): include_buttons_set1 = View.include(InfraMappingFormControlButtons) include_buttons_set2 = View.include(InfraMappingWizardCommon) source_networks = MultiSelectList('source_networks') target_networks = MultiSelectList('target_networks') next_btn = Button("Create") # overriding, since 'Next' is called 'Create' in this form cluster_selector = BootstrapSelect(id='cluster_select')
[docs] def fill(self, values): """Use to add all mappings specified in values. Args: values: format as following: { 'cluster_name': { 'mappings': [ { 'sources':['item1','item2'], 'target':['item_target'] }, ... ] }, ... } """ source_networks_filled = [] target_networks_filled = [] for cluster in values: self.cluster_selector.fill(cluster) for mapping in values[cluster]['mappings']: source_networks_filled.append(self.source_networks.fill(mapping['sources'])) target_networks_filled.append(self.target_networks.fill(mapping['target'])) self.add_mapping.click() was_change = any(source_networks_filled) and any(target_networks_filled) if was_change: self.next_btn.click() return was_change
[docs]class InfraMappingWizardResultsView(View): close_btn = Button("Close") continue_to_plan_wizard_btn = Button("Continue to the plan wizard")
[docs]class InfraMappingWizard(View): """Infrastructure Mapping Wizard Modal Widget. Usage: fill: takes values of following format: { 'general': { 'name':'infra_map_{}'.format(fauxfactory.gen_alphanumeric()), 'description':fauxfactory.gen_string("alphanumeric",length=50) }, 'cluster': { 'mappings': [ { 'sources':['Datacenter \ Cluster'], 'target':['Default \ Default'] } ] }, 'datastore':{ 'Cluster (Default)': { 'mappings':[ { 'sources':['NFS_Datastore_1','iSCSI_Datastore_1'], 'target':['hosted_storage'] }, { 'sources':['h02-Local_Datastore-8GB', 'h01-Local_Datastore-8GB'], 'target':['env-rhv41-01-nfs-iso'] } ] } }, 'network':{ 'Cluster (Default)': { 'mappings': [ { 'sources':['VM Network','VMkernel'], 'target':['ovirtmgmt'] }, { 'sources':['DPortGroup'], 'target':['Storage VLAN 33'] } ] } } } """ title = Text(locator='.//h4[contains(@class,"modal-title")]') general = View.nested(InfraMappingWizardGeneralView) cluster = View.nested(InfraMappingWizardClustersView) datastore = View.nested(InfraMappingWizardDatastoresView) network = View.nested(InfraMappingWizardNetworksView) result = View.nested(InfraMappingWizardResultsView)
[docs] def after_fill(self, was_change): if was_change: self.result.close_btn.click()
[docs]class MigrationDashboardView(BaseLoggedInPage): create_infrastructure_mapping = Text(locator='(//a|//button)' '[text()="Create Infrastructure Mapping"]') create_migration_plan = Text(locator='(//a|//button)[text()="Create Migration Plan"]') migration_plans_not_started_list = MigrationPlansList("plans-not-started-list") migration_plans_completed_list = MigrationPlansList("plans-complete-list") @property def is_displayed(self): return self.navigation.currently_selected == ['Compute', 'Migration']
[docs]class AddInfrastructureMappingView(View): form = InfraMappingWizard() @property def is_displayed(self): return self.form.title.text == 'Infrastructure Mapping Wizard'
[docs]class AddMigrationPlanView(View): title = Text(locator='.//h4[contains(@class,"modal-title")]') name = TextInput(name='name') description = TextInput(name='description') back_btn = Button('Back') # Since next is a keyword, suffixing it with btn and other two # because want to keep it consistent next_btn = Button('Next') cancel_btn = Button('Cancel') @property def is_displayed(self): return self.title.text == 'Migration Plan Wizard'
# Collections Entities @attr.s
[docs]class InfrastructureMapping(BaseEntity): """Class representing v2v infrastructure mappings""" name = attr.ib() description = attr.ib(default=None) form_data = attr.ib(default=None)
@attr.s
[docs]class InfrastructureMappingCollection(BaseCollection): """Collection object for Migration mapping object""" ENTITY = InfrastructureMapping
[docs] def create(self, form_data): infra_map = self.instantiate( name=form_data['general']['name'], description=form_data['general'].get('description', ''), form_data=form_data ) view = navigate_to(self, 'Add') view.form.fill(form_data) return infra_map
# TODO: Next Entity and Collection classes are to be filled by Yadnyawalk(ytale), # which he will submit PR for once my PR merged. @attr.s
[docs]class MigrationPlan(BaseEntity): """Class representing v2v Migration Plan""" # TODO: Ytale is updating rest of the code in this entity in separate PR. category = 'migrationplan' string_name = 'Migration Plan'
@attr.s
[docs]class MigrationPlanCollection(BaseCollection): """Collection object for Migration Plan object""" # TODO: Ytale is updating rest of the code in this collection in separate PR. ENTITY = MigrationPlan
# Navigations @navigator.register(InfrastructureMappingCollection, 'All') @navigator.register(MigrationPlanCollection, 'All')
[docs]class All(CFMENavigateStep): VIEW = MigrationDashboardView prerequisite = NavigateToAttribute('appliance.server', 'LoggedIn')
[docs] def step(self): self.prerequisite_view.navigation.select('Compute', 'Migration')
[docs] def resetter(self): """Reset the view""" self.view.browser.refresh()
@navigator.register(InfrastructureMappingCollection, 'Add')
[docs]class AddInfrastructureMapping(CFMENavigateStep): VIEW = AddInfrastructureMappingView prerequisite = NavigateToSibling('All')
[docs] def step(self): self.prerequisite_view.create_infrastructure_mapping.click()
@navigator.register(MigrationPlanCollection, 'Add')
[docs]class AddMigrationPlan(CFMENavigateStep): VIEW = AddMigrationPlanView prerequisite = NavigateToSibling('All')
[docs] def step(self): self.prerequisite_view.create_migration_plan.click()