Skip to content
This repository has been archived by the owner on Apr 7, 2022. It is now read-only.

[1LP][RFR] Cover provisioning issues #9985

Merged
merged 7 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cfme/cloud/provider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ class CloudProvider(BaseProvider, CloudInfraProviderMixin, Pretty, PolicyProfile
db_types = ["CloudManager"]
template_class = Image
collection_name = 'cloud_providers'
provisioning_dialog_widget_names = BaseProvider.provisioning_dialog_widget_names.union({
'properties', 'volumes', 'customize'})

name = attr.ib(default=None)
key = attr.ib(default=None)
Expand Down
3 changes: 3 additions & 0 deletions cfme/cloud/provider/ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ class EC2Provider(CloudProvider):
region = attr.ib(default=None)
region_name = attr.ib(default=None)

provisioning_dialog_widget_names = CloudProvider.provisioning_dialog_widget_names.difference(
{'volumes'})

@property
def view_value_mapping(self):
"""Maps values to view attrs"""
Expand Down
1 change: 1 addition & 0 deletions cfme/common/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class BaseProvider(Taggable, Updateable, Navigatable, BaseEntity, CustomButtonEv
_param_name = ParamClassName('name')
STATS_TO_MATCH = []
db_types = ["Providers"]
provisioning_dialog_widget_names = {'request', 'purpose', 'catalog', 'environment', 'schedule'}
ems_events = []
settings_key = None
vm_class = None # Set on type specific provider classes for VM/instance class
Expand Down
31 changes: 31 additions & 0 deletions cfme/common/vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
from datetime import datetime

import attr
import fauxfactory
from cached_property import cached_property
from manageiq_client.filters import Q
from navmazing import NavigateToSibling
from riggerlib import recursive_update
from widgetastic.exceptions import NoSuchElementException
from widgetastic.utils import partial_match

from cfme.common import BaseLoggedInPage
from cfme.common import CustomButtonEventsMixin
Expand All @@ -33,6 +35,7 @@
from cfme.utils.appliance.implementations.ui import navigate_to
from cfme.utils.appliance.implementations.ui import navigator
from cfme.utils.blockers import BZ
from cfme.utils.conf import cfme_data
from cfme.utils.log import logger
from cfme.utils.net import find_pingable
from cfme.utils.pretty import Pretty
Expand Down Expand Up @@ -274,6 +277,29 @@ def delete(self, cancel=False, from_details=False):
self.find_quadicon().ensure_checked()
view.toolbar.configuration.item_select(self.REMOVE_SELECTED, handle_alert=not cancel)

def _fill_clone_form(self, view, email=None, first_name=None, last_name=None,
new_name=None, provision_type=None):
first_name = first_name or fauxfactory.gen_alphanumeric()
last_name = last_name or fauxfactory.gen_alphanumeric()
email = email or f"{first_name}@{last_name}.test"
try:
prov_data = cfme_data["management_systems"][self.provider.key]["provisioning"]
except (KeyError, IndexError):
raise ValueError("You have to specify the correct options in cfme_data.yaml")

provisioning_data = {
'catalog': {'vm_name': new_name,
'provision_type': provision_type},
'request': {
'email': email,
'first_name': first_name,
'last_name': last_name},
'environment': {"host_name": {'name': prov_data.get("host")},
"datastore_name": {"name": prov_data.get("datastore")}},
'network': {'vlan': partial_match(prov_data.get("vlan"))},
}
view.form.fill_with(provisioning_data, on_change=view.form.submit_button)

@property
def ip_address(self):
"""Fetches IP Address of VM
Expand Down Expand Up @@ -1074,6 +1100,11 @@ def mgmt(self):
def exists_on_provider(self):
return self.provider.mgmt.does_template_exist(self.name)

def clone_template(self, email=None, first_name=None, last_name=None,
new_name=None, provision_type=None):
view = navigate_to(self, 'CloneTemplate')
self._fill_clone_form(view, email, first_name, last_name, new_name, provision_type)


@attr.s
class TemplateCollection(BaseVMCollection):
Expand Down
2 changes: 2 additions & 0 deletions cfme/infrastructure/provider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ class InfraProvider(BaseProvider, CloudInfraProviderMixin, Pretty, Fillable,
hosts_menu_item = "Hosts"
vm_name = "Virtual Machines"
collection_name = 'infra_providers'
provisioning_dialog_widget_names = BaseProvider.provisioning_dialog_widget_names.union(
{'hardware', 'network', 'customize'})

name = attr.ib(default=None)
key = attr.ib(default=None)
Expand Down
2 changes: 2 additions & 0 deletions cfme/infrastructure/provider/scvmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class SCVMMProvider(InfraProvider):
settings_key = 'ems_scvmm'
ui_prov_type = 'Microsoft System Center VMM'
log_name = 'scvmm'
provisioning_dialog_widget_names = (InfraProvider.provisioning_dialog_widget_names
- {'environment'} | {'customize'})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious but how is this different from - {'environment', 'customize'}?

Copy link
Contributor Author

@jarovo jarovo May 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first I was like WTF have I done here, but it is different. So perhaps I should rephrase this bit a bit to make it more clear for the reader.

The problem is the operator priority. The result of

(SOME_SET  - {'environment'} | {'customize'})

does always include the 'customize' while result of

(SOME_SET  - {'environment', 'customize'})

never does.

Should I change this to

((SOME_SET  - {'environment'}) | {'customize'})

pattern?

Or rather

SOME_SET.difference({'environment'}).union('{customize'})

or

newset = set(SOME_SET)
newset -= {'environment'}
newset |= '{customize'}

What do you guys find more clear?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, I'd say SOME_SET.difference({'environment'}).union('{customize'}) is the most clear, and is consistent with your use of union and difference in the other providers.

That said, the logic is sound, and the clarity is subjective, not going to block the PR on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mshriver Ok. I will try keeping this in mind and use this form.


@property
def view_value_mapping(self):
Expand Down
30 changes: 10 additions & 20 deletions cfme/infrastructure/virtual_machines.py
Original file line number Diff line number Diff line change
Expand Up @@ -948,26 +948,7 @@ def migrate_vm(self, email=None, first_name=None, last_name=None,
def clone_vm(self, email=None, first_name=None, last_name=None,
vm_name=None, provision_type=None):
view = navigate_to(self, 'Clone')
first_name = first_name or fauxfactory.gen_alphanumeric()
last_name = last_name or fauxfactory.gen_alphanumeric()
email = email or f"{first_name}@{last_name}.test"
try:
prov_data = cfme_data["management_systems"][self.provider.key]["provisioning"]
except (KeyError, IndexError):
raise ValueError("You have to specify the correct options in cfme_data.yaml")

provisioning_data = {
'catalog': {'vm_name': vm_name,
'provision_type': provision_type},
'request': {
'email': email,
'first_name': first_name,
'last_name': last_name},
'environment': {"host_name": {'name': prov_data.get("host")},
"datastore_name": {"name": prov_data.get("datastore")}},
'network': {'vlan': partial_match(prov_data.get("vlan"))},
}
view.form.fill_with(provisioning_data, on_change=view.form.submit_button)
self._fill_clone_form(view, email, first_name, last_name, vm_name, provision_type)

def publish_to_template(self, template_name, email=None, first_name=None, last_name=None):
view = navigate_to(self, 'Publish')
Expand Down Expand Up @@ -1736,6 +1717,15 @@ def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.configuration.item_select('Set Ownership')


@navigator.register(InfraTemplate, 'CloneTemplate')
class TemplateClone(CFMENavigateStep):
VIEW = CloneVmView
prerequisite = NavigateToSibling('Details')

def step(self, *args, **kwargs):
self.prerequisite_view.toolbar.lifecycle.item_select("Clone this Template")


@navigator.register(InfraVm, 'Rename')
class Rename(CFMENavigateStep):
VIEW = RenameVmView
Expand Down
6 changes: 6 additions & 0 deletions cfme/services/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,12 @@ class schedule(WaitTab): # noqa
retirement = SummaryFormItem('Lifespan', 'Time until Retirement')
retirement_warning = SummaryFormItem('Lifespan', 'Retirement Warning')

@View.nested
class volumes(WaitTab): # noqa
volume_name = SummaryFormItem('Volumes', 'Volume Name')
volume_size = SummaryFormItem('Volumes', 'Size (gigabytes)')
delete_on_terminate = Checkbox(name='volumes__delete_on_terminate_1')

@property
def is_displayed(self):
expected_description = self.context['object'].rest.description
Expand Down
10 changes: 10 additions & 0 deletions cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
from cfme.infrastructure.provider.scvmm import SCVMMProvider
from cfme.infrastructure.pxe import get_template_from_config
from cfme.markers.env_markers.provider import providers
from cfme.tests.infrastructure.test_provisioning_dialog import check_all_tabs
from cfme.utils import ssh
from cfme.utils.blockers import BZ
from cfme.utils.generators import random_vm_name
from cfme.utils.log import logger
from cfme.utils.providers import ProviderFilter
Expand Down Expand Up @@ -59,6 +61,7 @@ def vm_name():

@pytest.mark.tier(3)
@test_requirements.provision
@pytest.mark.meta(automates=[BZ(1797706)])
def test_provision_cloud_init(appliance, request, setup_provider, provider, provisioning,
setup_ci_template, vm_name):
""" Tests provisioning from a template with cloud_init
Expand All @@ -68,6 +71,7 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov

Bugzilla:
1619744
1797706

Polarion:
assignee: jhenner
Expand All @@ -88,6 +92,7 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov
# for image selection in before_fill
inst_args['template_name'] = image

# TODO Perhaps merge this with stuff in test_provisioning_dialog.prov_data
if provider.one_of(AzureProvider):
inst_args['environment'] = {'public_ip_address': "New"}
if provider.one_of(OpenStackProvider):
Expand All @@ -97,16 +102,19 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov
inst_args['environment'] = {'public_ip_address': floating_ip}
inst_arg_props = inst_args.setdefault('properties', {})
inst_arg_props['instance_type'] = partial_match(provisioning['ci-flavor-name'])

if provider.one_of(InfraProvider) and appliance.version > '5.9':
inst_args['customize']['customize_type'] = 'Specification'

logger.info(f'Instance args: {inst_args}')

collection = appliance.provider_based_collection(provider)
instance = collection.create(vm_name, provider, form_values=inst_args)

request.addfinalizer(instance.cleanup_on_provider)
provision_request = provider.appliance.collections.requests.instantiate(vm_name,
partial_check=True)
check_all_tabs(provision_request, provider)
provision_request.wait_for_request()
wait_for(lambda: instance.ip_address is not None, num_sec=600)
connect_ip = instance.ip_address
Expand All @@ -122,6 +130,7 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov

@test_requirements.provision
@pytest.mark.provider([RHEVMProvider])
@pytest.mark.meta(automates=[1797706])
def test_provision_cloud_init_payload(appliance, request, setup_provider, provider, provisioning,
vm_name):
"""
Expand Down Expand Up @@ -170,6 +179,7 @@ def test_provision_cloud_init_payload(appliance, request, setup_provider, provid
request.addfinalizer(instance.cleanup_on_provider)
provision_request = provider.appliance.collections.requests.instantiate(vm_name,
partial_check=True)
check_all_tabs(provision_request, provider)
provision_request.wait_for_request()

connect_ip = wait_for(find_global_ipv6, func_args=[instance], num_sec=600, delay=20).out
Expand Down
Loading