summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmit Uniyal <auniyal@redhat.com>2022-07-06 18:20:02 +0000
committerAmit Uniyal <auniyal@redhat.com>2022-11-29 11:37:29 +0000
commit92e8ac529cf8f1cc85176fbdf18198e62f8948a8 (patch)
tree45d62749cc5e2f8cc8102067c0e8d3bf2b05bb1b
parentd3b46af01b7afa1a9051cb440a7986bfcb1a59b1 (diff)
downloadnova-92e8ac529cf8f1cc85176fbdf18198e62f8948a8.tar.gz
add regression test case for bug 1978983
This change add a repoducer test for evacuating a vm in the powering-off state Conflicts: nova/tests/functional/integrated_helpers.py nova/tests/functional/test_servers.py Difference: nova/tests/functional/regressions/test_bug_1978983.py NOTE(auniyal): Conflicts are due to the following changes that are not in Ussuri: * I147bf4d95e6d86ff1f967a8ce37260730f21d236 (Cyborg evacuate support) * Ia3d7351c1805d98bcb799ab0375673c7f1cb8848 (Functional tests for NUMA live migration) NOTE(auniyal): Differences * Replaced GlanceFixture with fake.stub_out_image_service in regression test, as GlanceFixture does not exist in Ussuri NOTE(auniyal): Differences from ussuri to train * regression: as create_server is not present in train used _build_minimal_create_server instead to create server Related-Bug: #1978983 Change-Id: I5540df6c7497956219c06cff6f15b51c2c8bc299 (cherry picked from commit 5904c7f993ac737d68456fc05adf0aaa7a6f3018) (cherry picked from commit 6bd0bf00fca6ac6460d70c855eded3898cfe2401) (cherry picked from commit 1e0af92e17f878ce64bd16e428cb3c10904b0877) (cherry picked from commit b57b0eef218fd7604658842c9277aad782d11b45) (cherry picked from commit b6c877377f58ccaa797af3384b199002726745ea) (cherry picked from commit 9015c3b663a7b46192c106ef065f93e82f0ab8be)
-rw-r--r--nova/tests/functional/integrated_helpers.py43
-rw-r--r--nova/tests/functional/regressions/test_bug_1978983.py87
2 files changed, 130 insertions, 0 deletions
diff --git a/nova/tests/functional/integrated_helpers.py b/nova/tests/functional/integrated_helpers.py
index 2afafd0a22..183c983306 100644
--- a/nova/tests/functional/integrated_helpers.py
+++ b/nova/tests/functional/integrated_helpers.py
@@ -73,6 +73,12 @@ def generate_new_element(items, prefix, numeric=False):
LOG.debug("Random collision on %s", candidate)
+# placeholder used as a default parameter value to distinguish between the case
+# when the parameter is specified by the caller with None from the case when it
+# was not specified
+NOT_SPECIFIED = object()
+
+
class _IntegratedTestBase(test.TestCase):
REQUIRES_LOCKING = True
ADMIN_API = False
@@ -384,6 +390,43 @@ class InstanceHelperMixin(object):
self._wait_for_state_change(self.api, server, 'ACTIVE')
self._wait_for_migration_status(server, [migration_final_status])
+ def _evacuate_server(
+ self, server, extra_post_args=None, expected_host=None,
+ expected_state='ACTIVE', expected_task_state=NOT_SPECIFIED,
+ expected_migration_status='done'):
+ """Evacuate a server."""
+ api = getattr(self, 'admin_api', self.api)
+
+ post = {'evacuate': {}}
+ if extra_post_args:
+ post['evacuate'].update(extra_post_args)
+
+ expected_result = {'status': expected_state}
+ if expected_host:
+ expected_result['OS-EXT-SRV-ATTR:host'] = expected_host
+ if expected_task_state is not NOT_SPECIFIED:
+ expected_result['OS-EXT-STS:task_state'] = expected_task_state
+
+ api.post_server_action(server['id'], post)
+
+ # NOTE(gibi): The order of waiting for the migration and returning
+ # a fresh server from _wait_for_server_parameter is important as
+ # the compute manager sets status of the instance before sets the
+ # host and finally sets the migration status. So waiting for the
+ # migration first makes the returned server object more consistent.
+ self._wait_for_migration_status(server, [expected_migration_status])
+ return self._wait_for_server_parameter(api, server, expected_result)
+
+ def _start_server(self, server):
+ self.api.post_server_action(server['id'], {'os-start': None})
+ return self._wait_for_state_change(self.api, server, 'ACTIVE')
+
+ def _stop_server(self, server, wait_for_stop=True):
+ self.api.post_server_action(server['id'], {'os-stop': None})
+ if wait_for_stop:
+ return self._wait_for_state_change(self.api, server, 'SHUTOFF')
+ return server
+
class ProviderUsageBaseTestCase(test.TestCase, InstanceHelperMixin):
"""Base test class for functional tests that check provider usage
diff --git a/nova/tests/functional/regressions/test_bug_1978983.py b/nova/tests/functional/regressions/test_bug_1978983.py
new file mode 100644
index 0000000000..c07b047b39
--- /dev/null
+++ b/nova/tests/functional/regressions/test_bug_1978983.py
@@ -0,0 +1,87 @@
+# Copyright 2022 Red Hat, Inc.
+# All Rights Reserved.
+#
+# 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 nova import test
+from nova.tests import fixtures as nova_fixtures
+from nova.tests.functional.api import client
+from nova.tests.functional import fixtures as func_fixtures
+from nova.tests.functional import integrated_helpers
+from nova.tests.unit.image import fake
+
+
+class EvacuateServerWithTaskState(
+ test.TestCase, integrated_helpers.InstanceHelperMixin,
+):
+ """Regression test for bug 1978983
+ If instance task state is powering-off or not None
+ instance should be allowed to evacuate.
+ """
+
+ def setUp(self):
+ super(EvacuateServerWithTaskState, self).setUp()
+ # Stub out external dependencies.
+ self.useFixture(nova_fixtures.NeutronFixture(self))
+ fake.stub_out_image_service(self)
+ self.useFixture(func_fixtures.PlacementFixture())
+ self.useFixture(nova_fixtures.HostNameWeigherFixture())
+
+ # Start nova controller services.
+ self.start_service('conductor')
+ self.start_service('scheduler')
+
+ api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
+ api_version='v2.1'))
+ self.admin_api = api_fixture.admin_api
+ self.api = api_fixture.api
+
+ self.image_id = self.api.get_images()[0]['id']
+
+ self.admin_api.microversion = 'latest'
+ self.api.microversion = 'latest'
+
+ self.src = self._start_compute(host='host1')
+ self.dest = self._start_compute(host='host2')
+
+ def test_evacuate_instance(self):
+ """Evacuating a server
+ """
+ server = self.admin_api.post_server(
+ dict(server=self._build_minimal_create_server_request(
+ self.api, 'test_evacuate_instance', self.image_id,
+ networks='none')))
+
+ server = self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
+ self.assertEqual('host1', server['OS-EXT-SRV-ATTR:host'])
+
+ # stop host1 compute service
+ self.src.stop()
+
+ # poweroff instance
+ self._stop_server(server, wait_for_stop=False)
+ server = self._wait_for_server_parameter(self.admin_api,
+ server, {'OS-EXT-STS:task_state': 'powering-off'})
+
+ # FIXME(auniyal): As compute service is down in source node
+ # instance is stuck at powering-off, evacuation fails with
+ # msg: Cannot 'evacuate' instance <instance-id> while it is in
+ # task_state powering-off (HTTP 409)
+
+ ex = self.assertRaises(
+ client.OpenStackApiException,
+ self._evacuate_server,
+ server,
+ expected_host=self.dest.host)
+ self.assertEqual(409, ex.response.status_code)