Add requested_networks field to RequestSpec object

Since we want to support routed networks in Nova, we need to provide
the needed networks to the scheduler, hence the new field which
won't be persisted.

Change-Id: I03fcf9d64a750e3e8a71c1862d3e2ceb84aaffd2
Related-Implements: blueprint routed-networks-scheduling
This commit is contained in:
Sylvain Bauza 2020-09-01 17:59:30 +02:00
parent fefd984fd1
commit edaaac6aaf
3 changed files with 56 additions and 6 deletions

View File

@ -34,7 +34,8 @@ REQUEST_SPEC_OPTIONAL_ATTRS = ['requested_destination',
'security_groups',
'network_metadata',
'requested_resources',
'request_level_params']
'request_level_params',
'requested_networks']
@base.NovaObjectRegistry.register
@ -53,7 +54,8 @@ class RequestSpec(base.NovaObject):
# Version 1.11: Added is_bfv
# Version 1.12: Added requested_resources
# Version 1.13: Added request_level_params
VERSION = '1.13'
# Version 1.14: Added requested_networks
VERSION = '1.14'
fields = {
'id': fields.IntegerField(),
@ -108,11 +110,15 @@ class RequestSpec(base.NovaObject):
default=None),
# NOTE(efried): This field won't be persisted.
'request_level_params': fields.ObjectField('RequestLevelParams'),
# NOTE(sbauza); This field won't be persisted.
'requested_networks': fields.ObjectField('NetworkRequestList')
}
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, 14) and 'requested_networks' in primitive:
del primitive['requested_networks']
if target_version < (1, 13) and 'request_level_params' in primitive:
del primitive['request_level_params']
if target_version < (1, 12):
@ -152,6 +158,10 @@ class RequestSpec(base.NovaObject):
self.request_level_params = RequestLevelParams()
return
if attrname == 'requested_networks':
self.requested_networks = objects.NetworkRequestList(objects=[])
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.
@ -563,7 +573,8 @@ class RequestSpec(base.NovaObject):
if key in ['id', 'instance_uuid']:
setattr(spec, key, db_spec[key])
elif key in ('requested_destination', 'requested_resources',
'network_metadata', 'request_level_params'):
'network_metadata', 'request_level_params',
'requested_networks'):
# Do not override what we already have in the object as this
# field is not persisted. If save() is called after
# one of these fields is populated, it will reset the field to
@ -653,6 +664,10 @@ class RequestSpec(base.NovaObject):
# no need for it after scheduling
if 'network_metadata' in spec and spec.network_metadata:
del spec.network_metadata
# NOTE(sbauza): Don't persist requested_networks since we have
# no need for it after scheduling
if 'requested_networks' in spec and spec.requested_networks:
del spec.requested_networks
db_updates = {'spec': jsonutils.dumps(spec.obj_to_primitive())}
if 'instance_uuid' in updates:

View File

@ -1124,7 +1124,7 @@ object_data = {
'QuotasNoOp': '1.3-d1593cf969c81846bc8192255ea95cce',
'RequestGroup': '1.3-0458d350a8ec9d0673f9be5640a990ce',
'RequestLevelParams': '1.0-1e5c8c18bd44cd233c8b32509c99d06f',
'RequestSpec': '1.13-e1aa38b2bf3f8547474ee9e4c0aa2745',
'RequestSpec': '1.14-2cdbda368ca07e10905dc5fe96908a58',
'Resource': '1.0-d8a2abbb380da583b995fd118f6a8953',
'ResourceList': '1.0-4a53826625cc280e15fae64a575e0879',
'ResourceMetadata': '1.0-77509ea1ea0dd750d5864b9bd87d3f9d',

View File

@ -308,7 +308,7 @@ class _TestRequestSpecObject(object):
mock_limits.assert_called_once_with({})
# Make sure that all fields are set using that helper method
skip = ['id', 'security_groups', 'network_metadata', 'is_bfv',
'request_level_params']
'request_level_params', 'requested_networks']
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)
@ -339,7 +339,8 @@ class _TestRequestSpecObject(object):
filter_properties, instance_group, instance.availability_zone,
objects.SecurityGroupList())
# Make sure that all fields are set using that helper method
skip = ['id', 'network_metadata', 'is_bfv', 'request_level_params']
skip = ['id', 'network_metadata', 'is_bfv', 'request_level_params',
'requested_networks']
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)
@ -664,6 +665,8 @@ class _TestRequestSpecObject(object):
objects.ComputeNode(host='host2', hypervisor_hostname='node2'),
]))
req_obj.retry = expected_retry
nr = objects.NetworkRequest()
req_obj.requested_networks = objects.NetworkRequestList(objects=[nr])
orig_create_in_db = request_spec.RequestSpec._create_in_db
with mock.patch.object(request_spec.RequestSpec, '_create_in_db') \
@ -677,18 +680,21 @@ class _TestRequestSpecObject(object):
# 2. requested_destination
# 3. requested_resources
# 4. retry
# 5. requested_networks
data = jsonutils.loads(updates['spec'])['nova_object.data']
self.assertNotIn('network_metadata', data)
self.assertIsNone(data['requested_destination'])
self.assertIsNone(data['requested_resources'])
self.assertIsNone(data['retry'])
self.assertIsNotNone(data['instance_uuid'])
self.assertNotIn('requested_networks', data)
# also we expect that the following fields are not reset after create
# 1. network_metadata
# 2. requested_destination
# 3. requested_resources
# 4. retry
# 5. requested_networks
self.assertIsNotNone(req_obj.network_metadata)
self.assertJsonEqual(expected_network_metadata.obj_to_primitive(),
req_obj.network_metadata.obj_to_primitive())
@ -701,6 +707,9 @@ class _TestRequestSpecObject(object):
self.assertIsNotNone(req_obj.retry)
self.assertJsonEqual(expected_retry.obj_to_primitive(),
req_obj.retry.obj_to_primitive())
self.assertIsNotNone(req_obj.requested_networks)
self.assertJsonEqual(nr.obj_to_primitive(),
req_obj.requested_networks[0].obj_to_primitive())
def test_save_does_not_persist_requested_fields(self):
req_obj = fake_request_spec.fake_spec_obj(remove_id=True)
@ -722,6 +731,8 @@ class _TestRequestSpecObject(object):
req_obj.retry = expected_retry
req_obj.num_instances = 2
req_obj.ignore_hosts = [uuids.ignored_host]
nr = objects.NetworkRequest()
req_obj.requested_networks = objects.NetworkRequestList(objects=[nr])
orig_save_in_db = request_spec.RequestSpec._save_in_db
with mock.patch.object(request_spec.RequestSpec, '_save_in_db') \
@ -736,6 +747,7 @@ class _TestRequestSpecObject(object):
# 3. requested_resources
# 4. retry
# 5. ignore_hosts
# 6. requested_networks
data = jsonutils.loads(updates['spec'])['nova_object.data']
self.assertNotIn('network_metadata', data)
self.assertIsNone(data['requested_destination'])
@ -743,6 +755,7 @@ class _TestRequestSpecObject(object):
self.assertIsNone(data['retry'])
self.assertIsNone(data['ignore_hosts'])
self.assertIsNotNone(data['instance_uuid'])
self.assertNotIn('requested_networks', data)
# also we expect that the following fields are not reset after save
# 1. network_metadata
@ -750,6 +763,7 @@ class _TestRequestSpecObject(object):
# 3. requested_resources
# 4. retry
# 5. ignore_hosts
# 6. requested_networks
self.assertIsNotNone(req_obj.network_metadata)
self.assertJsonEqual(expected_network_metadata.obj_to_primitive(),
req_obj.network_metadata.obj_to_primitive())
@ -764,6 +778,9 @@ class _TestRequestSpecObject(object):
req_obj.retry.obj_to_primitive())
self.assertIsNotNone(req_obj.ignore_hosts)
self.assertEqual([uuids.ignored_host], req_obj.ignore_hosts)
self.assertIsNotNone(req_obj.requested_networks)
self.assertJsonEqual(nr.obj_to_primitive(),
req_obj.requested_networks[0].obj_to_primitive())
def test_save(self):
req_obj = fake_request_spec.fake_spec_obj()
@ -871,6 +888,17 @@ class _TestRequestSpecObject(object):
self.assertNotIn('requested_resources', primitive)
self.assertIn('instance_uuid', primitive)
def test_compat_requested_networks(self):
req_obj = objects.RequestSpec(
requested_networks=objects.NetworkRequestList(objects=[]),
instance_uuid=uuids.instance)
versions = ovo_base.obj_tree_get_versions('RequestSpec')
primitive = req_obj.obj_to_primitive(target_version='1.13',
version_manifest=versions)
primitive = primitive['nova_object.data']
self.assertNotIn('requested_networks', primitive)
self.assertIn('instance_uuid', primitive)
def test_default_requested_destination(self):
req_obj = objects.RequestSpec()
self.assertIsNone(req_obj.requested_destination)
@ -889,6 +917,13 @@ class _TestRequestSpecObject(object):
objects.NetworkMetadata)
self.assertIn('network_metadata', req_obj)
def test_requested_networks_load(self):
req_obj = objects.RequestSpec()
self.assertNotIn('requested_networks', req_obj)
self.assertIsInstance(req_obj.requested_networks,
objects.NetworkRequestList)
self.assertIn('requested_networks', req_obj)
def test_create_raises_on_unchanged_object(self):
ctxt = context.RequestContext(uuids.user_id, uuids.project_id)
req_obj = request_spec.RequestSpec(context=ctxt)