From 27da43251f9069af1691f37ee2cb9012652d9e4c Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Fri, 13 Mar 2020 21:38:25 +0100 Subject: [PATCH 1/7] Cover 1670327 --- cfme/services/requests.py | 8 ++++ .../test_cloud_init_provisioning.py | 5 ++ .../test_provisioning_dialog.py | 48 +++++++++++++++---- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/cfme/services/requests.py b/cfme/services/requests.py index cdb829ab84..04b43985d3 100644 --- a/cfme/services/requests.py +++ b/cfme/services/requests.py @@ -407,6 +407,8 @@ class network(WaitTab): # noqa @View.nested class properties(WaitTab): # noqa + # Cloud providers only? + instance_type = SummaryFormItem('Properties', 'Instance Type') boot_disk_size = SummaryFormItem('Properties', 'Boot Disk Size ') is_preemptible = Checkbox(name='hardware__is_preemptible') @@ -431,6 +433,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 diff --git a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py index de8fcf699d..2b8bf40b1d 100644 --- a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py +++ b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py @@ -12,6 +12,7 @@ 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.generators import random_vm_name from cfme.utils.log import logger @@ -104,9 +105,11 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov 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 @@ -122,6 +125,7 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov @test_requirements.provision @pytest.mark.provider([RHEVMProvider]) +@pytest.mark.meta(automates=[1670327]) def test_provision_cloud_init_payload(appliance, request, setup_provider, provider, provisioning, vm_name): """ @@ -170,6 +174,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 diff --git a/cfme/tests/infrastructure/test_provisioning_dialog.py b/cfme/tests/infrastructure/test_provisioning_dialog.py index 247d2c7ca6..e7c4906cce 100644 --- a/cfme/tests/infrastructure/test_provisioning_dialog.py +++ b/cfme/tests/infrastructure/test_provisioning_dialog.py @@ -9,6 +9,7 @@ from widgetastic_patternfly import CheckableBootstrapTreeview as CbTree from cfme import test_requirements +from cfme.cloud.provider import CloudProvider from cfme.common import BaseLoggedInPage from cfme.infrastructure.provider import InfraProvider from cfme.infrastructure.provider.rhevm import RHEVMProvider @@ -23,6 +24,7 @@ from cfme.utils.wait import TimedOutError from cfme.utils.wait import wait_for + not_scvmm = ProviderFilter(classes=[SCVMMProvider], inverted=True) all_infra = ProviderFilter(classes=[InfraProvider], required_fields=[['provisioning', 'template'], @@ -35,7 +37,7 @@ pytest.mark.long_running, test_requirements.provision, pytest.mark.tier(3), - pytest.mark.provider(gen_func=providers, filters=[all_infra], scope="module"), + pytest.mark.provider(gen_func=providers, scope="module"), ] @@ -54,13 +56,17 @@ def prov_data(provisioning, provider): 'last_name': fauxfactory.gen_alphanumeric(), 'manager_name': fauxfactory.gen_alphanumeric(20, start="manager ")}, 'network': {'vlan': partial_match(provisioning.get('vlan'))}, - 'environment': {'datastore_name': {'name': provisioning['datastore']}, - 'host_name': {'name': provisioning['host']}}, 'catalog': {}, 'hardware': {}, 'schedule': {}, 'purpose': {}, } + + if provider.one_of(InfraProvider): + data['environment'] = { + 'datastore_name': {'name': provisioning['datastore']}, + 'host_name': {'name': provisioning['host']}} + if provider.one_of(RHEVMProvider): data['catalog']['provision_type'] = 'Native Clone' elif provider.one_of(VMwareProvider): @@ -73,9 +79,9 @@ def prov_data(provisioning, provider): def provisioner(appliance, request, setup_provider, provider, vm_name): def _provisioner(template, provisioning_data, delayed=None): - vm = appliance.collections.infra_vms.instantiate(name=vm_name, - provider=provider, - template_name=template) + collection = appliance.provider_based_collection(provider) + vm = collection.instantiate(name=vm_name, provider=provider, template_name=template) + provisioning_data['template_name'] = template provisioning_data['provider_name'] = provider.name view = navigate_to(vm.parent, 'Provision') @@ -84,11 +90,12 @@ def _provisioner(template, provisioning_data, delayed=None): base_view.flash.assert_no_error() request.addfinalizer( - lambda: appliance.collections.infra_vms.instantiate(vm_name, provider) - .cleanup_on_provider()) + lambda: vm.cleanup_on_provider()) request_description = f'Provision from [{template}] to [{vm_name}]' provision_request = appliance.collections.requests.instantiate( description=request_description) + check_all_tabs(provision_request, provider) + if delayed is not None: total_seconds = (delayed - datetime.utcnow()).total_seconds() try: @@ -115,6 +122,24 @@ def _provisioner(template, provisioning_data, delayed=None): return _provisioner +def check_all_tabs(provision_request, provider): + view = navigate_to(provision_request, "Details") + widgets_names = 'request', 'purpose', 'catalog', 'environment', 'schedule' + if provider.one_of(CloudProvider): + widgets_names += 'properties', 'volumes', 'customize' + elif provider.one_of(SCVMMProvider): + widgets_names += 'environment', 'hardware', 'network' + elif provider.one_of(InfraProvider): + widgets_names += 'hardware', 'network', 'customize' + else: + raise NotImplementedError(f"Couldn't determine which tabs to check for " + "this provider: {provider}") + + for name in widgets_names: + widget = getattr(view, name) + widget.click() + + @pytest.mark.meta(blockers=[BZ(1627673, forced_streams=['5.10'])]) def test_change_cpu_ram(provisioner, soft_assert, provider, prov_data, vm_name): """ Tests change RAM and CPU in provisioning dialog. @@ -141,7 +166,11 @@ def test_change_cpu_ram(provisioner, soft_assert, provider, prov_data, vm_name): prov_data['hardware']["num_sockets"] = "4" prov_data['hardware']["cores_per_socket"] = "1" if not provider.one_of(SCVMMProvider) else None prov_data['hardware']["memory"] = "2048" - template_name = provider.data['provisioning']['template'] + if provider.one_of(CloudProvider): + template_name = provider.data['provisioning']['image']['name'] + else: + template_name = provider.data['provisioning']['template'] + vm = provisioner(template_name, prov_data) # Go to the VM info @@ -228,6 +257,7 @@ def test_disk_format_select(provisioner, disk_format, provider, prov_data, vm_na @pytest.mark.parametrize("started", [True, False]) +@pytest.mark.meta(automates=[1670327]) def test_power_on_or_off_after_provision(provisioner, prov_data, provider, started, vm_name): """ Tests setting the desired power state after provisioning. From 86b35c74311cd9ba8d20b5524319c5e213363127 Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Wed, 18 Mar 2020 16:55:35 +0100 Subject: [PATCH 2/7] Autoselect provision source by provider. --- .../test_cloud_init_provisioning.py | 2 + .../test_provisioning_dialog.py | 65 +++++++++++-------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py index 2b8bf40b1d..bf627189b6 100644 --- a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py +++ b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py @@ -89,6 +89,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): @@ -98,6 +99,7 @@ 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' diff --git a/cfme/tests/infrastructure/test_provisioning_dialog.py b/cfme/tests/infrastructure/test_provisioning_dialog.py index e7c4906cce..9f7e21ef0a 100644 --- a/cfme/tests/infrastructure/test_provisioning_dialog.py +++ b/cfme/tests/infrastructure/test_provisioning_dialog.py @@ -10,6 +10,9 @@ from cfme import test_requirements from cfme.cloud.provider import CloudProvider +from cfme.cloud.provider.azure import AzureProvider +from cfme.cloud.provider.ec2 import EC2Provider +from cfme.cloud.provider.openstack import OpenStackProvider from cfme.common import BaseLoggedInPage from cfme.infrastructure.provider import InfraProvider from cfme.infrastructure.provider.rhevm import RHEVMProvider @@ -41,6 +44,13 @@ ] +def prov_source(provider): + if provider.one_of(CloudProvider): + return provider.data['provisioning']['image']['name'] + else: + return provider.data['provisioning']['template'] + + @pytest.fixture(scope="function") def vm_name(): vm_name = random_vm_name('provd') @@ -49,23 +59,35 @@ def vm_name(): @pytest.fixture(scope="function") def prov_data(provisioning, provider): - data = { + # TODO Perhaps merge this with stuff with test_cloud_init_provisioning.test_provision_cloud_init + data = dict(provisioning, **{ 'request': { 'email': fauxfactory.gen_email(), 'first_name': fauxfactory.gen_alphanumeric(), 'last_name': fauxfactory.gen_alphanumeric(), 'manager_name': fauxfactory.gen_alphanumeric(20, start="manager ")}, - 'network': {'vlan': partial_match(provisioning.get('vlan'))}, 'catalog': {}, 'hardware': {}, 'schedule': {}, 'purpose': {}, - } + }) + + mgmt_system = provider.mgmt if provider.one_of(InfraProvider): + data['network'] = {'vlan': partial_match(provisioning.get('vlan'))} data['environment'] = { 'datastore_name': {'name': provisioning['datastore']}, 'host_name': {'name': provisioning['host']}} + elif provider.one_of(AzureProvider): + data['environment'] = {'public_ip_address': "New"} + elif provider.one_of(OpenStackProvider): + ip_pool = provider.data['public_network'] + floating_ip = mgmt_system.get_first_floating_ip(pool=ip_pool) + provider.refresh_provider_relationships() + data['environment'] = {'public_ip_address': floating_ip} + props = data.setdefault('properties', {}) + props['instance_type'] = partial_match(provisioning['ci-flavor-name']) if provider.one_of(RHEVMProvider): data['catalog']['provision_type'] = 'Native Clone' @@ -80,12 +102,10 @@ def provisioner(appliance, request, setup_provider, provider, vm_name): def _provisioner(template, provisioning_data, delayed=None): collection = appliance.provider_based_collection(provider) - vm = collection.instantiate(name=vm_name, provider=provider, template_name=template) - provisioning_data['template_name'] = template provisioning_data['provider_name'] = provider.name - view = navigate_to(vm.parent, 'Provision') - view.form.fill_with(provisioning_data, on_change=view.form.submit_button) + vm = collection.create(vm_name, provider, form_values=provisioning_data) + base_view = vm.appliance.browser.create_view(BaseLoggedInPage) base_view.flash.assert_no_error() @@ -125,7 +145,9 @@ def _provisioner(template, provisioning_data, delayed=None): def check_all_tabs(provision_request, provider): view = navigate_to(provision_request, "Details") widgets_names = 'request', 'purpose', 'catalog', 'environment', 'schedule' - if provider.one_of(CloudProvider): + if provider.one_of(EC2Provider): + widgets_names += 'properties', 'customize' + elif provider.one_of(CloudProvider): widgets_names += 'properties', 'volumes', 'customize' elif provider.one_of(SCVMMProvider): widgets_names += 'environment', 'hardware', 'network' @@ -141,6 +163,7 @@ def check_all_tabs(provision_request, provider): @pytest.mark.meta(blockers=[BZ(1627673, forced_streams=['5.10'])]) +@pytest.mark.provider(gen_func=providers, filters=[all_infra], scope="module") def test_change_cpu_ram(provisioner, soft_assert, provider, prov_data, vm_name): """ Tests change RAM and CPU in provisioning dialog. @@ -166,12 +189,8 @@ def test_change_cpu_ram(provisioner, soft_assert, provider, prov_data, vm_name): prov_data['hardware']["num_sockets"] = "4" prov_data['hardware']["cores_per_socket"] = "1" if not provider.one_of(SCVMMProvider) else None prov_data['hardware']["memory"] = "2048" - if provider.one_of(CloudProvider): - template_name = provider.data['provisioning']['image']['name'] - else: - template_name = provider.data['provisioning']['template'] - vm = provisioner(template_name, prov_data) + vm = provisioner(prov_source(provider), prov_data) # Go to the VM info view = navigate_to(vm, "Details") @@ -241,9 +260,8 @@ def test_disk_format_select(provisioner, disk_format, provider, prov_data, vm_na prov_data['catalog']['vm_name'] = vm_name prov_data['hardware']["disk_format"] = disk_format - template_name = provider.data['provisioning']['template'] - vm = provisioner(template_name, prov_data) + vm = provisioner(prov_source(provider), prov_data) # Go to the VM info view = navigate_to(vm, 'Details') @@ -258,6 +276,7 @@ def test_disk_format_select(provisioner, disk_format, provider, prov_data, vm_na @pytest.mark.parametrize("started", [True, False]) @pytest.mark.meta(automates=[1670327]) +@pytest.mark.provider(gen_func=providers, filters=[all_infra], scope="module") def test_power_on_or_off_after_provision(provisioner, prov_data, provider, started, vm_name): """ Tests setting the desired power state after provisioning. @@ -282,9 +301,8 @@ def test_power_on_or_off_after_provision(provisioner, prov_data, provider, start """ prov_data['catalog']['vm_name'] = vm_name prov_data['schedule']["power_on"] = started - template_name = provider.data['provisioning']['template'] - vm = provisioner(template_name, prov_data) + vm = provisioner(prov_source(provider), prov_data) wait_for( lambda: vm.exists_on_provider and @@ -317,9 +335,8 @@ def test_tag(provisioner, prov_data, provider, vm_name): """ prov_data['catalog']['vm_name'] = vm_name prov_data['purpose']["apply_tags"] = CbTree.CheckNode(path=("Service Level *", "Gold")) - template_name = provider.data['provisioning']['template'] - vm = provisioner(template_name, prov_data) + vm = provisioner(prov_source(provider), prov_data) tags = vm.get_tags() assert any( @@ -363,9 +380,7 @@ def test_provisioning_schedule(provisioner, provider, prov_data, vm_name): prov_data['schedule']["provision_start_hour"] = str(provision_time.hour) prov_data['schedule']["provision_start_min"] = str(provision_time.minute) - template_name = provider.data['provisioning']['template'] - - provisioner(template_name, prov_data, delayed=provision_time) + provisioner(prov_source(provider), prov_data, delayed=provision_time) @pytest.mark.provider([RHEVMProvider], @@ -399,9 +414,8 @@ def test_provisioning_vnic_profiles(provisioner, provider, prov_data, vm_name, v """ prov_data['catalog']['vm_name'] = vm_name prov_data['network'] = {'vlan': vnic_profile} - template_name = provider.data['provisioning']['template'] - vm = provisioner(template_name, prov_data) + vm = provisioner(prov_source(provider), prov_data) wait_for( lambda: vm.exists_on_provider, @@ -481,11 +495,10 @@ def test_vmware_default_placement(provisioner, prov_data, provider, setup_provid casecomponent: Provisioning initialEstimate: 1/4h """ - template_name = provider.data['provisioning']['template'] prov_data['catalog']['vm_name'] = vm_name prov_data['environment'] = {'automatic_placement': True} - vm = provisioner(template_name, prov_data) + vm = provisioner(prov_source(provider), prov_data) wait_for( lambda: vm.exists_on_provider, From 9b8dea0edc8e984818080db26c543f3f8cedf61c Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Thu, 19 Mar 2020 18:55:43 +0100 Subject: [PATCH 3/7] Correct the automates marker to BZ 1797706. --- cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py | 2 +- cfme/tests/infrastructure/test_provisioning_dialog.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py index bf627189b6..0504e17bff 100644 --- a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py +++ b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py @@ -127,7 +127,7 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov @test_requirements.provision @pytest.mark.provider([RHEVMProvider]) -@pytest.mark.meta(automates=[1670327]) +@pytest.mark.meta(automates=[1797706]) def test_provision_cloud_init_payload(appliance, request, setup_provider, provider, provisioning, vm_name): """ diff --git a/cfme/tests/infrastructure/test_provisioning_dialog.py b/cfme/tests/infrastructure/test_provisioning_dialog.py index 9f7e21ef0a..efd16097cd 100644 --- a/cfme/tests/infrastructure/test_provisioning_dialog.py +++ b/cfme/tests/infrastructure/test_provisioning_dialog.py @@ -275,7 +275,7 @@ def test_disk_format_select(provisioner, disk_format, provider, prov_data, vm_na @pytest.mark.parametrize("started", [True, False]) -@pytest.mark.meta(automates=[1670327]) +@pytest.mark.meta(automates=[1797706]) @pytest.mark.provider(gen_func=providers, filters=[all_infra], scope="module") def test_power_on_or_off_after_provision(provisioner, prov_data, provider, started, vm_name): """ Tests setting the desired power state after provisioning. From 0807082133496d9bf257400190fc6a47f8c452a9 Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Fri, 20 Mar 2020 14:33:23 +0100 Subject: [PATCH 4/7] Add template cloning. --- cfme/common/vm.py | 31 +++++++++++++ cfme/infrastructure/virtual_machines.py | 30 +++++-------- .../test_provisioning_dialog.py | 1 + cfme/tests/infrastructure/test_vm_clone.py | 44 ++++++++++++++++++- 4 files changed, 85 insertions(+), 21 deletions(-) diff --git a/cfme/common/vm.py b/cfme/common/vm.py index 714c69d041..327e7cfa03 100644 --- a/cfme/common/vm.py +++ b/cfme/common/vm.py @@ -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 @@ -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 @@ -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 @@ -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): diff --git a/cfme/infrastructure/virtual_machines.py b/cfme/infrastructure/virtual_machines.py index 6a78188915..62638de070 100644 --- a/cfme/infrastructure/virtual_machines.py +++ b/cfme/infrastructure/virtual_machines.py @@ -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') @@ -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 diff --git a/cfme/tests/infrastructure/test_provisioning_dialog.py b/cfme/tests/infrastructure/test_provisioning_dialog.py index efd16097cd..9954fb9d2f 100644 --- a/cfme/tests/infrastructure/test_provisioning_dialog.py +++ b/cfme/tests/infrastructure/test_provisioning_dialog.py @@ -160,6 +160,7 @@ def check_all_tabs(provision_request, provider): for name in widgets_names: widget = getattr(view, name) widget.click() + assert widget.is_displayed @pytest.mark.meta(blockers=[BZ(1627673, forced_streams=['5.10'])]) diff --git a/cfme/tests/infrastructure/test_vm_clone.py b/cfme/tests/infrastructure/test_vm_clone.py index 3ee12b4a7d..50844997a4 100644 --- a/cfme/tests/infrastructure/test_vm_clone.py +++ b/cfme/tests/infrastructure/test_vm_clone.py @@ -4,8 +4,11 @@ from cfme import test_requirements from cfme.infrastructure.provider import InfraProvider +from cfme.infrastructure.provider.rhevm import RHEVMProvider +from cfme.infrastructure.provider.scvmm import SCVMMProvider from cfme.infrastructure.provider.virtualcenter import VMwareProvider from cfme.markers.env_markers.provider import providers +from cfme.tests.infrastructure.test_provisioning_dialog import check_all_tabs from cfme.utils.blockers import BZ from cfme.utils.log import logger from cfme.utils.providers import ProviderFilter @@ -48,7 +51,7 @@ def create_vm(appliance, provider, request): @pytest.mark.provider([VMwareProvider], **filter_fields) -@pytest.mark.meta(blockers=[BZ(1685201)]) +@pytest.mark.meta(automates=[BZ(1685201)]) @test_requirements.provision def test_vm_clone(appliance, provider, clone_vm_name, create_vm): """ @@ -62,6 +65,45 @@ def test_vm_clone(appliance, provider, clone_vm_name, create_vm): request_description = clone_vm_name request_row = appliance.collections.requests.instantiate(request_description, partial_check=True) + check_all_tabs(request_row, provider) + request_row.wait_for_request(method='ui') + msg = f"Request failed with the message {request_row.row.last_message.text}" + assert request_row.is_succeeded(method='ui'), msg + + +@pytest.mark.provider([VMwareProvider, RHEVMProvider, SCVMMProvider], **filter_fields) +@test_requirements.provision +@pytest.mark.meta(automates=[BZ(1797733), BZ(1797706)]) +def test_template_clone(request, appliance, provider, clone_vm_name): + """ + Polarion: + assignee: jhenner + casecomponent: Provisioning + initialEstimate: 1/6h + caseimportance: high + """ + cloned_template_name = provider.data['provisioning']['template'] + vm = appliance.collections.infra_templates.instantiate(cloned_template_name, provider) + + if provider.one_of(VMwareProvider): + provision_type = 'VMware' + else: + provision_type = 'Native Clone' + + @request.addfinalizer + def template_clone_deltion(): + collections = appliance.collections + if BZ(1797733).blocks: + cloned_template = collections.infra_vms.instantiate(clone_vm_name, provider) + else: + cloned_template = collections.infra_templates.instantiate(clone_vm_name, provider) + cloned_template.delete() + + vm.clone_template("email@xyz.com", "first", "last", clone_vm_name, provision_type) + request_row = appliance.collections.requests.instantiate(clone_vm_name, partial_check=True) + + if not BZ(1797706).blocks and provider.one_of(RHEVMProvider): + check_all_tabs(request_row, provider) request_row.wait_for_request(method='ui') msg = f"Request failed with the message {request_row.row.last_message.text}" assert request_row.is_succeeded(method='ui'), msg From 279f0d999750892021a264a02f456ee7f27dcbb6 Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Mon, 23 Mar 2020 14:26:54 +0100 Subject: [PATCH 5/7] Add skip for BZ 1797706 --- cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py | 3 +++ cfme/tests/infrastructure/test_provisioning_dialog.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py index 0504e17bff..1041038572 100644 --- a/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py +++ b/cfme/tests/cloud_infra_common/test_cloud_init_provisioning.py @@ -14,6 +14,7 @@ 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 @@ -60,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 @@ -69,6 +71,7 @@ def test_provision_cloud_init(appliance, request, setup_provider, provider, prov Bugzilla: 1619744 + 1797706 Polarion: assignee: jhenner diff --git a/cfme/tests/infrastructure/test_provisioning_dialog.py b/cfme/tests/infrastructure/test_provisioning_dialog.py index 9954fb9d2f..1eb2e301ad 100644 --- a/cfme/tests/infrastructure/test_provisioning_dialog.py +++ b/cfme/tests/infrastructure/test_provisioning_dialog.py @@ -160,6 +160,9 @@ def check_all_tabs(provision_request, provider): for name in widgets_names: widget = getattr(view, name) widget.click() + bz_1726590_in_effect = BZ(1797706).blocks and provider.one_of(RHEVMProvider) + if bz_1726590_in_effect: + pytest.skip('Skipping as this fails due to BZ 1797706') assert widget.is_displayed From 3c1a2ec509edf63b4eb48954454befaa6768b057 Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Thu, 2 Apr 2020 13:13:07 +0200 Subject: [PATCH 6/7] Review fixes --- cfme/services/requests.py | 2 -- .../test_provisioning_dialog.py | 19 +++++++++++-------- cfme/tests/infrastructure/test_vm_clone.py | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/cfme/services/requests.py b/cfme/services/requests.py index 04b43985d3..faf769c060 100644 --- a/cfme/services/requests.py +++ b/cfme/services/requests.py @@ -407,8 +407,6 @@ class network(WaitTab): # noqa @View.nested class properties(WaitTab): # noqa - # Cloud providers only? - instance_type = SummaryFormItem('Properties', 'Instance Type') boot_disk_size = SummaryFormItem('Properties', 'Boot Disk Size ') is_preemptible = Checkbox(name='hardware__is_preemptible') diff --git a/cfme/tests/infrastructure/test_provisioning_dialog.py b/cfme/tests/infrastructure/test_provisioning_dialog.py index 1eb2e301ad..063e2e6037 100644 --- a/cfme/tests/infrastructure/test_provisioning_dialog.py +++ b/cfme/tests/infrastructure/test_provisioning_dialog.py @@ -144,24 +144,27 @@ def _provisioner(template, provisioning_data, delayed=None): def check_all_tabs(provision_request, provider): view = navigate_to(provision_request, "Details") - widgets_names = 'request', 'purpose', 'catalog', 'environment', 'schedule' + + widget_names = 'request', 'purpose', 'catalog', 'environment', 'schedule' + # Note the order of these branch checks is important as, for example, + # EC2Provider is subclass of CloudProvider and thus incorrect branch may + # get executed. if provider.one_of(EC2Provider): - widgets_names += 'properties', 'customize' + widget_names += 'properties', 'customize' elif provider.one_of(CloudProvider): - widgets_names += 'properties', 'volumes', 'customize' + widget_names += 'properties', 'volumes', 'customize' elif provider.one_of(SCVMMProvider): - widgets_names += 'environment', 'hardware', 'network' + widget_names += 'environment', 'hardware', 'network' elif provider.one_of(InfraProvider): - widgets_names += 'hardware', 'network', 'customize' + widget_names += 'hardware', 'network', 'customize' else: raise NotImplementedError(f"Couldn't determine which tabs to check for " "this provider: {provider}") - for name in widgets_names: + for name in widget_names: widget = getattr(view, name) widget.click() - bz_1726590_in_effect = BZ(1797706).blocks and provider.one_of(RHEVMProvider) - if bz_1726590_in_effect: + if BZ(1797706).blocks and provider.one_of(RHEVMProvider): pytest.skip('Skipping as this fails due to BZ 1797706') assert widget.is_displayed diff --git a/cfme/tests/infrastructure/test_vm_clone.py b/cfme/tests/infrastructure/test_vm_clone.py index 50844997a4..f57d0574ac 100644 --- a/cfme/tests/infrastructure/test_vm_clone.py +++ b/cfme/tests/infrastructure/test_vm_clone.py @@ -91,7 +91,7 @@ def test_template_clone(request, appliance, provider, clone_vm_name): provision_type = 'Native Clone' @request.addfinalizer - def template_clone_deltion(): + def template_clone_cleanup(): collections = appliance.collections if BZ(1797733).blocks: cloned_template = collections.infra_vms.instantiate(clone_vm_name, provider) From 637b1ebdf1f7b40dcaa2d802d490f4ef9a597a68 Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Mon, 6 Apr 2020 14:26:27 +0200 Subject: [PATCH 7/7] Use OOP instead of instanceof. --- cfme/cloud/provider/__init__.py | 2 ++ cfme/cloud/provider/ec2.py | 3 +++ cfme/common/provider.py | 1 + cfme/infrastructure/provider/__init__.py | 2 ++ cfme/infrastructure/provider/scvmm.py | 2 ++ .../test_provisioning_dialog.py | 19 +------------------ 6 files changed, 11 insertions(+), 18 deletions(-) diff --git a/cfme/cloud/provider/__init__.py b/cfme/cloud/provider/__init__.py index b85c616d00..33e065cf4e 100644 --- a/cfme/cloud/provider/__init__.py +++ b/cfme/cloud/provider/__init__.py @@ -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) diff --git a/cfme/cloud/provider/ec2.py b/cfme/cloud/provider/ec2.py index aee3b51b7d..4fa91d2239 100644 --- a/cfme/cloud/provider/ec2.py +++ b/cfme/cloud/provider/ec2.py @@ -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""" diff --git a/cfme/common/provider.py b/cfme/common/provider.py index 3c04783f0a..8ce84d34ba 100644 --- a/cfme/common/provider.py +++ b/cfme/common/provider.py @@ -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 diff --git a/cfme/infrastructure/provider/__init__.py b/cfme/infrastructure/provider/__init__.py index a2a800dc47..d4b7c52de9 100644 --- a/cfme/infrastructure/provider/__init__.py +++ b/cfme/infrastructure/provider/__init__.py @@ -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) diff --git a/cfme/infrastructure/provider/scvmm.py b/cfme/infrastructure/provider/scvmm.py index 14d1412963..f9e83fcab5 100644 --- a/cfme/infrastructure/provider/scvmm.py +++ b/cfme/infrastructure/provider/scvmm.py @@ -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'}) @property def view_value_mapping(self): diff --git a/cfme/tests/infrastructure/test_provisioning_dialog.py b/cfme/tests/infrastructure/test_provisioning_dialog.py index 063e2e6037..4095e2f7ba 100644 --- a/cfme/tests/infrastructure/test_provisioning_dialog.py +++ b/cfme/tests/infrastructure/test_provisioning_dialog.py @@ -11,7 +11,6 @@ from cfme import test_requirements from cfme.cloud.provider import CloudProvider from cfme.cloud.provider.azure import AzureProvider -from cfme.cloud.provider.ec2 import EC2Provider from cfme.cloud.provider.openstack import OpenStackProvider from cfme.common import BaseLoggedInPage from cfme.infrastructure.provider import InfraProvider @@ -145,23 +144,7 @@ def _provisioner(template, provisioning_data, delayed=None): def check_all_tabs(provision_request, provider): view = navigate_to(provision_request, "Details") - widget_names = 'request', 'purpose', 'catalog', 'environment', 'schedule' - # Note the order of these branch checks is important as, for example, - # EC2Provider is subclass of CloudProvider and thus incorrect branch may - # get executed. - if provider.one_of(EC2Provider): - widget_names += 'properties', 'customize' - elif provider.one_of(CloudProvider): - widget_names += 'properties', 'volumes', 'customize' - elif provider.one_of(SCVMMProvider): - widget_names += 'environment', 'hardware', 'network' - elif provider.one_of(InfraProvider): - widget_names += 'hardware', 'network', 'customize' - else: - raise NotImplementedError(f"Couldn't determine which tabs to check for " - "this provider: {provider}") - - for name in widget_names: + for name in provider.provisioning_dialog_widget_names: widget = getattr(view, name) widget.click() if BZ(1797706).blocks and provider.one_of(RHEVMProvider):