|
| 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 | + source_usages = self._get_provider_usages(source_rp_uuid) |
| 82 | + self.assertFlavorMatchesAllocation(self.flavor1, source_usages) |
0 commit comments