diff --git a/nova/objects/request_spec.py b/nova/objects/request_spec.py index 302ce9643660..a211edfd41d6 100644 --- a/nova/objects/request_spec.py +++ b/nova/objects/request_spec.py @@ -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. @@ -526,6 +537,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: diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index 0269e92c260f..433cfa8b2612 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -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', diff --git a/nova/tests/unit/objects/test_request_spec.py b/nova/tests/unit/objects/test_request_spec.py index 9852232f55b0..770f6b9d86a7 100644 --- a/nova/tests/unit/objects/test_request_spec.py +++ b/nova/tests/unit/objects/test_request_spec.py @@ -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)