diff --git a/ironic_tempest_plugin/services/baremetal/base.py b/ironic_tempest_plugin/services/baremetal/base.py index c588a70..e1c1d71 100644 --- a/ironic_tempest_plugin/services/baremetal/base.py +++ b/ironic_tempest_plugin/services/baremetal/base.py @@ -212,18 +212,21 @@ class BaremetalClient(rest_client.RestClient): return resp - def _delete_request(self, resource, uuid): + def _delete_request(self, resource, uuid, + expected_status=http_client.NO_CONTENT): """Delete specified object. :param resource: The name of the REST resource, e.g., 'nodes'. :param uuid: The unique identifier of an object in UUID format. + :param expected_status: Expected response status code. By default is + http_client.NO_CONTENT (204) :returns: A tuple with the server response and the response body. """ uri = self._get_uri(resource, uuid) resp, body = self.delete(uri) - self.expected_success(http_client.NO_CONTENT, resp.status) + self.expected_success(expected_status, resp.status) return resp, body def _patch_request(self, resource, uuid, patch_object): diff --git a/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py b/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py index 9eb5d7f..8650b76 100644 --- a/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py +++ b/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py @@ -274,15 +274,18 @@ class BaremetalStandaloneManager(bm.BaremetalScenarioTest, :param node_id: Name or UUID for the node. """ cls.detach_all_vifs_from_node(node_id) - cls.set_node_provision_state(node_id, 'deleted') - # NOTE(vsaienko) We expect here fast switching from deleted to - # available as automated cleaning is disabled so poll status each 1s. - cls.wait_provisioning_state( - node_id, - [bm.BaremetalProvisionStates.NOSTATE, - bm.BaremetalProvisionStates.AVAILABLE], - timeout=CONF.baremetal.unprovision_timeout, - interval=1) + + if cls.delete_node: + cls.set_node_provision_state(node_id, 'deleted') + # NOTE(vsaienko) We expect here fast switching from deleted to + # available as automated cleaning is disabled so poll status + # each 1s. + cls.wait_provisioning_state( + node_id, + [bm.BaremetalProvisionStates.NOSTATE, + bm.BaremetalProvisionStates.AVAILABLE], + timeout=CONF.baremetal.unprovision_timeout, + interval=1) @classmethod def rescue_node(cls, node_id, rescue_password): @@ -305,6 +308,63 @@ class BaremetalStandaloneManager(bm.BaremetalScenarioTest, timeout=CONF.baremetal.unrescue_timeout, interval=1) + def manual_cleaning(self, node, clean_steps): + """Performs manual cleaning. + + The following actions are executed: + * Expects node to be in available state. + * Brings the node to manageable state. + * Do manual cleaning. + * Brings the node back to original available. + + :param node: Ironic node to associate instance_uuid with. + :param clean_steps: clean steps for manual cleaning. + """ + self.set_node_provision_state(node['uuid'], 'manage') + self.wait_provisioning_state( + node['uuid'], + [bm.BaremetalProvisionStates.MANAGEABLE], + timeout=CONF.baremetal.unprovision_timeout, + interval=30) + self.set_node_provision_state( + node['uuid'], 'clean', clean_steps=clean_steps) + self.wait_provisioning_state( + node['uuid'], + [bm.BaremetalProvisionStates.MANAGEABLE], + timeout=CONF.baremetal.unprovision_timeout, + interval=30) + self.set_node_provision_state(node['uuid'], 'provide') + self.wait_provisioning_state( + node['uuid'], + [bm.BaremetalProvisionStates.NOSTATE, + bm.BaremetalProvisionStates.AVAILABLE], + timeout=CONF.baremetal.unprovision_timeout, + interval=30) + + def check_manual_partition_cleaning(self, node): + """Tests the cleanup step for erasing devices metadata. + + :param node: Ironic node to associate instance_uuid with, it is + expected to be in 'active' state + """ + self.set_node_provision_state(node['uuid'], 'deleted') + self.wait_provisioning_state( + node['uuid'], + [bm.BaremetalProvisionStates.NOSTATE, + bm.BaremetalProvisionStates.AVAILABLE], + timeout=CONF.baremetal.unprovision_timeout, + interval=30) + clean_steps = [ + { + "interface": "deploy", + "step": "erase_devices_metadata" + } + ] + self.manual_cleaning(node, clean_steps=clean_steps) + # TODO(yolanda): we currently are not checking it the cleanup + # was actually removing the metadata, because there was not a good + # way to achieve that check for vms and baremetal + class BaremetalStandaloneScenarioTest(BaremetalStandaloneManager): @@ -335,6 +395,9 @@ class BaremetalStandaloneScenarioTest(BaremetalStandaloneManager): # Image checksum, required when image is stored on HTTP server. image_checksum = None + # If we need to set provision state 'deleted' for the node after test + delete_node = True + mandatory_attr = ['driver', 'image_ref', 'wholedisk_image'] node = None @@ -405,7 +468,10 @@ class BaremetalStandaloneScenarioTest(BaremetalStandaloneManager): # Remove ports before deleting node, to catch regression for cases # when user did this prior unprovision node. for vif in vifs: - cls.ports_client.delete_port(vif) + try: + cls.ports_client.delete_port(vif) + except lib_exc.NotFound: + pass cls.terminate_node(cls.node['uuid']) base.reset_baremetal_api_microversion() super(BaremetalStandaloneManager, cls).resource_cleanup() diff --git a/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_cleaning.py b/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_cleaning.py new file mode 100644 index 0000000..5ea83b1 --- /dev/null +++ b/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_cleaning.py @@ -0,0 +1,71 @@ +# +# Copyright 2017 Mirantis Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_log import log as logging +from tempest.common import utils +from tempest import config +from tempest.lib import decorators + +from ironic_tempest_plugin.services.baremetal import base +from ironic_tempest_plugin.tests.scenario import \ + baremetal_standalone_manager as bsm + +LOG = logging.getLogger(__name__) +CONF = config.CONF + + +class BaremetalCleaningAgentIpmitoolWholedisk( + bsm.BaremetalStandaloneScenarioTest): + + driver = 'agent_ipmitool' + image_ref = CONF.baremetal.whole_disk_image_ref + wholedisk_image = True + delete_node = False + + @decorators.idempotent_id('0d82cedd-9697-4cf7-8e4a-80d510f53615') + @utils.services('image', 'network') + def test_manual_cleaning(self): + base.set_baremetal_api_microversion('1.28') + self.check_manual_partition_cleaning(self.node) + + +class BaremetalCleaningPxeIpmitoolWholedisk( + bsm.BaremetalStandaloneScenarioTest): + + driver = 'pxe_ipmitool' + image_ref = CONF.baremetal.whole_disk_image_ref + wholedisk_image = True + delete_node = False + + @decorators.idempotent_id('fb03abfa-cdfc-41ec-aaa8-c70402786a85') + @utils.services('image', 'network') + def test_manual_cleaning(self): + base.set_baremetal_api_microversion('1.28') + self.check_manual_partition_cleaning(self.node) + + +class BaremetalCleaningIpmiWholedisk( + bsm.BaremetalStandaloneScenarioTest): + + driver = 'ipmi' + image_ref = CONF.baremetal.whole_disk_image_ref + wholedisk_image = True + delete_node = False + + @decorators.idempotent_id('065238db-1b6d-4d75-a9da-c240f8cbd956') + @utils.services('image', 'network') + def test_manual_cleaning(self): + base.set_baremetal_api_microversion('1.28') + self.check_manual_partition_cleaning(self.node)