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 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()