From 6b989dba225997bfd5bc17d2a4175085ea810e4e Mon Sep 17 00:00:00 2001 From: Vladik Romanovsky Date: Wed, 27 Apr 2016 10:28:54 -0400 Subject: [PATCH] objects: adding an update method to virtual_interface Adding a save method to the virtual_interface object and an update method to its database model. Partially implements blueprint virt-device-role-tagging Co-authored-by: Artom Lifshitz Change-Id: I52673fc297cb578995be5c7a075c5693b0793bf5 --- nova/db/api.py | 5 +++++ nova/db/sqlalchemy/api.py | 9 ++++++++ nova/objects/virtual_interface.py | 21 ++++++++++++++++-- nova/tests/unit/db/test_db_api.py | 22 +++++++++++++++++++ nova/tests/unit/objects/test_objects.py | 2 +- .../unit/objects/test_virtual_interface.py | 16 ++++++++++++++ 6 files changed, 72 insertions(+), 3 deletions(-) diff --git a/nova/db/api.py b/nova/db/api.py index 805189cfee..a120b069d5 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -636,6 +636,11 @@ def virtual_interface_create(context, values): return IMPL.virtual_interface_create(context, values) +def virtual_interface_update(context, address, values): + """Create a virtual interface record in the database.""" + return IMPL.virtual_interface_update(context, address, values) + + def virtual_interface_get(context, vif_id): """Gets a virtual interface from the table.""" return IMPL.virtual_interface_get(context, vif_id) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 132847ae33..08ff0e1548 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1530,6 +1530,15 @@ def _virtual_interface_query(context): return model_query(context, models.VirtualInterface, read_deleted="no") +@require_context +@pick_context_manager_writer +def virtual_interface_update(context, address, values): + vif_ref = virtual_interface_get_by_address(context, address) + vif_ref.update(values) + vif_ref.save(context.session) + return vif_ref + + @require_context @pick_context_manager_reader def virtual_interface_get(context, vif_id): diff --git a/nova/objects/virtual_interface.py b/nova/objects/virtual_interface.py index 7772c94519..7a72b28dc0 100644 --- a/nova/objects/virtual_interface.py +++ b/nova/objects/virtual_interface.py @@ -21,11 +21,15 @@ from nova.objects import base from nova.objects import fields +VIF_OPTIONAL_FIELDS = ['network_id'] + + @base.NovaObjectRegistry.register class VirtualInterface(base.NovaPersistentObject, base.NovaObject): # Version 1.0: Initial version # Version 1.1: Add tag field - VERSION = '1.1' + # Version 1.2: Adding a save method + VERSION = '1.2' fields = { 'id': fields.IntegerField(), @@ -44,7 +48,10 @@ class VirtualInterface(base.NovaPersistentObject, base.NovaObject): @staticmethod def _from_db_object(context, vif, db_vif): for field in vif.fields: - setattr(vif, field, db_vif[field]) + if not db_vif[field] and field in VIF_OPTIONAL_FIELDS: + continue + else: + setattr(vif, field, db_vif[field]) vif._context = context vif.obj_reset_changes() return vif @@ -83,6 +90,16 @@ class VirtualInterface(base.NovaPersistentObject, base.NovaObject): db_vif = db.virtual_interface_create(self._context, updates) self._from_db_object(self._context, self, db_vif) + @base.remotable + def save(self): + updates = self.obj_get_changes() + if 'address' in updates: + raise exception.ObjectActionError(action='save', + reason='address is not mutable') + db_vif = db.virtual_interface_update(self._context, self.address, + updates) + return self._from_db_object(self._context, self, db_vif) + @base.remotable_classmethod def delete_by_instance_uuid(cls, context, instance_uuid): db.virtual_interface_delete_by_instance(context, instance_uuid) diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index bfe11a4f98..0c7c9d3f3f 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -6549,6 +6549,28 @@ class VirtualInterfaceTestCase(test.TestCase, ModelsObjectComparatorMixin): real_vifs = db.virtual_interface_get_all(self.ctxt) self._assertEqualListsOfObjects(vifs, real_vifs) + def test_virtual_interface_update(self): + instance_uuid = db.instance_create(self.ctxt, {})['uuid'] + network_id = db.network_create_safe(self.ctxt, {})['id'] + create = {'address': 'fake1', + 'network_id': network_id, + 'instance_uuid': instance_uuid, + 'uuid': uuidsentinel.vif_uuid, + 'tag': 'foo'} + update = {'tag': 'bar'} + updated = {'address': 'fake1', + 'network_id': network_id, + 'instance_uuid': instance_uuid, + 'uuid': uuidsentinel.vif_uuid, + 'tag': 'bar', + 'deleted': 0} + ignored_keys = ['created_at', 'id', 'deleted_at', 'updated_at'] + vif_addr = db.virtual_interface_create(self.ctxt, create)['address'] + db.virtual_interface_update(self.ctxt, vif_addr, update) + updated_vif = db.virtual_interface_get_by_address(self.ctxt, + updated['address']) + self._assertEqualObjects(updated, updated_vif, ignored_keys) + class NetworkTestCase(test.TestCase, ModelsObjectComparatorMixin): diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index 2ddf277b39..94640ffed5 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1195,7 +1195,7 @@ object_data = { 'VirtCPUFeature': '1.0-3310718d8c72309259a6e39bdefe83ee', 'VirtCPUModel': '1.0-6a5cc9f322729fc70ddc6733bacd57d3', 'VirtCPUTopology': '1.0-fc694de72e20298f7c6bab1083fd4563', - 'VirtualInterface': '1.1-422f46c1eaa24a1f63d3360c199cc7c0', + 'VirtualInterface': '1.2-25730967393678bd4da092b98694f971', 'VirtualInterfaceList': '1.0-9750e2074437b3077e46359102779fc6', 'VolumeUsage': '1.0-6c8190c46ce1469bb3286a1f21c2e475', 'XenapiLiveMigrateData': '1.0-5f982bec68f066e194cd9ce53a24ac4c', diff --git a/nova/tests/unit/objects/test_virtual_interface.py b/nova/tests/unit/objects/test_virtual_interface.py index d35d92faaf..3e03098bee 100644 --- a/nova/tests/unit/objects/test_virtual_interface.py +++ b/nova/tests/unit/objects/test_virtual_interface.py @@ -83,6 +83,22 @@ class _TestVirtualInterface(object): vif._context = None self._compare(self, fake_vif, vif) + def test_save(self): + vif = vif_obj.VirtualInterface(context=self.context) + vif.address = '00:00:00:00:00:00' + vif.network_id = 123 + vif.instance_uuid = uuids.instance_uuid + vif.uuid = uuids.vif_uuid + vif.tag = 'foo' + vif.create() + + with mock.patch.object(db, 'virtual_interface_update') as update: + update.return_value = fake_vif + vif.tag = 'bar' + vif.save() + update.assert_called_once_with(self.context, '00:00:00:00:00:00', + {'tag': 'bar'}) + def test_delete_by_instance_uuid(self): with mock.patch.object(db, 'virtual_interface_delete_by_instance') as delete: