objects: Add RequestSpec.network_metadata

We need a way to pass information about networks from the conductor to
the scheduler. These are not really part of the network requests but
rather metadata about these networks, meaning the 'NetworkRequest'
object doesn't really make sense. Instead, we use the recently added
'NetworkMetadata' object like the good citizens we are.

Part of blueprint numa-aware-vswitches

Change-Id: Icb295bbd8c83e2e340a7ac3ecc1f159e0db7c7b1
This commit is contained in:
Stephen Finucane 2018-06-07 15:15:48 +01:00
parent d985d66261
commit 51248a4c01
3 changed files with 41 additions and 6 deletions

View File

@ -27,7 +27,8 @@ from nova.scheduler import utils as scheduler_utils
from nova.virt import hardware
REQUEST_SPEC_OPTIONAL_ATTRS = ['requested_destination',
'security_groups']
'security_groups',
'network_metadata']
@base.NovaObjectRegistry.register
@ -42,7 +43,8 @@ class RequestSpec(base.NovaObject):
# Version 1.7: Added destroy()
# Version 1.8: Added security_groups
# Version 1.9: Added user_id
VERSION = '1.9'
# Version 1.10: Added network_metadata
VERSION = '1.10'
fields = {
'id': fields.IntegerField(),
@ -79,11 +81,15 @@ class RequestSpec(base.NovaObject):
'scheduler_hints': fields.DictOfListOfStringsField(nullable=True),
'instance_uuid': fields.UUIDField(),
'security_groups': fields.ObjectField('SecurityGroupList'),
'network_metadata': fields.ObjectField('NetworkMetadata'),
}
def obj_make_compatible(self, primitive, target_version):
super(RequestSpec, self).obj_make_compatible(primitive, target_version)
target_version = versionutils.convert_version_to_tuple(target_version)
if target_version < (1, 10):
if 'network_metadata' in primitive:
del primitive['network_metadata']
if target_version < (1, 9):
if 'user_id' in primitive:
del primitive['user_id']
@ -104,6 +110,11 @@ class RequestSpec(base.NovaObject):
self.security_groups = objects.SecurityGroupList(objects=[])
return
if attrname == 'network_metadata':
self.network_metadata = objects.NetworkMetadata(
physnets=set(), tunneled=False)
return
# NOTE(sbauza): In case the primitive was not providing that field
# because of a previous RequestSpec version, we want to default
# that field in order to have the same behaviour.
@ -525,6 +536,10 @@ class RequestSpec(base.NovaObject):
# NOTE(mriedem): Don't persist retries since those are per-request
if 'retry' in spec and spec.retry:
spec.retry = None
# NOTE(stephenfin): Don't persist network metadata since we have
# no need for it after scheduling
if 'network_metadata' in spec and spec.network_metadata:
del spec.network_metadata
db_updates = {'spec': jsonutils.dumps(spec.obj_to_primitive())}
if 'instance_uuid' in updates:

View File

@ -1142,7 +1142,7 @@ object_data = {
'PowerVMLiveMigrateData': '1.3-79c635ecf61d1d70b5b9fa04bf778a91',
'Quotas': '1.3-40fcefe522111dddd3e5e6155702cf4e',
'QuotasNoOp': '1.3-347a039fc7cfee7b225b68b5181e0733',
'RequestSpec': '1.9-e506ccb22cd7807a1207c22a3f179387',
'RequestSpec': '1.10-afe714bc445ab7cb791150a775f3b779',
'S3ImageMapping': '1.0-7dd7366a890d82660ed121de9092276e',
'SchedulerLimits': '1.0-249c4bd8e62a9b327b7026b7f19cc641',
'SchedulerRetries': '1.1-3c9c8b16143ebbb6ad7030e999d14cc0',

View File

@ -299,7 +299,7 @@ class _TestRequestSpecObject(object):
spec = objects.RequestSpec.from_primitives(ctxt, spec_dict, filt_props)
mock_limits.assert_called_once_with({})
# Make sure that all fields are set using that helper method
skip = ['id', 'security_groups']
skip = ['id', 'security_groups', 'network_metadata']
for field in [f for f in spec.obj_fields if f not in skip]:
self.assertTrue(spec.obj_attr_is_set(field),
'Field: %s is not set' % field)
@ -329,7 +329,8 @@ class _TestRequestSpecObject(object):
filter_properties, instance_group, instance.availability_zone,
objects.SecurityGroupList())
# Make sure that all fields are set using that helper method
for field in [f for f in spec.obj_fields if f != 'id']:
skip = ['id', 'network_metadata']
for field in [f for f in spec.obj_fields if f not in skip]:
self.assertTrue(spec.obj_attr_is_set(field),
'Field: %s is not set' % field)
# just making sure that the context is set by the method
@ -542,7 +543,7 @@ class _TestRequestSpecObject(object):
# object fields
for field in ['image', 'numa_topology', 'pci_requests', 'flavor',
'limits']:
'limits', 'network_metadata']:
self.assertEqual(
getattr(req_obj, field).obj_to_primitive(),
getattr(serialized_obj, field).obj_to_primitive())
@ -641,6 +642,18 @@ class _TestRequestSpecObject(object):
self.assertNotIn('user_id', primitive)
self.assertIn('project_id', primitive)
def test_compat_network_metadata(self):
network_metadata = objects.NetworkMetadata(physnets=set(),
tunneled=False)
req_obj = objects.RequestSpec(network_metadata=network_metadata,
user_id=fakes.FAKE_USER_ID)
versions = ovo_base.obj_tree_get_versions('RequestSpec')
primitive = req_obj.obj_to_primitive(target_version='1.9',
version_manifest=versions)
primitive = primitive['nova_object.data']
self.assertNotIn('network_metadata', primitive)
self.assertIn('user_id', primitive)
def test_default_requested_destination(self):
req_obj = objects.RequestSpec()
self.assertIsNone(req_obj.requested_destination)
@ -652,6 +665,13 @@ class _TestRequestSpecObject(object):
objects.SecurityGroupList)
self.assertIn('security_groups', req_obj)
def test_network_requests_load(self):
req_obj = objects.RequestSpec()
self.assertNotIn('network_metadata', req_obj)
self.assertIsInstance(req_obj.network_metadata,
objects.NetworkMetadata)
self.assertIn('network_metadata', req_obj)
def test_destination_aggregates_default(self):
destination = objects.Destination()
self.assertIsNone(destination.aggregates)