[placement] Unregister the ResourceClass object
Unregister the ResourceClass object because we do not need RPC and versioning for the objects in nova.objects.resource_provider. There are three primary changes here: * unregistering the ResourceClass class * where objects.ResourceClass is used, point directly to the nova.objects.resource_provider package instead * move the CUSTOM_NAMESPACE for resource class names to the the fields object. This avoids an import loop and also makes more sense as the field represents the name. Partially-Implements: bp placement-deregister-objects Change-Id: If537c786ea1a61383d82bad9a1de86c25c6cdbd2
This commit is contained in:
parent
5cabc535af
commit
99f0387b94
|
@ -22,7 +22,6 @@ from nova.api.openstack.placement import util
|
|||
from nova.api.openstack.placement import wsgi_wrapper
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import objects
|
||||
from nova.objects import resource_provider as rp_obj
|
||||
|
||||
|
||||
|
@ -78,7 +77,7 @@ def create_resource_class(req):
|
|||
data = util.extract_json(req.body, POST_RC_SCHEMA_V1_2)
|
||||
|
||||
try:
|
||||
rc = objects.ResourceClass(context, name=data['name'])
|
||||
rc = rp_obj.ResourceClass(context, name=data['name'])
|
||||
rc.create()
|
||||
except exception.ResourceClassExists:
|
||||
raise webob.exc.HTTPConflict(
|
||||
|
@ -107,7 +106,7 @@ def delete_resource_class(req):
|
|||
name = util.wsgi_path_item(req.environ, 'name')
|
||||
context = req.environ['placement.context']
|
||||
# The containing application will catch a not found here.
|
||||
rc = objects.ResourceClass.get_by_name(context, name)
|
||||
rc = rp_obj.ResourceClass.get_by_name(context, name)
|
||||
try:
|
||||
rc.destroy()
|
||||
except exception.ResourceClassCannotDeleteStandard as exc:
|
||||
|
@ -135,7 +134,7 @@ def get_resource_class(req):
|
|||
name = util.wsgi_path_item(req.environ, 'name')
|
||||
context = req.environ['placement.context']
|
||||
# The containing application will catch a not found here.
|
||||
rc = objects.ResourceClass.get_by_name(context, name)
|
||||
rc = rp_obj.ResourceClass.get_by_name(context, name)
|
||||
|
||||
req.response.body = encodeutils.to_utf8(jsonutils.dumps(
|
||||
_serialize_resource_class(req.environ, rc))
|
||||
|
@ -179,7 +178,7 @@ def update_resource_class(req):
|
|||
data = util.extract_json(req.body, PUT_RC_SCHEMA_V1_2)
|
||||
|
||||
# The containing application will catch a not found here.
|
||||
rc = objects.ResourceClass.get_by_name(context, name)
|
||||
rc = rp_obj.ResourceClass.get_by_name(context, name)
|
||||
|
||||
rc.name = data['name']
|
||||
|
||||
|
@ -219,10 +218,10 @@ def update_resource_class(req):
|
|||
|
||||
status = 204
|
||||
try:
|
||||
rc = objects.ResourceClass.get_by_name(context, name)
|
||||
rc = rp_obj.ResourceClass.get_by_name(context, name)
|
||||
except exception.NotFound:
|
||||
try:
|
||||
rc = objects.ResourceClass(context, name=name)
|
||||
rc = rp_obj.ResourceClass(context, name=name)
|
||||
rc.create()
|
||||
status = 201
|
||||
# We will not see ResourceClassCannotUpdateStandard because
|
||||
|
|
|
@ -22,7 +22,6 @@ import six
|
|||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova.network import model as network_model
|
||||
from nova import objects
|
||||
|
||||
|
||||
# Import field errors from oslo.versionedobjects
|
||||
|
@ -463,6 +462,9 @@ class OSType(BaseNovaEnum):
|
|||
class ResourceClass(StringField):
|
||||
"""Classes of resources provided to consumers."""
|
||||
|
||||
CUSTOM_NAMESPACE = 'CUSTOM_'
|
||||
"""All non-standard resource classes must begin with this string."""
|
||||
|
||||
VCPU = 'VCPU'
|
||||
MEMORY_MB = 'MEMORY_MB'
|
||||
DISK_GB = 'DISK_GB'
|
||||
|
@ -486,12 +488,12 @@ class ResourceClass(StringField):
|
|||
V1_0 = (VCPU, MEMORY_MB, DISK_GB, PCI_DEVICE, SRIOV_NET_VF, NUMA_SOCKET,
|
||||
NUMA_CORE, NUMA_THREAD, NUMA_MEMORY_MB, IPV4_ADDRESS)
|
||||
|
||||
@staticmethod
|
||||
def normalize_name(rc_name):
|
||||
@classmethod
|
||||
def normalize_name(cls, rc_name):
|
||||
if rc_name is None:
|
||||
return None
|
||||
norm_name = rc_name.upper()
|
||||
cust_prefix = objects.ResourceClass.CUSTOM_NAMESPACE
|
||||
cust_prefix = cls.CUSTOM_NAMESPACE
|
||||
norm_name = cust_prefix + norm_name
|
||||
# Replace some punctuation characters with underscores
|
||||
norm_name = re.sub('[^0-9A-Z]+', '_', norm_name)
|
||||
|
|
|
@ -1983,13 +1983,8 @@ class UsageList(base.ObjectListBase, base.NovaObject):
|
|||
return "UsageList[" + ", ".join(strings) + "]"
|
||||
|
||||
|
||||
@base.NovaObjectRegistry.register
|
||||
@base.NovaObjectRegistry.register_if(False)
|
||||
class ResourceClass(base.NovaObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
CUSTOM_NAMESPACE = 'CUSTOM_'
|
||||
"""All non-standard resource classes must begin with this string."""
|
||||
|
||||
MIN_CUSTOM_RESOURCE_CLASS_ID = 10000
|
||||
"""Any user-defined resource classes must have an identifier greater than
|
||||
|
@ -2053,10 +2048,11 @@ class ResourceClass(base.NovaObject):
|
|||
if self.name in fields.ResourceClass.STANDARD:
|
||||
raise exception.ResourceClassExists(resource_class=self.name)
|
||||
|
||||
if not self.name.startswith(self.CUSTOM_NAMESPACE):
|
||||
if not self.name.startswith(fields.ResourceClass.CUSTOM_NAMESPACE):
|
||||
raise exception.ObjectActionError(
|
||||
action='create',
|
||||
reason='name must start with ' + self.CUSTOM_NAMESPACE)
|
||||
reason='name must start with ' +
|
||||
fields.ResourceClass.CUSTOM_NAMESPACE)
|
||||
|
||||
updates = self.obj_get_changes()
|
||||
# There is the possibility of a race when adding resource classes, as
|
||||
|
@ -2171,7 +2167,7 @@ class ResourceClassList(base.ObjectListBase, base.NovaObject):
|
|||
def get_all(cls, context):
|
||||
resource_classes = cls._get_all(context)
|
||||
return base.obj_make_list(context, cls(context),
|
||||
objects.ResourceClass, resource_classes)
|
||||
ResourceClass, resource_classes)
|
||||
|
||||
def __repr__(self):
|
||||
strings = [repr(x) for x in self.objects]
|
||||
|
|
|
@ -31,7 +31,6 @@ from nova import objects
|
|||
from nova.objects import base as obj_base
|
||||
from nova.objects import fields
|
||||
from nova.objects import instance as obj_instance
|
||||
from nova.objects.resource_provider import ResourceClass
|
||||
from nova import rpc
|
||||
|
||||
|
||||
|
@ -104,7 +103,7 @@ def _process_extra_specs(extra_specs, resources):
|
|||
if key.startswith("resources:")}
|
||||
resource_keys = set(resource_specs)
|
||||
custom_keys = set([key for key in resource_keys
|
||||
if key.startswith(ResourceClass.CUSTOM_NAMESPACE)])
|
||||
if key.startswith(fields.ResourceClass.CUSTOM_NAMESPACE)])
|
||||
std_keys = resource_keys - custom_keys
|
||||
|
||||
def validate_int(key):
|
||||
|
|
|
@ -1459,7 +1459,7 @@ class ResourceClassListTestCase(ResourceProviderBaseCase):
|
|||
class ResourceClassTestCase(ResourceProviderBaseCase):
|
||||
|
||||
def test_get_by_name(self):
|
||||
rc = objects.ResourceClass.get_by_name(
|
||||
rc = rp_obj.ResourceClass.get_by_name(
|
||||
self.ctx,
|
||||
fields.ResourceClass.VCPU
|
||||
)
|
||||
|
@ -1471,17 +1471,17 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
|
||||
def test_get_by_name_not_found(self):
|
||||
self.assertRaises(exception.ResourceClassNotFound,
|
||||
objects.ResourceClass.get_by_name,
|
||||
rp_obj.ResourceClass.get_by_name,
|
||||
self.ctx,
|
||||
'CUSTOM_NO_EXISTS')
|
||||
|
||||
def test_get_by_name_custom(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
rc.create()
|
||||
get_rc = objects.ResourceClass.get_by_name(
|
||||
get_rc = rp_obj.ResourceClass.get_by_name(
|
||||
self.ctx,
|
||||
'CUSTOM_IRON_NFV',
|
||||
)
|
||||
|
@ -1489,7 +1489,7 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
self.assertEqual(rc.name, get_rc.name)
|
||||
|
||||
def test_create_fail_not_using_namespace(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
context=self.ctx,
|
||||
name='IRON_NFV',
|
||||
)
|
||||
|
@ -1497,39 +1497,40 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
self.assertIn('name must start with', str(exc))
|
||||
|
||||
def test_create_duplicate_standard(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
context=self.ctx,
|
||||
name=fields.ResourceClass.VCPU,
|
||||
)
|
||||
self.assertRaises(exception.ResourceClassExists, rc.create)
|
||||
|
||||
def test_create(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
rc.create()
|
||||
min_id = objects.ResourceClass.MIN_CUSTOM_RESOURCE_CLASS_ID
|
||||
min_id = rp_obj.ResourceClass.MIN_CUSTOM_RESOURCE_CLASS_ID
|
||||
self.assertEqual(min_id, rc.id)
|
||||
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_ENTERPRISE',
|
||||
)
|
||||
rc.create()
|
||||
self.assertEqual(min_id + 1, rc.id)
|
||||
|
||||
@mock.patch.object(nova.objects.ResourceClass, "_get_next_id")
|
||||
@mock.patch.object(nova.objects.resource_provider.ResourceClass,
|
||||
"_get_next_id")
|
||||
def test_create_duplicate_id_retry(self, mock_get):
|
||||
# This order of ID generation will create rc1 with an ID of 42, try to
|
||||
# create rc2 with the same ID, and then return 43 in the retry loop.
|
||||
mock_get.side_effect = (42, 42, 43)
|
||||
rc1 = objects.ResourceClass(
|
||||
rc1 = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
rc1.create()
|
||||
rc2 = objects.ResourceClass(
|
||||
rc2 = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_TWO',
|
||||
)
|
||||
|
@ -1537,18 +1538,19 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
self.assertEqual(rc1.id, 42)
|
||||
self.assertEqual(rc2.id, 43)
|
||||
|
||||
@mock.patch.object(nova.objects.ResourceClass, "_get_next_id")
|
||||
@mock.patch.object(nova.objects.resource_provider.ResourceClass,
|
||||
"_get_next_id")
|
||||
def test_create_duplicate_id_retry_failing(self, mock_get):
|
||||
"""negative case for test_create_duplicate_id_retry"""
|
||||
# This order of ID generation will create rc1 with an ID of 44, try to
|
||||
# create rc2 with the same ID, and then return 45 in the retry loop.
|
||||
mock_get.side_effect = (44, 44, 44, 44)
|
||||
rc1 = objects.ResourceClass(
|
||||
rc1 = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
rc1.create()
|
||||
rc2 = objects.ResourceClass(
|
||||
rc2 = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_TWO',
|
||||
)
|
||||
|
@ -1556,28 +1558,28 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
self.assertRaises(exception.MaxDBRetriesExceeded, rc2.create)
|
||||
|
||||
def test_create_duplicate_custom(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
rc.create()
|
||||
self.assertEqual(objects.ResourceClass.MIN_CUSTOM_RESOURCE_CLASS_ID,
|
||||
self.assertEqual(rp_obj.ResourceClass.MIN_CUSTOM_RESOURCE_CLASS_ID,
|
||||
rc.id)
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
self.assertRaises(exception.ResourceClassExists, rc.create)
|
||||
|
||||
def test_destroy_fail_no_id(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
self.assertRaises(exception.ObjectActionError, rc.destroy)
|
||||
|
||||
def test_destroy_fail_standard(self):
|
||||
rc = objects.ResourceClass.get_by_name(
|
||||
rc = rp_obj.ResourceClass.get_by_name(
|
||||
self.ctx,
|
||||
'VCPU',
|
||||
)
|
||||
|
@ -1585,7 +1587,7 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
rc.destroy)
|
||||
|
||||
def test_destroy(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
|
@ -1594,7 +1596,7 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
rc_ids = (r.id for r in rc_list)
|
||||
self.assertIn(rc.id, rc_ids)
|
||||
|
||||
rc = objects.ResourceClass.get_by_name(
|
||||
rc = rp_obj.ResourceClass.get_by_name(
|
||||
self.ctx,
|
||||
'CUSTOM_IRON_NFV',
|
||||
)
|
||||
|
@ -1606,7 +1608,7 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
|
||||
# Verify rc cache was purged of the old entry
|
||||
self.assertRaises(exception.ResourceClassNotFound,
|
||||
objects.ResourceClass.get_by_name,
|
||||
rp_obj.ResourceClass.get_by_name,
|
||||
self.ctx,
|
||||
'CUSTOM_IRON_NFV')
|
||||
|
||||
|
@ -1614,7 +1616,7 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
"""Test that we raise an exception when attempting to delete a resource
|
||||
class that is referenced in an inventory record.
|
||||
"""
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
|
@ -1644,14 +1646,14 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
self.assertNotIn(rc.id, rc_ids)
|
||||
|
||||
def test_save_fail_no_id(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
self.assertRaises(exception.ObjectActionError, rc.save)
|
||||
|
||||
def test_save_fail_standard(self):
|
||||
rc = objects.ResourceClass.get_by_name(
|
||||
rc = rp_obj.ResourceClass.get_by_name(
|
||||
self.ctx,
|
||||
'VCPU',
|
||||
)
|
||||
|
@ -1659,13 +1661,13 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
rc.save)
|
||||
|
||||
def test_save(self):
|
||||
rc = objects.ResourceClass(
|
||||
rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_IRON_NFV',
|
||||
)
|
||||
rc.create()
|
||||
|
||||
rc = objects.ResourceClass.get_by_name(
|
||||
rc = rp_obj.ResourceClass.get_by_name(
|
||||
self.ctx,
|
||||
'CUSTOM_IRON_NFV',
|
||||
)
|
||||
|
@ -1674,7 +1676,7 @@ class ResourceClassTestCase(ResourceProviderBaseCase):
|
|||
|
||||
# Verify rc cache was purged of the old entry
|
||||
self.assertRaises(exception.NotFound,
|
||||
objects.ResourceClass.get_by_name,
|
||||
rp_obj.ResourceClass.get_by_name,
|
||||
self.ctx,
|
||||
'CUSTOM_IRON_NFV')
|
||||
|
||||
|
@ -2855,7 +2857,7 @@ class AllocationCandidatesTestCase(ResourceProviderBaseCase):
|
|||
cn.set_inventory(inv_list)
|
||||
|
||||
# Create a custom resource called MAGIC
|
||||
magic_rc = objects.ResourceClass(
|
||||
magic_rc = rp_obj.ResourceClass(
|
||||
self.ctx,
|
||||
name='CUSTOM_MAGIC',
|
||||
)
|
||||
|
|
|
@ -20,6 +20,7 @@ import webob
|
|||
from nova.api.openstack.placement import microversion
|
||||
from nova.api.openstack.placement import util
|
||||
from nova import objects
|
||||
from nova.objects import resource_provider as rp_obj
|
||||
from nova import test
|
||||
from nova.tests import uuidsentinel
|
||||
|
||||
|
@ -264,7 +265,7 @@ class TestPlacementURLs(test.NoDBTestCase):
|
|||
self.resource_provider = objects.ResourceProvider(
|
||||
name=uuidsentinel.rp_name,
|
||||
uuid=uuidsentinel.rp_uuid)
|
||||
self.resource_class = objects.ResourceClass(
|
||||
self.resource_class = rp_obj.ResourceClass(
|
||||
name='CUSTOM_BAREMETAL_GOLD',
|
||||
id=1000)
|
||||
|
||||
|
|
|
@ -1150,7 +1150,6 @@ object_data = {
|
|||
'Quotas': '1.3-40fcefe522111dddd3e5e6155702cf4e',
|
||||
'QuotasNoOp': '1.3-347a039fc7cfee7b225b68b5181e0733',
|
||||
'RequestSpec': '1.8-35033ecef47a880f9a5e46e2269e2b97',
|
||||
'ResourceClass': '1.0-e6b367e2cf1733c5f3526f20a3286fe9',
|
||||
'ResourceProvider': '1.4-35e8a41d2ece17a862fac5b07ca966af',
|
||||
'ResourceProviderList': '1.1-15ecf022a68ddbb8c2a6739cfc9f8f5e',
|
||||
'S3ImageMapping': '1.0-7dd7366a890d82660ed121de9092276e',
|
||||
|
|
|
@ -574,12 +574,13 @@ class TestResourceClass(test.NoDBTestCase):
|
|||
self.context = context.RequestContext(self.user_id, self.project_id)
|
||||
|
||||
def test_cannot_create_with_id(self):
|
||||
rc = objects.ResourceClass(self.context, id=1, name='CUSTOM_IRON_NFV')
|
||||
rc = resource_provider.ResourceClass(self.context, id=1,
|
||||
name='CUSTOM_IRON_NFV')
|
||||
exc = self.assertRaises(exception.ObjectActionError, rc.create)
|
||||
self.assertIn('already created', str(exc))
|
||||
|
||||
def test_cannot_create_requires_name(self):
|
||||
rc = objects.ResourceClass(self.context)
|
||||
rc = resource_provider.ResourceClass(self.context)
|
||||
exc = self.assertRaises(exception.ObjectActionError, rc.create)
|
||||
self.assertIn('name is required', str(exc))
|
||||
|
||||
|
|
Loading…
Reference in New Issue