Skip to content

Commit ed24dfa

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add functional recreate test for regression bug 1825537" into stable/stein
2 parents 3bc6ff0 + eaa1fc6 commit ed24dfa

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
13+
from nova.tests.functional import integrated_helpers
14+
15+
16+
class FinishResizeErrorAllocationCleanupTestCase(
17+
integrated_helpers.ProviderUsageBaseTestCase):
18+
"""Test for bug 1825537 introduced in Rocky and backported down to Pike.
19+
20+
Tests a scenario where finish_resize fails on the dest compute during a
21+
resize and ensures resource provider allocations are properly cleaned up
22+
in placement.
23+
"""
24+
25+
compute_driver = 'fake.FakeFinishMigrationFailDriver'
26+
27+
def setUp(self):
28+
super(FinishResizeErrorAllocationCleanupTestCase, self).setUp()
29+
# Get the flavors we're going to use.
30+
flavors = self.api.get_flavors()
31+
self.flavor1 = flavors[0]
32+
self.flavor2 = flavors[1]
33+
34+
def _resize_and_assert_error(self, server, dest_host):
35+
# Now resize the server and wait for it to go to ERROR status because
36+
# the finish_migration virt driver method in host2 should fail.
37+
req = {'resize': {'flavorRef': self.flavor2['id']}}
38+
self.api.post_server_action(server['id'], req)
39+
# The instance is set to ERROR status before the fault is recorded so
40+
# to avoid a race we need to wait for the task_state to change
41+
# to None which happens after the fault is recorded.
42+
server = self._wait_for_server_parameter(
43+
self.admin_api, server,
44+
{'status': 'ERROR', 'OS-EXT-STS:task_state': None})
45+
# The server should be pointing at $dest_host because resize_instance
46+
# will have updated the host/node value on the instance before casting
47+
# to the finish_resize method on the dest compute.
48+
self.assertEqual(dest_host, server['OS-EXT-SRV-ATTR:host'])
49+
# In this case the FakeFinishMigrationFailDriver.finish_migration
50+
# method raises VirtualInterfaceCreateException.
51+
self.assertIn('Virtual Interface creation failed',
52+
server['fault']['message'])
53+
54+
def test_finish_resize_fails_allocation_cleanup(self):
55+
# Start two computes so we can resize across hosts.
56+
self._start_compute('host1')
57+
self._start_compute('host2')
58+
59+
# Create a server on host1.
60+
server = self._boot_and_check_allocations(self.flavor1, 'host1')
61+
62+
# Resize to host2 which should fail.
63+
self._resize_and_assert_error(server, 'host2')
64+
65+
# Check the resource provider allocations. Since the server is pointed
66+
# at the dest host in the DB now, the dest node resource provider
67+
# allocations should still exist with the new flavor.
68+
source_rp_uuid = self._get_provider_uuid_by_host('host1')
69+
dest_rp_uuid = self._get_provider_uuid_by_host('host2')
70+
# FIXME(mriedem): This is bug 1825537 where the allocations are
71+
# reverted when finish_resize fails so the dest node resource provider
72+
# does not have any allocations and the instance allocations are for
73+
# the old flavor on the source node resource provider even though the
74+
# instance is not running on the source host nor pointed at the source
75+
# host in the DB.
76+
# self.assertFlavorMatchesAllocation(
77+
# self.flavor2, server['id'], dest_rp_uuid)
78+
dest_rp_usages = self._get_provider_usages(dest_rp_uuid)
79+
no_usage = {'VCPU': 0, 'MEMORY_MB': 0, 'DISK_GB': 0}
80+
self.assertEqual(no_usage, dest_rp_usages)
81+
self.assertFlavorMatchesAllocation(
82+
self.flavor1, server['id'], source_rp_uuid)

nova/tests/functional/test_servers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3723,6 +3723,7 @@ def fake_resize_method(*args, **kwargs):
37233723

37243724
# Ensure the allocation records still exist on the host.
37253725
source_rp_uuid = self._get_provider_uuid_by_host(hostname)
3726+
# FIXME(mriedem): This is wrong for the _finish_resize case.
37263727
# The new_flavor should have been subtracted from the doubled
37273728
# allocation which just leaves us with the original flavor.
37283729
self.assertFlavorMatchesUsage(source_rp_uuid, self.flavor1)

nova/virt/fake.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,13 @@ def update_provider_tree(self, provider_tree, nodename, allocations=None):
731731
self.child_resources)
732732

733733

734+
class FakeFinishMigrationFailDriver(FakeDriver):
735+
"""FakeDriver variant that will raise an exception from finish_migration"""
736+
737+
def finish_migration(self, *args, **kwargs):
738+
raise exception.VirtualInterfaceCreateException()
739+
740+
734741
class FakeRescheduleDriver(FakeDriver):
735742
"""FakeDriver derivative that triggers a reschedule on the first spawn
736743
attempt. This is expected to only be used in tests that have more than

0 commit comments

Comments
 (0)