diff --git a/nova/exception.py b/nova/exception.py index 0be8f0f959..8c187eee65 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -2251,10 +2251,7 @@ class InvalidInventory(Invalid): # An exception with this name is used on both sides of the placement/ # nova interaction. class InventoryInUse(InvalidInventory): - # NOTE(mriedem): This message cannot change without impacting the - # nova.scheduler.client.report._RE_INV_IN_USE regex. - msg_fmt = _("Inventory for '%(resource_classes)s' on " - "resource provider '%(resource_provider)s' in use.") + pass class UnsupportedPointerModelRequested(Invalid): diff --git a/nova/scheduler/client/report.py b/nova/scheduler/client/report.py index 07532dd35d..9c013eddc1 100644 --- a/nova/scheduler/client/report.py +++ b/nova/scheduler/client/report.py @@ -18,7 +18,6 @@ import contextlib import copy import functools import random -import re import time from keystoneauth1 import exceptions as ks_exc @@ -41,8 +40,6 @@ from nova import utils CONF = nova.conf.CONF LOG = logging.getLogger(__name__) -_RE_INV_IN_USE = re.compile("Inventory for (.+) on resource provider " - "(.+) in use") WARN_EVERY = 10 RESHAPER_VERSION = '1.30' CONSUMER_GENERATION_VERSION = '1.28' @@ -173,19 +170,6 @@ def _move_operation_alloc_request(source_allocs, dest_alloc_req): return new_alloc_req -def _extract_inventory_in_use(body): - """Given an HTTP response body, extract the resource classes that were - still in use when we tried to delete inventory. - - :returns: String of resource classes or None if there was no InventoryInUse - error in the response body. - """ - match = _RE_INV_IN_USE.search(body) - if match: - return match.group(1) - return None - - def get_placement_request_id(response): if response is not None: return response.headers.get(request_id.HTTP_RESP_HEADER_REQUEST_ID) @@ -946,12 +930,12 @@ class SchedulerReportClient(object): if resp.status_code == 409: # If a conflict attempting to remove inventory in a resource class # with active allocations, raise InventoryInUse - rc = _extract_inventory_in_use(resp.text) - if rc is not None: - raise exception.InventoryInUse( - resource_classes=rc, - resource_provider=rp_uuid, - ) + err = resp.json()['errors'][0] + # TODO(efried): If there's ever a lib exporting symbols for error + # codes, use it. + if err['code'] == 'placement.inventory.inuse': + # The error detail includes the resource class and provider. + raise exception.InventoryInUse(err['detail']) # Other conflicts are generation mismatch: raise conflict exception raise exception.ResourceProviderUpdateConflict( uuid=rp_uuid, generation=generation, error=resp.text) diff --git a/nova/tests/functional/test_report_client.py b/nova/tests/functional/test_report_client.py index a965aacac9..b6bf1747cb 100644 --- a/nova/tests/functional/test_report_client.py +++ b/nova/tests/functional/test_report_client.py @@ -702,10 +702,11 @@ class SchedulerReportClientTests(SchedulerReportClientTestBase): } # Allocation bumped the generation, so refresh to get the latest self.client._refresh_and_get_inventory(self.context, uuids.cn) - self.assertRaises( - exception.InventoryInUse, - self.client.set_inventory_for_provider, - self.context, uuids.cn, bad_inv) + msgre = (".*update conflict: Inventory for 'SRIOV_NET_VF' on " + "resource provider '%s' in use..*" % uuids.cn) + with self.assertRaisesRegex(exception.InventoryInUse, msgre): + self.client.set_inventory_for_provider(self.context, uuids.cn, + bad_inv) self.assertEqual( inv, self.client._get_inventory( @@ -713,10 +714,9 @@ class SchedulerReportClientTests(SchedulerReportClientTestBase): # Same result if we try to clear all the inventory bad_inv = {} - self.assertRaises( - exception.InventoryInUse, - self.client.set_inventory_for_provider, - self.context, uuids.cn, bad_inv) + with self.assertRaisesRegex(exception.InventoryInUse, msgre): + self.client.set_inventory_for_provider(self.context, uuids.cn, + bad_inv) self.assertEqual( inv, self.client._get_inventory(